Files
homelab-optimized/docs/infrastructure/npm-migration-jan2026.md
Gitea Mirror Bot fb88e1b6d4
Some checks failed
Documentation / Build Docusaurus (push) Failing after 5m1s
Documentation / Deploy to GitHub Pages (push) Has been skipped
Sanitized mirror from private repository - 2026-03-27 11:43:05 UTC
2026-03-27 11:43:05 +00:00

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

  1. Router Configuration

    • Port 443 → 192.168.0.250:8443 (NPM HTTPS)
    • Port 80 → 192.168.0.250:8880 (NPM HTTP)
  2. NPM Container Ports

    • HTTP: 8880 → 80 (internal)
    • HTTPS: 8443 → 443 (internal)
    • Admin: 81 → 81 (internal)
  3. Cleaned up duplicate .synology.me entries (11 deleted)

  4. Created new .vish.gg equivalents for services that only had .synology.me

  5. Added Cloudflare Origin Certificates for thevish.io and crista.love domains

  6. Changed Cloudflare SSL mode from "Full (strict)" to "Full" for thevish.io

  7. 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
  8. Fixed joplin.thevish.io: Works correctly - /login accessible, 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)
Email 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_scheme is set to http in 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

  1. thevish.io domains: Need SSL certificates Fixed - Origin certs added
  2. crista.love domains: Need SSL certificates Fixed - Origin certs added
  3. Change NPM password: Currently using default Changed to REDACTED_NPM_PASSWORD
  4. retro.vish.gg: Returns 403 - check upstream service
  5. joplin.thevish.io: Returns 400 Works correctly - /login accessible
  6. meet.thevish.io: DNS not proxied Fixed - Enabled proxy, HTTPS backend, WebSocket support
  7. cocalc.crista.love: Backend service (192.168.0.100:8080) is down
  8. 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