# 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