Sanitized mirror from private repository - 2026-03-21 11:14:37 UTC
This commit is contained in:
360
docs/infrastructure/npm-migration-jan2026.md
Normal file
360
docs/infrastructure/npm-migration-jan2026.md
Normal file
@@ -0,0 +1,360 @@
|
||||
# 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:
|
||||
|
||||
```nginx
|
||||
# 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:
|
||||
```bash
|
||||
curl -I http://192.168.0.250:9000/outpost.goauthentik.io/auth/nginx
|
||||
```
|
||||
|
||||
### Authentik Recovery
|
||||
```bash
|
||||
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:
|
||||
```bash
|
||||
docker logs nginx-proxy-manager
|
||||
```
|
||||
|
||||
### Test Domain Resolution
|
||||
```bash
|
||||
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:
|
||||
|
||||
```nginx
|
||||
# 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:
|
||||
|
||||
```bash
|
||||
# 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
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Authentik SSO Setup](./authentik-sso.md)
|
||||
- [Cloudflare DNS](./cloudflare-dns.md)
|
||||
- [Service Documentation](../services/README.md)
|
||||
Reference in New Issue
Block a user