diff options
-rw-r--r-- | config.toml | 7 | ||||
-rw-r--r-- | content/post/searchix.md | 33 | ||||
-rw-r--r-- | fly.toml | 3 | ||||
-rw-r--r-- | go.mod | 1 | ||||
-rw-r--r-- | go.sum | 2 | ||||
-rw-r--r-- | internal/config/config.go | 3 | ||||
-rw-r--r-- | internal/server/server.go | 32 | ||||
-rw-r--r-- | internal/server/tls.go | 39 | ||||
-rw-r--r-- | internal/vcs/repository.go | 34 | ||||
-rw-r--r-- | templates/page.templ | 9 | ||||
-rw-r--r-- | templates/style.css | 8 |
11 files changed, 137 insertions, 34 deletions
diff --git a/config.toml b/config.toml index 979669f..a1302ee 100644 --- a/config.toml +++ b/config.toml @@ -13,14 +13,15 @@ domains = [ "alanpearce.uk", "www.alanpearce.uk", "aln.pe", - "www.aln.pe", - "alanpearce-eu.fly.dev", + "*.aln.pe", ] oidc_host = "https://id.alanpearce.eu/" goatcounter = "https://stats.alanpearce.eu/count" +wildcard_domain = "aln.pe" + [[taxonomies]] name = "tags" feed = true @@ -51,6 +52,8 @@ goatcounter = "https://stats.alanpearce.eu/count" "'sha256-dCSzNS1o8vygl80V2G2nPTiSOUNvyDnW+06hHS4ZdHQ='", ## atom.xml style "'sha256-CFhPA4p8skr5MyhReF+Tk2GzmYzXdECg8zm+o7EOVPI=", + ## cv style + "'sha256-FzrPQ6x2ugtwEN5peA8OqpIvrV3uXqkpfUMHG8P2uT0='", ] frame-ancestors = [ "https://kagi.com", diff --git a/content/post/searchix.md b/content/post/searchix.md new file mode 100644 index 0000000..6e1962b --- /dev/null +++ b/content/post/searchix.md @@ -0,0 +1,33 @@ +--- +title: "Announcing Searchix: Nix ecosystem search" +date: 2024-07-11T15:05:00+02:00 +taxonomies: + tags: [nix, searchix] +--- + +I decided to create a search tool for NixOS, nix-darwin and +home-manager options and packages, potentially with more sources to +come. + +I called it [Searchix](https://searchix.alanpearce.eu/) + +For NixOS options and packages, +[search.nixos.org](https://search.nixos.org) already exists (and works +better than Searchix), whereas for home-manager and nix-darwin, I +couldn't manage to find a web-based search tool that's still +online[^1]. So I wrote one. + +What I'm happy about with it is that it doesn't _require_ JavaScript, +but, if it's enabled, makes things a little bit better. It's only my +second project in Golang, so I still have things to learn, but I +definitely think I will enjoy using this language further. + +It still has quite a bit of room for improvement, but I've been using +it quite a lot recently, which leads me to think that other people +might like to use it, too. + +If anyone would like to contribute, raise an issue, or host an +instance themselves, the [project site and source code are on sr.ht](https://sr.ht/~alanpearce/searchix/). + +[^1]: I found [Home Manager Option Search](https://home-manager-options.extranix.com/) after I + started this project, but nothing for nix-darwin. diff --git a/fly.toml b/fly.toml index 7508dd6..ef6e3ea 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 @@ -42,7 +43,7 @@ primary_region = "ams" [[services.http_checks]] grace_period = "10s" protocol = "https" - tls_server_name = "alanpearce-eu.fly.dev" + tls_server_name = "alanpearce.eu" interval = "10s" method = "GET" timeout = "1s" 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..7ccad85 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -42,7 +42,8 @@ type Config struct { OriginalDomain string `toml:"original_domain"` GoatCounter URL `toml:"goatcounter"` Domains []string - OIDCHost URL `toml:"oidc_host"` + WildcardDomain string `toml:"wildcard_domain"` + OIDCHost URL `toml:"oidc_host"` Taxonomies []Taxonomy CSP *CSP `toml:"content-security-policy"` Extra struct { diff --git a/internal/server/server.go b/internal/server/server.go index b174c0c..269ed9e 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" @@ -74,7 +75,6 @@ func applyDevModeOverrides(config *cfg.Config, runtimeConfig *Config) { } func updateCSPHashes(config *cfg.Config, r *builder.Result) { - clear(config.CSP.StyleSrc) for i, h := range r.Hashes { config.CSP.StyleSrc[i] = fmt.Sprintf("'%s'", h) } @@ -184,21 +184,35 @@ func New(runtimeConfig *Config, log *log.Logger) (*Server, error) { } if runtimeConfig.Redirect { + re := regexp.MustCompile( + "^(.*)\\." + strings.ReplaceAll(config.WildcardDomain, ".", `\.`) + "$", + ) + replace := "${1}." + 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 { + url := config.BaseURL + url.Host = re.ReplaceAllString(r.Host, replace) + http.Redirect(w, r, url.String(), http.StatusTemporaryRedirect) + } }) } else { loggingMux.Handle("/", mux) } - top.Handle("/", - serverHeaderHandler( - wrapHandlerWithLogging(loggingMux, log), - ), - ) + if runtimeConfig.Development { + top.Handle("/", + serverHeaderHandler( + wrapHandlerWithLogging(loggingMux, log), + ), + ) + } else { + top.Handle("/", serverHeaderHandler(loggingMux)) + } top.HandleFunc("/health", func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusNoContent) diff --git a/internal/server/tls.go b/internal/server/tls.go index 9481b6a..4d52b8d 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") @@ -32,10 +40,7 @@ func (s *Server) serveTLS() (err error) { cfg := certmagic.NewDefault() cfg.DefaultServerName = s.config.Domains[0] - issuer := &certmagic.DefaultACME - certmagic.DefaultACME.Agreed = true - certmagic.DefaultACME.Email = s.config.Email - certmagic.DefaultACME.Logger = certmagic.Default.Logger + var issuer *certmagic.ACMEIssuer if s.runtimeConfig.Development { ca := s.runtimeConfig.ACMECA @@ -63,8 +68,8 @@ func (s *Server) serveTLS() (err error) { ListenHost: s.runtimeConfig.ListenAddress, AltHTTPPort: s.runtimeConfig.Port, AltTLSALPNPort: s.runtimeConfig.TLSPort, + Logger: certmagic.Default.Logger, }) - cfg.Issuers[0] = issuer } else { rc := &redisConfig{} _, err = conf.Parse("REDIS", rc) @@ -72,6 +77,27 @@ 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 = certmagic.NewACMEIssuer(cfg, certmagic.ACMEIssuer{ + CA: certmagic.LetsEncryptProductionCA, + Email: s.config.Email, + Agreed: true, + Logger: certmagic.Default.Logger, + DNS01Solver: &certmagic.DNS01Solver{ + DNSManager: certmagic.DNSManager{ + DNSProvider: acme, + Logger: certmagic.Default.Logger, + }, + }, + }) + + log.Info("acme", "username", acme.Username, "subdomain", acme.Subdomain, "server_url", acme.ServerURL) + rs := certmagic_redis.New() rs.Address = []string{rc.Address} rs.Username = rc.Username @@ -87,6 +113,7 @@ func (s *Server) serveTLS() (err error) { return errors.Wrap(err, "could not provision redis storage") } } + cfg.Issuers[0] = issuer ln, err := listenfd.GetListener( 1, @@ -137,7 +164,7 @@ func (s *Server) serveTLS() (err error) { "https_port", s.runtimeConfig.TLSPort, ) - err = cfg.ManageSync(context.TODO(), s.config.Domains) + err = cfg.ManageAsync(context.TODO(), s.config.Domains) if err != nil { return errors.Wrap(err, "could not enable TLS") } diff --git a/internal/vcs/repository.go b/internal/vcs/repository.go index e034ea4..5950e53 100644 --- a/internal/vcs/repository.go +++ b/internal/vcs/repository.go @@ -7,6 +7,7 @@ import ( "go.alanpearce.eu/x/log" "github.com/go-git/go-git/v5" + "github.com/go-git/go-git/v5/plumbing" "gitlab.com/tozd/go/errors" ) @@ -61,13 +62,8 @@ func (r *Repository) Update() (bool, error) { } r.log.Info("updating from", "rev", head.Hash().String()) - wt, err := r.repo.Worktree() - if err != nil { - return false, err - } - err = wt.Pull(&git.PullOptions{ - SingleBranch: true, - Force: true, + err = r.repo.Fetch(&git.FetchOptions{ + Prune: true, }) if err != nil { if errors.Is(err, git.NoErrAlreadyUpToDate) { @@ -79,11 +75,31 @@ func (r *Repository) Update() (bool, error) { return false, err } - head, err = r.repo.Head() + rem, err := r.repo.Remote("origin") if err != nil { return false, err } - r.log.Info("updated to", "rev", head.Hash().String()) + refs, err := rem.List(&git.ListOptions{ + Timeout: 5, + }) + + var hash plumbing.Hash + for _, ref := range refs { + if ref.Name() == plumbing.Main { + hash = ref.Hash() + } + } + + wt, err := r.repo.Worktree() + if err != nil { + return false, err + } + wt.Checkout(&git.CheckoutOptions{ + Hash: hash, + Force: true, + }) + + r.log.Info("updated to", "rev", hash) return true, r.Clean(wt) } diff --git a/templates/page.templ b/templates/page.templ index fb91b23..39dd263 100644 --- a/templates/page.templ +++ b/templates/page.templ @@ -4,6 +4,7 @@ import ( "io/fs" "go.alanpearce.eu/website/internal/config" + "net/url" ) var ( @@ -86,8 +87,12 @@ templ Page(site *config.Config, page PageSettings) { </html> } -func mkURL(u config.URL, path string, title string) string { - q := u.Query() +func mkURL(original config.URL, path string, title string) string { + ou := *original.URL + u := config.URL{ + URL: &ou, + } + q := url.Values{} q.Add("p", path) q.Add("t", title) u.RawQuery = q.Encode() diff --git a/templates/style.css b/templates/style.css index 84ce1ce..e9a2955 100644 --- a/templates/style.css +++ b/templates/style.css @@ -188,13 +188,13 @@ ul.h-feed li a:visited { .tags { font-size: small; -} - -.p-categories, -ul.tags { display: inline-block; padding-inline-start: 0; } +.p-categories { + padding-inline-start: 1ex; +} + .tags li { list-style: none; display: inline-block; |