move certs to ./.lego directory

This commit is contained in:
m5r 2024-07-20 02:43:52 +02:00
parent 43788570ee
commit b97b2f2131
Signed by: mokhtar
GPG Key ID: 1509B54946D08A95
5 changed files with 34 additions and 32 deletions

View File

@ -8,15 +8,20 @@ RUN CGO_ENABLED=0 go build -o /app/local-ip
FROM gcr.io/distroless/base-debian12:latest FROM gcr.io/distroless/base-debian12:latest
ENV PORT 53 WORKDIR /local-ip
WORKDIR /app COPY --from=build /app/local-ip /local-ip/local-ip
COPY --from=build /app/http/static /local-ip/http/static
COPY --from=build /app/local-ip /app/local-ip VOLUME /local-ip/.lego
COPY --from=build /app/http/static /app/http/static
COPY ./.lego /app/.lego # DNS
EXPOSE 53/udp
# HTTP
EXPOSE 80/tcp
# HTTPS
EXPOSE 443/tcp
EXPOSE $PORT
USER root USER root
CMD ["/app/local-ip"] CMD ["/local-ip/local-ip"]

View File

@ -22,16 +22,13 @@ dig @localhost 127.0.0.1.my.local-ip.sh +short
local-ip.sh packs up: local-ip.sh packs up:
- an authoritative DNS server that answers queries for the zone `local-ip.sh` - an authoritative DNS server that answers queries for the zone `local-ip.sh`
- a Let's Encrypt client that takes care of obtaining and renewing the wildcard certificate for `*.local-ip.sh` using the DNS-01 challenge - a Let's Encrypt client that takes care of obtaining and renewing the wildcard certificate for `*.local-ip.sh` and the root certificate for `local-ip.sh` using the [DNS-01 challenge](https://letsencrypt.org/docs/challenge-types/#dns-01-challenge)
- an HTTP server that serves the certificate files - an HTTP server that serves static files, including the certificate files
It answers queries with the IPv4 address it may find in the subdomain by pattern matching the FQDN. It answers queries with the IPv4 address it may find in the subdomain by pattern matching the FQDN.
It registers an account to Let's Encrypt's ACME server to obtain the wildcard certificate on the first run and then renew It registers an account to Let's Encrypt's ACME server to obtain the wildcard certificate on the first run and then renew
it about a month before it expires. The account file and the associated key used to request a certificate under the `.lego` it about a month before it expires. The account file and the associated key used to request a certificate under the `./.lego/accounts`
directory but the certificate's files are stored in `/certs` at the root of the filesystem. I've done it this way to mount directory and the certificate's files are stored in `./.lego/certs`.
a persistent storage volume there and keep the files between deployments without tracking them in git but feel free to
change this behavior in [`certs/certs.go`](./certs/certs.go) and in [`http/server.go`](./http/server.go)
if you're planning to self-host it.
The certificate files are served by an HTTP server on the arbitrary port `:9229` that is intentionally not exposed to The certificate files are served by an HTTP server on the arbitrary port `:9229` that is intentionally not exposed to
the internet. [The website](https://local-ip.sh) is connected to the same private network as the service and serves the internet. [The website](https://local-ip.sh) is connected to the same private network as the service and serves

View File

@ -92,19 +92,19 @@ func (c *certsClient) renewCertificates() {
} }
func persistFiles(certificates *certificate.Resource, certType string) { func persistFiles(certificates *certificate.Resource, certType string) {
err := os.MkdirAll(fmt.Sprintf("/certs/%s", certType), 0o755) err := os.MkdirAll(fmt.Sprintf("./.lego/certs/%s", certType), 0o755)
if err != nil { if err != nil {
utils.Logger.Fatal().Err(err).Msgf("Failed to mkdir /certs/%s", certType) utils.Logger.Fatal().Err(err).Msgf("Failed to mkdir ./.lego/certs/%s", certType)
} }
err = os.WriteFile(fmt.Sprintf("/certs/%s/server.pem", certType), certificates.Certificate, 0o644) err = os.WriteFile(fmt.Sprintf("./.lego/certs/%s/server.pem", certType), certificates.Certificate, 0o644)
if err != nil { if err != nil {
utils.Logger.Fatal().Err(err).Msgf("Failed to save /certs/%s/server.pem", certType) utils.Logger.Fatal().Err(err).Msgf("Failed to save ./.lego/certs/%s/server.pem", certType)
} }
os.WriteFile(fmt.Sprintf("/certs/%s/server.key", certType), certificates.PrivateKey, 0o644) os.WriteFile(fmt.Sprintf("./.lego/certs/%s/server.key", certType), certificates.PrivateKey, 0o644)
if err != nil { if err != nil {
utils.Logger.Fatal().Err(err).Msgf("Failed to save /certs/%s/server.key", certType) utils.Logger.Fatal().Err(err).Msgf("Failed to save ./.lego/certs/%s/server.key", certType)
} }
jsonBytes, err := json.MarshalIndent(certificates, "", "\t") jsonBytes, err := json.MarshalIndent(certificates, "", "\t")
@ -112,9 +112,9 @@ func persistFiles(certificates *certificate.Resource, certType string) {
utils.Logger.Fatal().Err(err).Msg("Failed to marshal certificates to JSON") utils.Logger.Fatal().Err(err).Msg("Failed to marshal certificates to JSON")
} }
err = os.WriteFile(fmt.Sprintf("/certs/%s/output.json", certType), jsonBytes, 0o644) err = os.WriteFile(fmt.Sprintf("./.lego/certs/%s/output.json", certType), jsonBytes, 0o644)
if err != nil { if err != nil {
utils.Logger.Fatal().Err(err).Msgf("Failed to save /certs/%s/output.json", certType) utils.Logger.Fatal().Err(err).Msgf("Failed to save ./.lego/certs/%s/output.json", certType)
} }
} }
@ -140,7 +140,7 @@ func NewCertsClient(xip *xip.Xip, user *Account) *certsClient {
} }
func getLastCertificate(legoClient *lego.Client, certType string) *certificate.Resource { func getLastCertificate(legoClient *lego.Client, certType string) *certificate.Resource {
jsonBytes, err := os.ReadFile(fmt.Sprintf("/certs/%s/output.json", certType)) jsonBytes, err := os.ReadFile(fmt.Sprintf("./.lego/certs/%s/output.json", certType))
if err != nil { if err != nil {
if strings.Contains(err.Error(), "no such file or directory") { if strings.Contains(err.Error(), "no such file or directory") {
return nil return nil

View File

@ -17,8 +17,8 @@ auto_rollback = true
PORT = "53" PORT = "53"
[mounts] [mounts]
source = "certs" source = "lego"
destination = "/certs" destination = "/local-ip/.lego"
[[services]] [[services]]
protocol = "udp" protocol = "udp"

View File

@ -13,11 +13,11 @@ import (
func registerHandlers() { func registerHandlers() {
http.HandleFunc("GET /server.key", func(w http.ResponseWriter, r *http.Request) { http.HandleFunc("GET /server.key", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/octet-stream") w.Header().Set("Content-Type", "application/octet-stream")
http.ServeFile(w, r, "/certs/wildcard/server.key") http.ServeFile(w, r, "./.lego/certs/wildcard/server.key")
}) })
http.HandleFunc("GET /server.pem", func(w http.ResponseWriter, r *http.Request) { http.HandleFunc("GET /server.pem", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/x-x509-ca-cert") w.Header().Set("Content-Type", "application/x-x509-ca-cert")
http.ServeFile(w, r, "/certs/wildcard/server.pem") http.ServeFile(w, r, "./.lego/certs/wildcard/server.pem")
}) })
http.HandleFunc("GET /og.png", func(w http.ResponseWriter, r *http.Request) { http.HandleFunc("GET /og.png", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "image/png; charset=utf-8") w.Header().Set("Content-Type", "image/png; charset=utf-8")
@ -58,13 +58,13 @@ func serveHttp() *http.Server {
func waitForCertificate(ready chan bool) { func waitForCertificate(ready chan bool) {
for { for {
_, err := os.Stat("/certs/root/output.json") _, err := os.Stat("./.lego/certs/root/output.json")
if err != nil { if err != nil {
if strings.Contains(err.Error(), "no such file or directory") { if strings.Contains(err.Error(), "no such file or directory") {
time.Sleep(1 * time.Second) time.Sleep(1 * time.Second)
continue continue
} }
utils.Logger.Fatal().Err(err).Msg("Unexpected error while looking for /certs/root/output.json") utils.Logger.Fatal().Err(err).Msg("Unexpected error while looking for ./.lego/certs/root/output.json")
} }
break break
} }
@ -100,7 +100,7 @@ func redirectHttpToHttps() {
func serveHttps() { func serveHttps() {
utils.Logger.Info().Msg("Starting up HTTPS server on :443") utils.Logger.Info().Msg("Starting up HTTPS server on :443")
httpsServer := &http.Server{Addr: ":https"} httpsServer := &http.Server{Addr: ":https"}
go httpsServer.ListenAndServeTLS("/certs/root/server.pem", "/certs/root/server.key") go httpsServer.ListenAndServeTLS("./.lego/certs/root/server.pem", "./.lego/certs/root/server.key")
} }
func ServeHttp() { func ServeHttp() {