Pangolin
Self-hosted reverse proxy and tunnelling solution
| Item | Detail |
|---|---|
| Gerbil version | 1.3.0 |
| Traefik version | 3.6 |
| VPS hostname | WTSCPVM01 |
| VPS IP | 152.53.226.118 |
| Install location | /root/ |
| Config location | /root/config/ |
| Compose file | /root/docker-compose.yml |
| License | Enterprise Edition (Personal Use) |
Pangolin replaces the Cloudflare Tunnel for services that require large file uploads. Cloudflare imposes a 100 MB maximum request size on tunnelled traffic. Pangolin has no such limit, which is why Immich video uploads route through it.
Architecture
Section titled “Architecture”Three containers run on the VPS managed via Docker Compose.
| Container | Image | Purpose |
|---|---|---|
| pangolin | fosrl/pangolin:ee-1.16.2 | Main application and API |
| gerbil | fosrl/gerbil:1.3.0 | WireGuard tunnel manager |
| traefik | traefik:v3.6 | Reverse proxy, TLS termination |
Traefik shares Gerbil’s network namespace (network_mode: service:gerbil). All inbound traffic on ports 80 and 443 enters through Gerbil and is routed by Traefik. IPv6 is disabled on the Docker network.
TrueNAS connects to Pangolin via a Newt client running as an Arcane project.
| Item | Detail |
|---|---|
| Newt image | fosrl/newt |
| Container name | pangolin |
| Arcane project | Pangolin |
Newt compose file at /app/data/projects/pangolin/compose.yaml:
services: newt: image: fosrl/newt container_name: pangolin restart: unless-stopped environment: - PANGOLIN_ENDPOINT=https://pangolin.wighttrash.uk - NEWT_ID=<newt-id> - NEWT_SECRET=<newt-secret>The NEWT_ID and NEWT_SECRET are generated by Pangolin when creating a site. If the site is deleted and recreated, new credentials are generated and the compose file must be updated.
Resources configured
Section titled “Resources configured”| Name | External URL | Internal Target | Status | Authentication | Notes |
|---|---|---|---|---|---|
| Immich | https://photos.wighttrash.uk | http://192.168.1.28:30041 | healthy | Not protected - Immich handles its own auth via Keycloak | Enable SSL must be off. DNS-only in Cloudflare - must not be proxied. |
| Jellyfin | https://media.wighttrash.uk | http://192.168.1.28:8096 | healthy | Not protected - Keycloak OIDC handles auth within Jellyfin | Proxied through Cloudflare. |
| OpenCloud | https://cloud.wighttrash.uk | http://192.168.1.28:9200 | healthy | Not protected at proxy - Keycloak OIDC handled by OpenCloud internally | Enable SSL must be off. PROXY_TLS=false in container. |
| Collabora | https://collabora.wighttrash.uk | http://192.168.1.28:9980 | healthy | Internal - accessed by OpenCloud only | ssl.enable=false, ssl.termination=true. No direct user access. |
| WOPI Server | https://wopiserver.wighttrash.uk | http://192.168.1.28:9300 | healthy | Internal - accessed by Collabora only | OpenCloud collaboration endpoint. Called by Collabora for WOPI. |
| Planka | https://planka.wighttrash.uk | http://192.168.1.28:3050 | healthy | Keycloak OIDC | Enable SSL must be off. |
In the Pangolin proxy settings for each resource, Enable SSL must be off. Both Immich and Jellyfin serve plain HTTP internally. Enabling SSL causes Traefik to attempt a TLS connection to the backend, which both services reject.
Authentication
Section titled “Authentication”Pangolin uses Keycloak as an external OIDC identity provider for dashboard login. Two accounts exist following a break-glass pattern.
| Account | Identity Provider | Role | Purpose |
|---|---|---|---|
| [email protected] | Internal | Owner | Break-glass - username/password + MFA |
| [email protected] | Keycloak | Admin | Day-to-day login via social |
Keycloak client settings
Section titled “Keycloak client settings”| Setting | Value |
|---|---|
| Client ID | pangolin |
| Realm | wighttrash |
| Valid redirect URI | https://pangolin.wighttrash.uk/auth/idp/1/oidc/callback |
| Post logout redirect URI | https://pangolin.wighttrash.uk |
| Client authentication | On (confidential client) |
Pangolin IdP configuration
Section titled “Pangolin IdP configuration”Configured at the server level under Admin - Identity Providers.
| Field | Value |
|---|---|
| Authorization URL | https://auth.wighttrash.uk/realms/wighttrash/protocol/openid-connect/auth |
| Token URL | https://auth.wighttrash.uk/realms/wighttrash/protocol/openid-connect/token |
| Scopes | openid profile email |
| Identifier Path | sub |
| Email Path | |
| Name Path | name |
| Auto Provision Users | On |
Newly provisioned users have no organisation or role by default. Assign them manually in Admin - All Users after their first login.
Security
Section titled “Security”Cloudflare Access
Section titled “Cloudflare Access”pangolin.wighttrash.uk is protected by two Cloudflare Access applications.
| Application | URL | Policy |
|---|---|---|
| Pangolin | pangolin.wighttrash.uk | Admin Only |
| Pangolin API Bypass | pangolin.wighttrash.uk/api/ | Bypass Everyone |
The bypass application allows Newt to make unauthenticated token requests to the API. Without it, Cloudflare Access intercepts the request and Newt fails to establish its tunnel.
| Record | Type | Proxied | Notes |
|---|---|---|---|
| pangolin.wighttrash.uk | A | Yes (orange cloud) | Pangolin admin dashboard |
| photos.wighttrash.uk | A | No (grey cloud) | Immich - must not be proxied |
| media.wighttrash.uk | A | Yes (orange cloud) | Jellyfin |
| auth.wighttrash.uk | A | Yes (orange cloud) | Keycloak |
photos.wighttrash.uk must remain DNS only. Cloudflare’s 100 MB limit would block large video uploads, which is the original reason Pangolin exists.
Common commands
Section titled “Common commands”# Full restart (always use down/up, never restart)cd /root && docker compose down && docker compose up -d
# Follow Traefik logsdocker compose logs traefik --follow
# Check ACME cert activitydocker compose logs traefik 2>&1 | grep -i acme
# Check all container statusdocker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
# Check all logsdocker compose logs --tail=50Always use docker compose down && docker compose up -d to restart. Never use docker compose restart - it cannot handle the Gerbil dependency ordering when Gerbil has exited, and if badger fails to load all Traefik routes that reference it fail.
Troubleshooting
Section titled “Troubleshooting”Traefik returning 502 for a resource. Confirm the resource is running on TrueNAS and that the Newt tunnel is active. Check Pangolin dashboard for tunnel status.
Newt not connecting. Check the Arcane logs for the Pangolin project. Confirm the NEWT_ID and NEWT_SECRET in the compose file match the current Pangolin site credentials. If the site was recreated in Pangolin, new credentials will have been generated.
ACME certificate not renewing. Check Traefik logs for DNS-01 challenge errors. Confirm the Cloudflare API token in /root/.env is valid and has Zone:Read and DNS:Edit permissions for wighttrash.uk.