new version
This commit is contained in:
parent
53a1aa2cc5
commit
b33bed8745
@ -1 +1,2 @@
|
|||||||
.env
|
.env
|
||||||
|
certs
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -1 +1,2 @@
|
|||||||
.env
|
.env
|
||||||
|
certs
|
14
Dockerfile
14
Dockerfile
@ -1,16 +1,16 @@
|
|||||||
FROM golang:1.22-alpine as build
|
FROM docker.io/golang:1.22-alpine as build
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
ENV GOCACHE=/root/.cache/go-build
|
ENV GOCACHE=/root/.cache/go-build
|
||||||
RUN --mount=type=cache,target="/root/.cache/go-build" go build .
|
RUN --mount=type=cache,target="/root/.cache/go-build" go build -ldflags="-w -s" -gcflags=all=-l .
|
||||||
RUN --mount=type=cache,target="/root/.cache/go-build" go build -C cert .
|
|
||||||
|
|
||||||
FROM nginx:alpine-slim
|
FROM scratch
|
||||||
|
|
||||||
COPY --from=build app app
|
COPY --from=build app app
|
||||||
|
# copy ssl for work HTTPS requests to gitea instance
|
||||||
|
COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY nginx.conf /etc/nginx/nginx.conf
|
ENV GIN_MODE=release
|
||||||
|
ENTRYPOINT [ "./giteapages" ]
|
||||||
ENTRYPOINT [ "sh", "entrypoint.sh" ]
|
|
41
README.md
41
README.md
@ -1,5 +1,38 @@
|
|||||||
|
## currently hosted by me on
|
||||||
|
https://pages.mi6e4ka.dev
|
||||||
|
|
||||||
# how to run
|
# how to run
|
||||||
`docker run -p 443:443 -p 80:80 --name gitea-pages -v gitea-pages-ssl:/etc/ssl -d gitea-pages`
|
|
||||||
## gen ssl (first run)
|
`docker run -p 8080:8080 --name gitea-pages -d git.mi6e4ka.dev/mi6e4ka/gitea-pages`
|
||||||
`docker exec -it gp /app/cert/cert root.domain`
|
```
|
||||||
and restart docker container!
|
issue wildcard ssl for domains *.rootdomain and rootdomain should be your reverse proxy
|
||||||
|
```
|
||||||
|
or by docker-compose
|
||||||
|
```
|
||||||
|
services:
|
||||||
|
gitea-pages:
|
||||||
|
env_file: ".env"
|
||||||
|
image: git.mi6e4ka.dev/mi6e4ka/gitea-pages
|
||||||
|
ports:
|
||||||
|
- 8080:8080
|
||||||
|
```
|
||||||
|
|
||||||
|
## ENV SETTINGS
|
||||||
|
|
||||||
|
also by create .env file
|
||||||
|
|
||||||
|
<!--
|
||||||
|
PDNS_KEY | | RvvA8qH8kkH3 | yes | PowerDNS api key
|
||||||
|
PDNS_HOST | | http://10.0.0.4:8081 | yes | PowerDNS api host
|
||||||
|
ACME_EMAIL | | me@example.com | yes | ACME email
|
||||||
|
TEST_MODE | false | true | Issue stagins le certs
|
||||||
|
-->
|
||||||
|
param | default | eg | description
|
||||||
|
--- | --- | ---| ---
|
||||||
|
ROOT_DOMAIN | localhost | my.pages | root domain to serve sites
|
||||||
|
DEFAULT_USER | | mi6e4ka | Gitea user if not specified user subdomain
|
||||||
|
GITEA_URL | https://codeberg.org | | Gitea instance with api
|
||||||
|
INDEX_FILE | index.html | | File serving by default
|
||||||
|
DIRECTORY_INDEX | false | true | Show list files if not index.html in directory
|
||||||
|
SERVE_PORT | 8080 | | Port to listen
|
||||||
|
GITEA_TOKEN | | 5yE5j5r1qHZI | For access to private repos
|
@ -7,12 +7,14 @@ import (
|
|||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/go-acme/lego/v4/certcrypto"
|
"github.com/go-acme/lego/v4/certcrypto"
|
||||||
"github.com/go-acme/lego/v4/certificate"
|
"github.com/go-acme/lego/v4/certificate"
|
||||||
"github.com/go-acme/lego/v4/challenge/dns01"
|
|
||||||
"github.com/go-acme/lego/v4/lego"
|
"github.com/go-acme/lego/v4/lego"
|
||||||
|
"github.com/go-acme/lego/v4/providers/dns/pdns"
|
||||||
"github.com/go-acme/lego/v4/registration"
|
"github.com/go-acme/lego/v4/registration"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -33,60 +35,62 @@ func (u *MyUser) GetPrivateKey() crypto.PrivateKey {
|
|||||||
return u.key
|
return u.key
|
||||||
}
|
}
|
||||||
|
|
||||||
type DNSProviderBestDNS struct {
|
func GenCerts() {
|
||||||
apiAuthToken string
|
testMode := false
|
||||||
}
|
testModeStr, exists := os.LookupEnv("TEST_MODE")
|
||||||
|
if !exists {
|
||||||
func NewDNSProviderBestDNS(apiAuthToken string) (*DNSProviderBestDNS, error) {
|
if testModeStr == "true" {
|
||||||
return &DNSProviderBestDNS{apiAuthToken: apiAuthToken}, nil
|
testMode = true
|
||||||
}
|
}
|
||||||
func (d *DNSProviderBestDNS) Present(domain, token, keyAuth string) error {
|
}
|
||||||
info := dns01.GetChallengeInfo(domain, keyAuth)
|
rootDomain, exists := os.LookupEnv("ROOT_DOMAIN")
|
||||||
fmt.Println()
|
if !exists {
|
||||||
fmt.Println("------")
|
rootDomain = "localhost"
|
||||||
fmt.Println()
|
}
|
||||||
fmt.Println("Please create DNS TXT record, for domain", info.FQDN, "with these content:")
|
pdnsKey, has := os.LookupEnv("PDNS_KEY")
|
||||||
fmt.Println()
|
if !has {
|
||||||
fmt.Println(info.Value)
|
fmt.Println("must have PDNS_KEY")
|
||||||
fmt.Println()
|
|
||||||
fmt.Println("------")
|
|
||||||
fmt.Scanln()
|
|
||||||
// make API request to set a TXT record on fqdn with value and TTL
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
func (d *DNSProviderBestDNS) CleanUp(domain, token, keyAuth string) error {
|
|
||||||
// clean up any state you created in Present, like removing the TXT record
|
|
||||||
fmt.Println("------")
|
|
||||||
fmt.Println()
|
|
||||||
fmt.Println("you can delete the TXT record, and press enter to continue")
|
|
||||||
fmt.Println()
|
|
||||||
fmt.Println("------")
|
|
||||||
fmt.Scanln()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
if len(os.Args) != 2 {
|
|
||||||
fmt.Println("usage: ./cert root.domain")
|
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
fmt.Println("root domain is", os.Args[1])
|
pdnsHost, has := os.LookupEnv("PDNS_HOST")
|
||||||
|
if !has {
|
||||||
|
fmt.Println("must have PDNS_HOST ENV")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
acmeEmail, has := os.LookupEnv("ACME_EMAIL")
|
||||||
|
if !has {
|
||||||
|
fmt.Println("must have ACME_EMAIL ENV")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
fmt.Println("root domain is", rootDomain)
|
||||||
// Create a user. New accounts need an email and private key to start.
|
// Create a user. New accounts need an email and private key to start.
|
||||||
privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
var email string
|
|
||||||
fmt.Print("enter you email > ")
|
|
||||||
fmt.Scanln(&email)
|
|
||||||
myUser := MyUser{
|
myUser := MyUser{
|
||||||
Email: email,
|
Email: acmeEmail,
|
||||||
key: privateKey,
|
key: privateKey,
|
||||||
}
|
}
|
||||||
|
pdnsUrl, _ := url.Parse(pdnsHost)
|
||||||
|
provider, err := pdns.NewDNSProviderConfig(&pdns.Config{
|
||||||
|
Host: pdnsUrl,
|
||||||
|
APIKey: pdnsKey,
|
||||||
|
ServerName: "localhost",
|
||||||
|
TTL: 5,
|
||||||
|
PropagationTimeout: time.Duration(time.Second * 30),
|
||||||
|
PollingInterval: time.Duration(time.Millisecond * 500),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
config := lego.NewConfig(&myUser)
|
config := lego.NewConfig(&myUser)
|
||||||
|
// uncoment for tesing ->>
|
||||||
|
if testMode {
|
||||||
|
config.CADirURL = lego.LEDirectoryStaging
|
||||||
|
}
|
||||||
|
|
||||||
//config.CADirURL = lego.LEDirectoryStaging
|
|
||||||
config.Certificate.KeyType = certcrypto.RSA2048
|
config.Certificate.KeyType = certcrypto.RSA2048
|
||||||
|
|
||||||
// A client facilitates communication with the CA server.
|
// A client facilitates communication with the CA server.
|
||||||
@ -94,15 +98,7 @@ func main() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
client.Challenge.SetDNS01Provider(provider)
|
||||||
bestDNS, err := NewDNSProviderBestDNS("my-auth-token")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
err = client.Challenge.SetDNS01Provider(bestDNS)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// New users will need to register
|
// New users will need to register
|
||||||
reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
|
reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
|
||||||
@ -112,7 +108,7 @@ func main() {
|
|||||||
myUser.Registration = reg
|
myUser.Registration = reg
|
||||||
|
|
||||||
request := certificate.ObtainRequest{
|
request := certificate.ObtainRequest{
|
||||||
Domains: []string{os.Args[1], "*." + os.Args[1]},
|
Domains: []string{rootDomain, "*." + rootDomain},
|
||||||
Bundle: true,
|
Bundle: true,
|
||||||
}
|
}
|
||||||
certificates, err := client.Certificate.Obtain(request)
|
certificates, err := client.Certificate.Obtain(request)
|
||||||
@ -122,9 +118,9 @@ func main() {
|
|||||||
|
|
||||||
// Each certificate comes back with the cert bytes, the bytes of the client's
|
// Each certificate comes back with the cert bytes, the bytes of the client's
|
||||||
// private key, and a certificate URL. SAVE THESE TO DISK.
|
// private key, and a certificate URL. SAVE THESE TO DISK.
|
||||||
os.Mkdir("/etc/ssl", 0777)
|
os.Mkdir("./certs", 0777)
|
||||||
os.WriteFile("/etc/ssl/cert.crt", certificates.Certificate, 0777)
|
os.WriteFile("./certs/cert.crt", certificates.Certificate, 0777)
|
||||||
os.WriteFile("/etc/ssl/priv.key", certificates.PrivateKey, 0777)
|
os.WriteFile("./certs/priv.key", certificates.PrivateKey, 0777)
|
||||||
|
|
||||||
// ... all done.
|
// ... all done.
|
||||||
}
|
}
|
@ -1,8 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
if [ -e /etc/ssl/cert.crt ] && [ -e /etc/ssl/priv.key ]
|
|
||||||
then
|
|
||||||
nginx & GIN_MODE=release ./giteapages
|
|
||||||
else
|
|
||||||
echo "create certs first"
|
|
||||||
tail -f /dev/null
|
|
||||||
fi
|
|
31
main.go
31
main.go
@ -3,6 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"embed"
|
"embed"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
"io"
|
"io"
|
||||||
"mime"
|
"mime"
|
||||||
@ -32,6 +33,29 @@ func (t *transport) RoundTrip(req *http.Request) (*http.Response, error) {
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
godotenv.Load()
|
godotenv.Load()
|
||||||
|
// if os.Args[len(os.Args)-1] == "gencrt" {
|
||||||
|
// GenCerts()
|
||||||
|
// os.Exit(0)
|
||||||
|
// }
|
||||||
|
// if _, err := os.Stat("./certs/cert.crt"); err != nil {
|
||||||
|
// fmt.Println("Not found cert file")
|
||||||
|
// GenCerts()
|
||||||
|
// }
|
||||||
|
// if _, err := os.Stat("./certs/priv.key"); err != nil {
|
||||||
|
// fmt.Println("Not fount cert key file")
|
||||||
|
// GenCerts()
|
||||||
|
// }
|
||||||
|
//certFile, _ := os.ReadFile("./certs/cert.crt")
|
||||||
|
//block, _ := pem.Decode(certFile)
|
||||||
|
//if block == nil {
|
||||||
|
// fmt.Println("invalid certificate")
|
||||||
|
// GenCerts()
|
||||||
|
// }
|
||||||
|
// cert, _ := x509.ParseCertificate(block.Bytes)
|
||||||
|
// certExpired := time.Now().After(cert.NotAfter)
|
||||||
|
// if certExpired {
|
||||||
|
// GenCerts()
|
||||||
|
// }
|
||||||
rootDomain, exists := os.LookupEnv("ROOT_DOMAIN")
|
rootDomain, exists := os.LookupEnv("ROOT_DOMAIN")
|
||||||
if !exists {
|
if !exists {
|
||||||
rootDomain = "localhost"
|
rootDomain = "localhost"
|
||||||
@ -49,9 +73,10 @@ func main() {
|
|||||||
indexFile = "index.html"
|
indexFile = "index.html"
|
||||||
}
|
}
|
||||||
directoryIndexStr := os.Getenv("DIRECTORY_INDEX")
|
directoryIndexStr := os.Getenv("DIRECTORY_INDEX")
|
||||||
directoryIndex := true
|
fmt.Println(rootDomain, giteaUrl)
|
||||||
if directoryIndexStr == "false" {
|
directoryIndex := false
|
||||||
directoryIndex = false
|
if directoryIndexStr == "true" {
|
||||||
|
directoryIndex = true
|
||||||
}
|
}
|
||||||
defaultUser := os.Getenv("DEFAULT_USER")
|
defaultUser := os.Getenv("DEFAULT_USER")
|
||||||
servePort, exists := os.LookupEnv("SERVE_PORT")
|
servePort, exists := os.LookupEnv("SERVE_PORT")
|
||||||
|
47
nginx.conf
47
nginx.conf
@ -1,47 +0,0 @@
|
|||||||
worker_processes 1;
|
|
||||||
|
|
||||||
events { worker_connections 1024; }
|
|
||||||
|
|
||||||
http {
|
|
||||||
|
|
||||||
sendfile on;
|
|
||||||
large_client_header_buffers 4 32k;
|
|
||||||
|
|
||||||
upstream web-api {
|
|
||||||
server localhost:8080;
|
|
||||||
}
|
|
||||||
|
|
||||||
server {
|
|
||||||
listen 80 default_server;
|
|
||||||
server_name _;
|
|
||||||
|
|
||||||
location / {
|
|
||||||
return 301 https://$host$request_uri;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
server {
|
|
||||||
listen 443 ssl;
|
|
||||||
server_name _;
|
|
||||||
|
|
||||||
ssl_certificate /etc/ssl/cert.crt;
|
|
||||||
ssl_certificate_key /etc/ssl/priv.key;
|
|
||||||
|
|
||||||
location / {
|
|
||||||
proxy_pass http://web-api;
|
|
||||||
proxy_redirect off;
|
|
||||||
proxy_http_version 1.1;
|
|
||||||
proxy_cache_bypass $http_upgrade;
|
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
|
||||||
proxy_set_header Connection keep-alive;
|
|
||||||
proxy_set_header Host $host;
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
|
||||||
proxy_set_header X-Forwarded-Host $server_name;
|
|
||||||
proxy_buffer_size 128k;
|
|
||||||
proxy_buffers 4 256k;
|
|
||||||
proxy_busy_buffers_size 256k;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user