about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAlan Pearce2024-07-09 20:32:15 +0200
committerAlan Pearce2024-07-10 20:04:21 +0200
commitde704a079eb09b0b9126cb44839d1c0a34014173 (patch)
tree35d63d7df9d0f7872885d56be3a57a904bef7f4d
parentbfc935f6ea7b00c539192e486936b8ffbb5a403e (diff)
downloadwebsite-de704a079eb09b0b9126cb44839d1c0a34014173.tar.lz
website-de704a079eb09b0b9126cb44839d1c0a34014173.tar.zst
website-de704a079eb09b0b9126cb44839d1c0a34014173.zip
add wildcard domain redirect support
-rw-r--r--config.toml4
-rw-r--r--fly.toml1
-rw-r--r--go.mod1
-rw-r--r--go.sum2
-rw-r--r--internal/config/config.go1
-rw-r--r--internal/server/server.go22
-rw-r--r--internal/server/tls.go23
7 files changed, 50 insertions, 4 deletions
diff --git a/config.toml b/config.toml
index 979669f..3ea8fa4 100644
--- a/config.toml
+++ b/config.toml
@@ -13,7 +13,7 @@ domains = [
   "alanpearce.uk",
   "www.alanpearce.uk",
   "aln.pe",
-  "www.aln.pe",
+  "*.aln.pe",
   "alanpearce-eu.fly.dev",
 ]
 
@@ -21,6 +21,8 @@ oidc_host = "https://id.alanpearce.eu/"
 
 goatcounter = "https://stats.alanpearce.eu/count"
 
+wildcard_domain = "aln.pe"
+
 [[taxonomies]]
   name = "tags"
   feed = true
diff --git a/fly.toml b/fly.toml
index 7508dd6..54936a3 100644
--- a/fly.toml
+++ b/fly.toml
@@ -18,6 +18,7 @@ primary_region = "ams"
   PRODUCTION = "true"
   VCS_LOCAL_PATH = "/data/website"
   VCS_REMOTE_URL = "https://git.alanpearce.eu/website.git"
+  ACME_SERVER_URL = "https://acme.alanpearce.eu"
 
 [[services]]
   internal_port = 8080
diff --git a/go.mod b/go.mod
index 1c07814..b472a9e 100644
--- a/go.mod
+++ b/go.mod
@@ -20,6 +20,7 @@ require (
 	github.com/fsnotify/fsnotify v1.7.0
 	github.com/go-git/go-git/v5 v5.12.0
 	github.com/kevinpollet/nego v0.0.0-20211010160919-a65cd48cee43
+	github.com/libdns/acmedns v0.2.0
 	github.com/osdevisnot/sorvor v0.4.4
 	github.com/pberkel/caddy-storage-redis v1.2.0
 	github.com/snabb/sitemap v1.0.4
diff --git a/go.sum b/go.sum
index c11d666..7838b77 100644
--- a/go.sum
+++ b/go.sum
@@ -137,6 +137,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/libdns/acmedns v0.2.0 h1:zTXdHZwe3r2issdVRyqt5/4X2yHpiBVmFnTrwBA29ik=
+github.com/libdns/acmedns v0.2.0/go.mod h1:XlKHilQQK/IGHYY//vCb903PdG4Wc/XnDQzcMp2hV3g=
 github.com/libdns/libdns v0.2.2 h1:O6ws7bAfRPaBsgAYt8MDe2HcNBGC29hkZ9MX2eUSX3s=
 github.com/libdns/libdns v0.2.2/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ=
 github.com/mholt/acmez/v2 v2.0.1 h1:3/3N0u1pLjMK4sNEAFSI+bcvzbPhRpY383sy1kLHJ6k=
diff --git a/internal/config/config.go b/internal/config/config.go
index 47d5de8..24a2fed 100644
--- a/internal/config/config.go
+++ b/internal/config/config.go
@@ -42,6 +42,7 @@ type Config struct {
 	OriginalDomain   string `toml:"original_domain"`
 	GoatCounter      URL    `toml:"goatcounter"`
 	Domains          []string
+	WildcardDomain   string
 	OIDCHost         URL `toml:"oidc_host"`
 	Taxonomies       []Taxonomy
 	CSP              *CSP `toml:"content-security-policy"`
diff --git a/internal/server/server.go b/internal/server/server.go
index b174c0c..6ef715b 100644
--- a/internal/server/server.go
+++ b/internal/server/server.go
@@ -8,6 +8,7 @@ import (
 	"net/url"
 	"os"
 	"path/filepath"
+	"regexp"
 	"slices"
 	"strconv"
 	"strings"
@@ -184,11 +185,26 @@ func New(runtimeConfig *Config, log *log.Logger) (*Server, error) {
 	}
 
 	if runtimeConfig.Redirect {
+		re := regexp.MustCompile(
+			"^(.*)\\." + strings.ReplaceAll(config.WildcardDomain, ".", `\.`) + "$",
+		)
+		replace := "${0}." + config.Domains[0]
 		loggingMux.Handle(config.BaseURL.Hostname()+"/", mux)
 		loggingMux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
-			path, _ := website.CanonicalisePath(r.URL.Path)
-			newURL := config.BaseURL.JoinPath(path)
-			http.Redirect(w, r, newURL.String(), http.StatusMovedPermanently)
+			if slices.Contains(config.Domains, r.Host) {
+				path, _ := website.CanonicalisePath(r.URL.Path)
+				newURL := config.BaseURL.JoinPath(path)
+				http.Redirect(w, r, newURL.String(), http.StatusMovedPermanently)
+			} else {
+				matches := re.FindSubmatchIndex([]byte(r.Host))
+				if matches == nil {
+					http.Redirect(w, r, config.BaseURL.String(), http.StatusTemporaryRedirect)
+
+					return
+				}
+				newHost := re.ExpandString([]byte{}, replace, r.Host, matches)
+				http.Redirect(w, r, string(newHost), http.StatusTemporaryRedirect)
+			}
 		})
 	} else {
 		loggingMux.Handle("/", mux)
diff --git a/internal/server/tls.go b/internal/server/tls.go
index 9481b6a..556013d 100644
--- a/internal/server/tls.go
+++ b/internal/server/tls.go
@@ -12,6 +12,7 @@ import (
 	"github.com/ardanlabs/conf/v3"
 	"github.com/caddyserver/caddy/v2"
 	"github.com/caddyserver/certmagic"
+	"github.com/libdns/acmedns"
 	certmagic_redis "github.com/pberkel/caddy-storage-redis"
 	"gitlab.com/tozd/go/errors"
 )
@@ -24,6 +25,13 @@ type redisConfig struct {
 	KeyPrefix     string `conf:"default:certmagic"`
 }
 
+type acmeConfig struct {
+	Username  string `conf:"required"`
+	Password  string `conf:"required"`
+	Subdomain string `conf:"required"`
+	ServerURL string `conf:"env:SERVER_URL,default:https://acme.alanpearce.eu"`
+}
+
 func (s *Server) serveTLS() (err error) {
 	log := s.log.Named("tls")
 
@@ -72,6 +80,21 @@ func (s *Server) serveTLS() (err error) {
 			return errors.Wrap(err, "could not parse redis config")
 		}
 
+		acme := &acmedns.Provider{}
+		_, err = conf.Parse("ACME", acme)
+		if err != nil {
+			return errors.Wrap(err, "could not parse ACME config")
+		}
+
+		issuer.DNS01Solver = &certmagic.DNS01Solver{
+			DNSManager: certmagic.DNSManager{
+				DNSProvider: acme,
+				Logger:      certmagic.Default.Logger,
+			},
+		}
+
+		log.Debug("acme", "username", acme.Username, "subdomain", acme.Subdomain, "server_url", acme.ServerURL)
+
 		rs := certmagic_redis.New()
 		rs.Address = []string{rc.Address}
 		rs.Username = rc.Username