## Summary Expose Forgejo publicly at `forge.eblu.me` via the Fly.io reverse proxy — the first dynamic, authenticated public-facing service. - **Forgejo hardening:** Domain changed to forge.eblu.me, SSH stays on forge.ops.eblu.me, reverse proxy trust headers configured, local registration locked to external-only (Authentik SSO) - **Tailscale Ingress:** ExternalName Service + Ingress in tailscale-operator creates forge.tail8d86e.ts.net endpoint - **Fly.io proxy:** nginx server block with rate-limited auth endpoints (3r/s), fail2ban with custom nginx-deny action, security headers, /swagger blocked, WebSocket support, 512m body limit - **Authentik:** OAuth callback updated to forge.eblu.me - **DNS/TLS:** CNAME record in Pulumi, cert in fly-setup - **Rename:** ~29 files updated from forge.ops.eblu.me to forge.eblu.me (HTTPS refs only; SSH, container builds, and Caddy table kept as-is) ## Deployment Order 1. `mise run provision-indri -- --tags forgejo` (config changes) 2. Verify forge.ops.eblu.me still works 3. `argocd app set tailscale-operator --revision feature/forge-public && argocd app sync tailscale-operator` 4. Verify `curl https://forge.tail8d86e.ts.net` 5. `cd fly && fly deploy` 6. Verify pre-DNS: `curl -H "Host: forge.eblu.me" https://blumeops-proxy.fly.dev/` 7. `fly certs add forge.eblu.me -a blumeops-proxy` 8. `argocd app set authentik --revision feature/forge-public && argocd app sync authentik` 9. `mise run dns-preview && mise run dns-up` 10. Full verification (see below) 11. Rehearse `mise run fly-shutoff` 12. After merge: reset ArgoCD revisions to main, re-sync ## Verification Checklist - [ ] forge.eblu.me loads, shows public repos - [ ] forge.ops.eblu.me still works from tailnet - [ ] SSH clone via forge.ops.eblu.me:2222 works - [ ] HTTPS clone via forge.eblu.me works - [ ] UI shows forge.eblu.me for HTTPS clone, forge.ops.eblu.me for SSH - [ ] /swagger returns 403 - [ ] Rapid login attempts trigger 429 rate limit - [ ] fail2ban bans after 5 failed logins in 10 minutes - [ ] ArgoCD can still sync (SSH unaffected) - [ ] `mise run fly-shutoff` stops all public traffic - [ ] `mise run services-check` passes Reviewed-on: #278
3.2 KiB
| title | modified | last-reviewed | requires | tags | ||||||
|---|---|---|---|---|---|---|---|---|---|---|
| Build Authentik from Source | 2026-03-01 | 2026-03-02 |
|
|
Build Authentik from Source
Custom Nix derivation that builds authentik from source, replacing the pkgs.authentik nixpkgs dependency. This gives full version control independent of the nixpkgs release cycle.
Motivation
The nix-container-builder runner on ringtail resolves nixpkgs via the NixOS nix registry, which pins to nixos-25.11. That channel lags behind upstream authentik releases. Building from source lets us target any release by updating sources.nix.
Architecture
Authentik has four build components assembled by containers/authentik/default.nix:
- API client generation (
client-go.nix,client-ts.nix) — Go and TypeScript bindings generated fromschema.yml(OpenAPI) - Python backend (
authentik-django.nix) — Django application with 60+ Python dependencies installed viauvfrom PyPI (see authentik-python-backend-derivation) - Web UI (
webui.nix) — Lit-based TypeScript frontend built with esbuild + rollup - Go server (
authentik-server.nix) — HTTP server binary that serves the web UI and spawns gunicorn for Django
The ak wrapper script in default.nix sets PATH/VIRTUAL_ENV and delegates to lifecycle/ak, which dispatches server to the Go binary and everything else to Python/Django.
Python packaging strategy: Nix provides the Python 3.14 interpreter and system libraries. Python packages are installed from PyPI using uv, locked by authentik's uv.lock. This avoids nixpkgs' Python 3.14 compatibility issues and aligns with upstream's build process.
Source
All derivations fetch from forge mirrors for supply chain control:
- https://forge.eblu.me/mirrors/authentik (upstream:
goauthentik/authentik) - https://forge.eblu.me/mirrors/authentik-client-go (upstream:
goauthentik/client-go)
Version and hashes are centralized in containers/authentik/sources.nix.
Updating to a New Version
- Update
versioninsources.nixanddefault.nix - Update
srcandclient-go-srchashes insources.nix(usenix-prefetch-giton ringtail) - Rebuild
python-deps.nixFOD — hash changes whenuv.lockchanges - Rebuild
webui-deps.nixFOD — hash changes whenpackage-lock.jsonor platform-specific npm binaries change - Recompute
vendorHashinauthentik-server.nixif Go dependencies changed - Test on ringtail:
nix-build test-build.nix -A assembled - Build and push the container via CI
Testing
Nix derivations target x86_64-linux. Test incrementally on ringtail:
set tmpdir (ssh ringtail 'mktemp -d /tmp/authentik-test.XXXXXX')
scp containers/authentik/*.nix ringtail:$tmpdir/
ssh ringtail "cd $tmpdir && nix-build test-build.nix -A assembled --extra-experimental-features 'nix-command flakes'"
ssh ringtail "rm -rf $tmpdir"
test-build.nix provides both individual component targets and a fully-wired assembled target.
Related
- build-authentik-container — Container build reference
- deploy-authentik — Parent deployment goal
- agent-change-process — C2 methodology