Files
portainer-core/setup-new-host.md
T
jpmschweitzerandClaude Opus 4.5 9b2b32323c docs: add setup guide for SSL + Authentik protected hosts
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 <noreply@anthropic.com>
2025-12-14 12:06:05 +01:00

9.3 KiB

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 <subdomain>.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 AdminApplicationsProviders
  2. Click Create → Select Proxy Provider
  3. Configure:
Setting Value
Name <subdomain>.schweitz.net proxy
Authorization flow default-provider-authorization-implicit-consent
Forward auth (single application) Selected
External host https://<subdomain>.schweitz.net

Leave other settings as defaults (token validity 24 hours is fine).

1.2 Create an Application

  1. Go to ApplicationsApplications
  2. Click Create
  3. Configure:
Setting Value
Name <Descriptive Name> (e.g., "Library Wiki")
Slug <subdomain>-schweitz-net
Provider Select the proxy provider created above
Launch URL https://<subdomain>.schweitz.net

1.3 Add Application to Outpost

  1. Go to ApplicationsOutposts
  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 <subdomain>.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:

# 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://<subdomain>.schweitz.net
  3. You should be redirected to Authentik login (Google OAuth or local)
  4. After login, you should see your application

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://<forward_host>:<forward_port> 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 <subdomain>.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://<subdomain>.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