VPS
| Item | Detail |
|---|---|
| Hostname | WTSCPVM01 |
| Provider | Netcup SCP |
| IP address | 152.53.226.118 |
| OS | Debian 13 |
| Spec | 2 vCPU, 4 GB RAM |
| Location | Germany |
The VPS runs two stacks: Pangolin (the reverse proxy and tunnel server) and Keycloak (identity provider). Both are managed via Docker Compose under /root/ and /opt/keycloak/ respectively.
Services
Section titled “Services”| Name | Description | Version | URLs | Status |
|---|---|---|---|---|
| Pangolin | Self-hosted reverse proxy and tunnelling solution | ee-1.16.2 | https://pangolin.wighttrash.uk | running |
| Traefik | Reverse proxy - TLS termination and routing | 3.6 | - | running |
| Gerbil | WireGuard tunnel manager | 1.3.0 | - | running |
| Keycloak | Identity and access management | 26.4.7 | https://auth.wighttrash.uk | running |
| PostgreSQL | Keycloak database | 16 | - | running |
- Traefik: Shares network namespace with Gerbil.
- Gerbil: Handles inbound ports 80, 443, 51820, 21820.
- PostgreSQL: Internal only. Not exposed.
Architecture
Section titled “Architecture”Cloudflare terminates TLS at the edge for all proxied records. Traffic arrives at the VPS on ports 80 and 443, enters through Gerbil, and is routed by Traefik. Keycloak runs on HTTP internally and is exposed via Traefik on port 8080.
flowchart TD
INT([Internet])
CF["Cloudflare
TLS for proxied records"]
TR["Traefik - port 443
shares Gerbil network namespace"]
GB["Gerbil
WireGuard tunnel manager
inbound 51820 and 21820"]
TN["TrueNAS
via Newt WireGuard tunnel"]
PN["Pangolin frontend
pangolin.wighttrash.uk"]
KC["Keycloak
auth.wighttrash.uk"]
JF["Jellyfin
media.wighttrash.uk"]
IM["Immich
photos.wighttrash.uk - DNS only"]
INT --> CF
CF -->|"*.wighttrash.uk → 152.53.226.118:443"| TR
GB --> TR
TR --> PN
TR --> KC
TR --> JF
TR --> IM
TN -->|"192.168.1.28:8096"| JF
TN -->|"192.168.1.28:30041"| IM
File layout
Section titled “File layout”/root/├── docker-compose.yml <- Pangolin stack (pangolin, gerbil, traefik)├── .env <- Cloudflare API token├── config/│ ├── config.yml <- Pangolin main config│ ├── privateConfig.yml <- Enterprise Edition features│ ├── traefik/│ │ ├── traefik_config.yml│ │ └── dynamic_config.yml│ ├── letsencrypt/│ │ └── acme.json│ └── db/ <- Pangolin database
/opt/keycloak/├── docker-compose.yml <- Keycloak stack (keycloak, postgres)├── .env <- Keycloak secrets└── Dockerfile <- Optimised build imageCommon commands
Section titled “Common commands”# Pangolin - full restart (always use down/up, never restart)cd /root && docker compose down && docker compose up -d
# Pangolin - follow Traefik logscd /root && docker compose logs traefik --follow
# Keycloak - restartcd /opt/keycloak && docker compose restart
# Keycloak - check healthcurl -s http://localhost:9000/health/ready
# Check all containersdocker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"VPS firewall
Section titled “VPS firewall”Managed via the Netcup SCP firewall panel. Rules are applied top to bottom with an implicit DROP on all unmatched traffic.
| Description | Direction | Protocol | Port |
|---|---|---|---|
| HTTP | INCOMING | TCP | 80 |
| HTTPS | INCOMING | TCP | 443 |
| WireGuard (Gerbil) | INCOMING | UDP | 51820 |
| WireGuard (Gerbil) | INCOMING | UDP | 21820 |
| SSH | INCOMING | TCP | 22 (source-restricted) |
| HTTPS outbound | OUTGOING | TCP | 443 |
| HTTP outbound | OUTGOING | TCP | 80 |
| DNS | OUTGOING | UDP | 53 |
| Mail relay | OUTGOING | TCP | 587 |
| WireGuard | OUTGOING | UDP | 51820, 21820 |
| ICMP | INCOMING + OUTGOING | ICMP/ICMPv6 | * |
SSH is restricted to a specific source IP.