11 KiB
NPM Migration & Authentik Configuration (January 2026)
This document details the migration from Synology's built-in reverse proxy to Nginx Proxy Manager (NPM) with Authentik SSO protection.
Migration Summary
Date: January 31, 2026
Status: Complete
Last Updated: January 31, 2026 (Session 2)
Performed by: OpenHands AI Agent
What Changed
-
Router Configuration
- Port 443 → 192.168.0.250:8443 (NPM HTTPS)
- Port 80 → 192.168.0.250:8880 (NPM HTTP)
-
NPM Container Ports
- HTTP: 8880 → 80 (internal)
- HTTPS: 8443 → 443 (internal)
- Admin: 81 → 81 (internal)
-
Cleaned up duplicate .synology.me entries (11 deleted)
-
Created new .vish.gg equivalents for services that only had .synology.me
-
Added Cloudflare Origin Certificates for thevish.io and crista.love domains
-
Changed Cloudflare SSL mode from "Full (strict)" to "Full" for thevish.io
-
Fixed meet.thevish.io (Jitsi):
- Enabled Cloudflare proxy (was DNS-only)
- Changed backend to HTTPS (port 5443 uses SSL internally)
- Added WebSocket support for XMPP connections
-
Fixed joplin.thevish.io: Works correctly -
/loginaccessible, root returns 400 (expected API behavior)
Access Credentials
NPM (Nginx Proxy Manager)
| Field | Value |
|---|---|
| URL | https://npm.vish.gg or http://192.168.0.250:81 (local) |
| user@example.com | |
| Password | REDACTED_NPM_PASSWORD |
| API Port | 81 |
Note: npm.vish.gg shows "Not Secure" because the wildcard cert doesn't cover it. Access locally at http://192.168.0.250:81 for admin tasks.
Authentik SSO
| Field | Value |
|---|---|
| URL | https://sso.vish.gg |
| Admin Username | akadmin |
| Recovery Command | docker exec -it Authentik-SERVER ak create_recovery_key 10 akadmin |
| Secret Key | RpRexcYo5HAzvb8UGBhznwhq17sa2HALAYdMN51LR1ZBg5iL |
| PostgreSQL Password | ANJXq7n70DFEgWE+gD1qKhY/cXgQDPpjAJeF+Huiac8= |
Portainer
| Field | Value |
|---|---|
| URL | http://vishinator.synology.me:10000 |
| API Key | ptr_REDACTED_PORTAINER_TOKEN |
| NPM Endpoint ID | 443397 |
Cloudflare API
| Field | Value |
|---|---|
| Token | REDACTED_CLOUDFLARE_TOKEN |
| vish.gg Zone ID | 4dbd15d096d71101b7c0c6362b307a66 |
| thevish.io Zone ID | 11681f1c93ca32f56a0c41973e02b6f9 |
| crista.love Zone ID | (not documented) |
SSL Certificates
Certificate Inventory
| ID | Domain | Type | Expires | Location |
|---|---|---|---|---|
| 1 | *.vish.gg, vish.gg |
Cloudflare Origin | 2041 | /data/custom_ssl/npm-1/ |
| 2 | *.thevish.io, thevish.io |
Cloudflare Origin | 2041-01-27 | /data/custom_ssl/npm-2/ |
| 3 | *.crista.love, crista.love |
Cloudflare Origin | 2041-01-21 | /data/custom_ssl/npm-3/ |
Cloudflare SSL Mode Settings
| Zone | SSL Mode | Notes |
|---|---|---|
| vish.gg | Full | Works with Origin CA |
| thevish.io | Full | Changed from Full (strict) on 2026-01-31 |
| crista.love | Full | Works with Origin CA |
Proxy Host Inventory
vish.gg Domains (20 total, SSL cert ID 1)
| Domain | Backend | Port | Authentik | Status |
|---|---|---|---|---|
| actual.vish.gg | 192.168.0.250 | 8304 | ✅ Yes | ✅ Working |
| cal.vish.gg | 192.168.0.200 | 12852 | No | ✅ Working |
| dav.vish.gg | 192.168.0.250 | 8612 | No | ✅ Working |
| docs.vish.gg | 192.168.0.250 | 8777 | ✅ Yes | ✅ Working |
| gf.vish.gg | 192.168.0.210 | 3300 | ✅ Yes | ✅ Working |
| git.vish.gg | 192.168.0.250 | 3052 | No (own auth) | ✅ Working |
| mastodon.vish.gg | 192.168.0.154 | 3000 | No (public) | ✅ Working |
| mx.vish.gg | 192.168.0.154 | 8082 | No | ✅ Working |
| npm.vish.gg | 192.168.0.250 | 81 | ✅ Yes | ✅ Working |
| ntfy.vish.gg | 192.168.0.210 | 8081 | No (API access needed) | ✅ Working |
| ollama.vish.gg | 192.168.0.200 | 11434 | No | ✅ Working |
| ost.vish.gg | 192.168.0.250 | 8004 | No | ✅ Working |
| paperless.vish.gg | 192.168.0.250 | 8777 | ✅ Yes | ✅ Working |
| pw.vish.gg | 192.168.0.200 | 4080 | No (Vaultwarden) | ✅ Working |
| rackula.vish.gg | 192.168.0.250 | 3891 | No | ✅ Working |
| retro.vish.gg | 192.168.0.250 | 8025 | No | ⚠️ 403 (upstream issue) |
| rxv4access.vish.gg | 192.168.0.250 | 9751 | No | ✅ Working |
| rxv4download.vish.gg | 192.168.0.250 | 9753 | No | ✅ Working |
| sf.vish.gg | 192.168.0.250 | 8611 | No (Seafile) | ✅ Working |
| sso.vish.gg | 192.168.0.250 | 9000 | No (Authentik itself) | ✅ Working |
thevish.io Domains (5 total, SSL cert ID 2)
| Domain | Backend | Port | Status | Notes |
|---|---|---|---|---|
| binterest.thevish.io | 192.168.0.210 | 21544 | ✅ Working | |
| hoarder.thevish.io | 192.168.0.210 | 3000 | ✅ Working | Returns 307 redirect |
| joplin.thevish.io | 192.168.0.200 | 22300 | ✅ Working | /login works, / returns 400 (expected for API) |
| matrix.thevish.io | 192.168.0.154 | 8081 | ✅ Working | |
| meet.thevish.io | 192.168.0.200 | 5443 | ✅ Working | HTTPS backend, WebSocket config added |
crista.love Domains (3 total, SSL cert ID 3)
| Domain | Backend | Port | Status | Notes |
|---|---|---|---|---|
| crista.love | 192.168.0.100 | 28888 | ✅ Working | Academic portfolio site |
| cocalc.crista.love | 192.168.0.100 | 8080 | ❌ 502 | Backend service is down |
| mm.crista.love | 192.168.0.154 | 8065 | ✅ Working | Mattermost |
Authentik Forward Auth Configuration
Services protected by Authentik use this NPM Advanced Configuration:
# Authentik Forward Auth Configuration
proxy_buffers 8 16k;
proxy_buffer_size 32k;
auth_request /outpost.goauthentik.io/auth/nginx;
error_page 401 = @goauthentik_proxy_signin;
auth_request_set $auth_cookie $upstream_http_set_cookie;
add_header Set-Cookie $auth_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;
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;
location /outpost.goauthentik.io {
proxy_pass http://192.168.0.250:9000/outpost.goauthentik.io;
proxy_set_header Host $host;
proxy_set_header X-Original-URL $scheme://$http_host$request_uri;
add_header Set-Cookie $auth_cookie;
auth_request_set $auth_cookie $upstream_http_set_cookie;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
}
location @goauthentik_proxy_signin {
internal;
add_header Set-Cookie $auth_cookie;
return 302 https://sso.vish.gg/outpost.goauthentik.io/start?rd=$scheme://$http_host$request_uri;
}
Cloudflare DNS Configuration
vish.gg Zone
All subdomains should be Proxied (orange cloud) and point to YOUR_WAN_IP.
Missing DNS records were added during migration:
- paperless.vish.gg
- ollama.vish.gg
- rxv4access.vish.gg
- rxv4download.vish.gg
thevish.io Zone
All subdomains point to YOUR_WAN_IP and are proxied.
Important: SSL mode must be "Full" (not "Full strict") for Origin CA certs to work.
crista.love Zone
Subdomains point to YOUR_WAN_IP and are proxied.
Troubleshooting
NPM Returns 500 Error
Check if Authentik outpost is accessible:
curl -I http://192.168.0.250:9000/outpost.goauthentik.io/auth/nginx
Authentik Recovery
docker exec -it Authentik-SERVER ak create_recovery_key 10 akadmin
Then visit: https://sso.vish.gg/recovery/use-token/<TOKEN>/
Check NPM Logs
Via Portainer or:
docker logs nginx-proxy-manager
Test Domain Resolution
curl -sI -k https://domain.vish.gg | head -5
522 Error (Connection Timed Out)
- Check if Cloudflare can reach your origin (port 443 forwarded?)
- Verify SSL mode is "Full" not "Full (strict)" for Origin CA certs
- Check if backend service is running
525 Error (SSL Handshake Failed)
- Origin expects HTTPS but backend doesn't have SSL
- Check
forward_schemeis set tohttpin NPM for internal services
Host Shows "Offline" in NPM
- Config file may not be generated
- Re-save the host in NPM to regenerate config
- Or manually create config in
/data/nginx/proxy_host/{id}.conf
TODO / Known Issues
thevish.io domains: Need SSL certificates✅ Fixed - Origin certs addedcrista.love domains: Need SSL certificates✅ Fixed - Origin certs addedChange NPM password: Currently using default✅ Changed to REDACTED_NPM_PASSWORD- retro.vish.gg: Returns 403 - check upstream service
joplin.thevish.io: Returns 400✅ Works correctly - /login accessiblemeet.thevish.io: DNS not proxied✅ Fixed - Enabled proxy, HTTPS backend, WebSocket support- cocalc.crista.love: Backend service (192.168.0.100:8080) is down
crista.love: Verify correct backend✅ Working - Academic portfolio site
Jitsi Meet (meet.thevish.io) WebSocket Configuration
Jitsi requires special WebSocket handling for XMPP connections. The NPM config at /data/nginx/proxy_host/18.conf includes:
# meet.thevish.io - Jitsi Meet with WebSocket support
map $scheme $hsts_header {
https "max-age=63072000; preload";
}
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
set $forward_scheme https; # Jitsi uses HTTPS internally
set $server "192.168.0.200";
set $port 5443;
listen 80;
listen 443 ssl;
server_name meet.thevish.io;
http2 on;
ssl_certificate /data/custom_ssl/npm-2/fullchain.pem;
ssl_certificate_key /data/custom_ssl/npm-2/privkey.pem;
# XMPP WebSocket endpoint - critical for Jitsi
location /xmpp-websocket {
proxy_pass $forward_scheme://$server:$port/xmpp-websocket;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
# BOSH endpoint (fallback)
location /http-bind {
proxy_pass $forward_scheme://$server:$port/http-bind;
proxy_buffering off;
tcp_nodelay on;
}
}
Manual Config Creation
If NPM shows a host as "offline" and won't generate configs, create manually:
# Inside NPM container
cat > /data/nginx/proxy_host/{ID}.conf << 'EOF'
# {domain}
map $scheme $hsts_header {
https "max-age=63072000; preload";
}
server {
set $forward_scheme http;
set $server "{backend_ip}";
set $port {backend_port};
listen 80;
listen 443 ssl;
server_name {domain};
http2 on;
ssl_certificate /data/custom_ssl/npm-{cert_id}/fullchain.pem;
ssl_certificate_key /data/custom_ssl/npm-{cert_id}/privkey.pem;
include conf.d/include/block-exploits.conf;
include conf.d/include/force-ssl.conf;
access_log /data/logs/proxy-host-{ID}_access.log proxy;
error_log /data/logs/proxy-host-{ID}_error.log warn;
location / {
include conf.d/include/proxy.conf;
}
include /data/nginx/custom/server_proxy[.]conf;
}
EOF
# Then reload nginx
nginx -t && nginx -s reload