From 9b2b32323cfdb179826cd413676b5b110e8f9381 Mon Sep 17 00:00:00 2001 From: Jeroen Schweitzer Date: Sun, 14 Dec 2025 12:06:05 +0100 Subject: [PATCH] docs: add setup guide for SSL + Authentik protected hosts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Step-by-step instructions for adding new subdomains with: - Let's Encrypt SSL via NPM - Authentik forward authentication - Troubleshooting common issues πŸ€– Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- setup-new-host.md | 263 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 263 insertions(+) create mode 100644 setup-new-host.md diff --git a/setup-new-host.md b/setup-new-host.md new file mode 100644 index 0000000..3e55f78 --- /dev/null +++ b/setup-new-host.md @@ -0,0 +1,263 @@ +# Setting Up a New SSL-Secured, Authentik-Protected Host + +This guide documents how to add a new public-facing subdomain with SSL (Let's Encrypt) and Authentik forward authentication through Nginx Proxy Manager (NPM). + +## Prerequisites + +Before starting, ensure: + +1. **DNS A Record**: Create an A record for `.schweitz.net` pointing to your public IP +2. **Container Running**: The target service container is running and accessible +3. **Network**: Container is on `docker-dataplane` network (or accessible from NPM) +4. **Authentik Running**: Both Authentik server and outpost(s) are operational + +## Step 1: Authentik Configuration + +### 1.1 Create a Proxy Provider + +1. Go to **Authentik Admin** β†’ **Applications** β†’ **Providers** +2. Click **Create** β†’ Select **Proxy Provider** +3. Configure: + +| Setting | Value | +|---------|-------| +| Name | `.schweitz.net proxy` | +| Authorization flow | `default-provider-authorization-implicit-consent` | +| Forward auth (single application) | **Selected** | +| External host | `https://.schweitz.net` | + +Leave other settings as defaults (token validity 24 hours is fine). + +### 1.2 Create an Application + +1. Go to **Applications** β†’ **Applications** +2. Click **Create** +3. Configure: + +| Setting | Value | +|---------|-------| +| Name | `` (e.g., "Library Wiki") | +| Slug | `-schweitz-net` | +| Provider | Select the proxy provider created above | +| Launch URL | `https://.schweitz.net` | + +### 1.3 Add Application to Outpost + +1. Go to **Applications** β†’ **Outposts** +2. Edit the **standalone outpost** (authentik-proxy on port 9443/9445) +3. In **Applications**, add your new application to the selected list +4. Click **Update** + +> **Note**: If using both embedded and standalone outposts, add the application to whichever outpost your forward auth config points to (standalone at `localhost:9445` in our setup). + +## Step 2: NPM Configuration + +### 2.1 Create Proxy Host + +In NPM Admin (port 8000 or via API): + +**Details Tab:** + +| Setting | Value | +|---------|-------| +| Domain Names | `.schweitz.net` | +| Scheme | `http` (usually) | +| Forward Hostname/IP | Container name or IP (e.g., `wiki` or `192.168.86.149`) | +| Forward Port | Container's internal port (e.g., `3000`) | +| Cache Assets | Off (unless needed) | +| Block Common Exploits | On | +| Websockets Support | On | + +**SSL Tab:** + +| Setting | Value | +|---------|-------| +| SSL Certificate | Request a new SSL Certificate | +| Force SSL | On | +| HTTP/2 Support | On | +| HSTS Enabled | On | +| Email for Let's Encrypt | `jpmschweitzer@gmail.com` | +| Agree to TOS | Yes | + +**Advanced Tab:** + +Paste the following configuration: + +```nginx +# Increase buffer size for large headers from Authentik +proxy_buffers 8 16k; +proxy_buffer_size 32k; + +# Forward authentication via standalone outpost +auth_request /outpost.goauthentik.io/auth/nginx; +error_page 401 = @goauthentik_proxy_signin; + +# Capture auth response headers +auth_request_set $auth_cookie $upstream_http_set_cookie; +auth_request_set $authentik_username $upstream_http_x_authentik_username; +auth_request_set $authentik_groups $upstream_http_x_authentik_groups; +auth_request_set $authentik_email $upstream_http_x_authentik_email; +auth_request_set $authentik_name $upstream_http_x_authentik_name; +auth_request_set $authentik_uid $upstream_http_x_authentik_uid; + +# Forward auth headers to application +add_header Set-Cookie $auth_cookie; +proxy_set_header X-authentik-username $authentik_username; +proxy_set_header X-authentik-groups $authentik_groups; +proxy_set_header X-authentik-email $authentik_email; +proxy_set_header X-authentik-name $authentik_name; +proxy_set_header X-authentik-uid $authentik_uid; + +# Outpost proxy location +location /outpost.goauthentik.io { + proxy_pass https://localhost:9445/outpost.goauthentik.io; + proxy_set_header Host $host; + proxy_set_header X-Original-URL $scheme://$http_host$request_uri; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Host $http_host; + proxy_set_header X-Forwarded-For $remote_addr; + proxy_pass_request_body off; + proxy_set_header Content-Length ""; +} + +# Signin redirect handler - MUST use relative path, not absolute URL +location @goauthentik_proxy_signin { + internal; + add_header Set-Cookie $auth_cookie; + return 302 /outpost.goauthentik.io/start?rd=$request_uri; +} +``` + +> **Critical**: The redirect in `@goauthentik_proxy_signin` MUST use a relative path (`/outpost.goauthentik.io/start`), NOT an absolute URL. Using `https://auth.schweitz.net/outpost.goauthentik.io/start` will cause a 404 error due to host header mismatch. + +### 2.2 Save and Verify + +1. Click **Save** +2. Verify nginx status shows online (no errors) +3. If errors occur, check the Advanced config syntax + +## Step 3: Testing + +### 3.1 Initial Test + +1. Open an **incognito/private browser window** +2. Navigate to `https://.schweitz.net` +3. You should be redirected to Authentik login (Google OAuth or local) +4. After login, you should see your application + +### 3.2 SSO Cookie Test + +If already logged into another `.schweitz.net` service: +1. Open a new tab (same browser, not incognito) +2. Navigate to the new subdomain +3. You should access the application without re-authenticating (SSO cookie shared across `.schweitz.net`) + +## Troubleshooting + +### Authentik 404 "Not Found" Error + +**Symptom**: Redirected to `auth.schweitz.net/outpost.goauthentik.io/start?rd=...` but see 404 + +**Causes & Fixes**: + +1. **Absolute URL in redirect** (most common) + - Fix: Change `return 302 https://auth.schweitz.net/outpost.goauthentik.io/start...` to `return 302 /outpost.goauthentik.io/start...` + +2. **Application not added to outpost** + - Fix: Go to Authentik β†’ Outposts β†’ Edit standalone outpost β†’ Add application + +3. **Provider not linked to application** + - Fix: Edit application β†’ Select the correct proxy provider + +### Nginx Config Error / nginx_online: false + +**Symptom**: NPM shows nginx error when saving + +**Causes & Fixes**: + +1. **Undefined variable `$connection_upgrade`** + - Fix: Remove WebSocket lines (`proxy_http_version`, `Upgrade`, `Connection` headers) from advanced config. NPM handles WebSockets via the "Websockets Support" toggle. + +2. **Syntax error in advanced config** + - Fix: Verify all brackets are closed, semicolons present + +### 502 Bad Gateway + +**Symptom**: Auth works but application shows 502 + +**Causes & Fixes**: + +1. **Wrong forward host/port** + - Fix: Verify container name and port in NPM proxy host settings + - Test: `curl http://:` from NPM container + +2. **Container not on correct network** + - Fix: Ensure container is on `docker-dataplane` network + +3. **Outpost not running** + - Check: `docker ps | grep authentik-proxy` + - Check logs: `docker logs authentik-proxy` + +### SSL Certificate Not Provisioning + +**Symptom**: Certificate request fails + +**Causes & Fixes**: + +1. **DNS not propagated** + - Fix: Wait for DNS propagation, verify with `dig .schweitz.net` + +2. **Port 80 blocked** + - Fix: Ensure port 80 is open for Let's Encrypt HTTP-01 challenge + +### Redirect Loop + +**Symptom**: Browser shows "too many redirects" + +**Causes & Fixes**: + +1. **Auth domain has forward auth enabled** + - Fix: `auth.schweitz.net` must NOT have forward auth (would create loop) + +2. **Cookie domain mismatch** + - Fix: Verify Authentik cookie domain is `.schweitz.net` + +## Reference Files + +| File | Purpose | +|------|---------| +| `stacks/authentik.yml` | Authentik server, worker, and standalone outpost | +| `stacks/wiki.yml` | Example: Wiki.js container configuration | +| `npm-configs/organizr-forward-auth.conf` | Legacy reference (has bugs, do not use directly) | + +## Architecture Overview + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ User Browser │────▢│ NPM (port 80/ │────▢│ Target Service β”‚ +β”‚ β”‚ β”‚ 443) β”‚ β”‚ (e.g., Wiki.js)β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β”‚ auth_request + β–Ό + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚ Authentik │────▢│ Authentik β”‚ + β”‚ Standalone β”‚ β”‚ Server β”‚ + β”‚ Outpost (9445) β”‚ β”‚ (auth.schweitz β”‚ + β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ .net) β”‚ + β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +**Flow**: +1. User requests `https://.schweitz.net` +2. NPM's `auth_request` directive checks with Authentik outpost +3. If not authenticated: redirect to Authentik login +4. User authenticates (Google OAuth, etc.) +5. Authentik sets session cookie for `.schweitz.net` +6. User redirected back, `auth_request` succeeds +7. NPM proxies request to target service + +--- + +**Last Updated**: 2025-12-13 +**Based on**: library.schweitz.net setup session