Pangolin mit Docker installieren: Identity-aware Tunnel-Reverse-Proxy auf WireGuard-Basis
Pangolin ist die selbstgehostete Cloudflare-Tunnel-Alternative mit 21k+ Stars: Identity-aware Reverse Proxy auf WireGuard-Basis, der interne Dienste ohne Portfreigabe sicher nach außen bringt – mit Web-UI, RBAC und automatischem TLS über Traefik.

Wer interne Dienste – etwa Home Assistant, Nextcloud oder ein Firmen-Dashboard – sicher von außen erreichbar machen will, steht vor einer bekannten Herausforderung: Portweiterleitung am Router öffnet Angriffsfläche, Cloudflare Tunnel ist komfortabel aber proprietär. Pangolin löst dieses Problem als vollständig selbstgehostete Alternative: Der Identity-aware Reverse Proxy verbindet einen öffentlichen VPS mit internen Servern hinter NAT über WireGuard-Tunnel – ohne eine einzige Portfreigabe am Heimrouter. Das Ergebnis ist ein zentrales Zugangssystem mit Web-Dashboard, rollenbasierter Zugriffskontrolle (RBAC) und automatischem Let's-Encrypt-TLS. Mit Version 1.19.1, 21.100+ GitHub-Stars und 78 Releases (Stand Juni 2026) ist das Projekt von Fossorial produktionsreif und wird aktiv weiterentwickelt.
Voraussetzungen
- VPS oder Cloud-Server mit öffentlicher IPv4-Adresse und Linux (Ubuntu 22.04 oder 24.04 empfohlen)
- Docker Engine 24+ und Docker Compose v2 installiert – falls nicht vorhanden, folge der Anleitung Docker und Docker Compose auf Linux installieren
- Eigene Domain mit Zugriff auf die DNS-Einstellungen (A-Record auf Server-IP gesetzt)
- Ports offen in der VPS-Firewall: 80/tcp, 443/tcp, 51820/udp, 21820/udp
- Mindestens 512 MB RAM (empfohlen: 1 GB+), 1 vCPU, 5 GB freier Speicher
- Interner Host für den Newt-Client (Heimserver, NAS, Raspberry Pi o. ä.)
opensslundcurlauf dem VPS verfügbar
Schritt 1: Projektordner und Verzeichnisstruktur anlegen
Pangolin erwartet eine feste Verzeichnisstruktur unterhalb des Projektordners. Lege alle benötigten Ordner vorab an – fehlende Verzeichnisse führen sonst beim Start zu Berechtigungsfehlern.
mkdir -p /opt/pangolin/config/db
mkdir -p /opt/pangolin/config/letsencrypt
mkdir -p /opt/pangolin/config/traefik/logs
cd /opt/pangolinDie vollständige Verzeichnisstruktur sieht danach so aus:
/opt/pangolin/
├── compose.yaml
├── config/
│ ├── config.yml # Pangolin-Hauptkonfiguration (noch anzulegen)
│ ├── db/ # SQLite-Datenbank (automatisch erstellt)
│ ├── letsencrypt/ # ACME-Zertifikate (automatisch befüllt)
│ └── traefik/
│ ├── logs/ # Traefik Access-/Error-Logs
│ ├── traefik_config.yml # Traefik statische Konfiguration
│ └── dynamic_config.yml # Traefik dynamische RoutenVerifizieren: Prüfe die Ordnerstruktur mit find /opt/pangolin -type d. Alle Verzeichnisse aus der obigen Liste müssen vorhanden sein.
Schritt 2: Server-Secret generieren und config.yml anlegen
Pangolin verwendet keine klassischen Docker-Umgebungsvariablen für die Hauptkonfiguration. Alle Einstellungen stehen in config/config.yml. Das wichtigste Pflichtfeld ist server.secret – ein zufälliger Schlüssel, der alle Sessions absichert. Erzeuge ihn einmalig und ändere ihn danach nie wieder:
openssl rand -hex 32Notiere die Ausgabe (z. B. a3f8...) und trage sie in die folgende Konfigurationsdatei ein. Ersetze dabei alle Vorkommen von pangolin.example.com und example.com durch deine tatsächliche Domain sowie admin@example.com durch deine E-Mail-Adresse:
# /opt/pangolin/config/config.yml
app:
dashboard_url: "https://pangolin.example.com"
log_level: "info"
server:
secret: "HIER-openssl-rand-hex-32-Ausgabe-einfuegen"
internal_hostname: "pangolin"
session_cookie_name: "p_session_token"
trust_proxy: 1
cors:
origins: ["https://pangolin.example.com"]
gerbil:
base_endpoint: "pangolin.example.com"
start_port: 51820
clients_start_port: 21820
domains:
domain1:
base_domain: "example.com"
cert_resolver: "letsencrypt"
flags:
require_email_verification: false
disable_signup_without_invite: false
allow_raw_resources: trueWichtig: YAML verwendet ausschließlich Leerzeichen zur Einrückung, niemals Tabs. Die dashboard_url muss exakt mit dem Hostnamen übereinstimmen, über den du das Dashboard aufrufst – kein abschließender Schrägstrich.
Verifizieren: Prüfe die YAML-Syntax mit python3 -c "import yaml; yaml.safe_load(open('config/config.yml'))" && echo "YAML OK". Ausgabe muss YAML OK lauten.
Schritt 3: Traefik-Konfiguration anlegen
Traefik benötigt zwei Dateien: eine statische Hauptkonfiguration und eine dynamische Routen-Konfiguration. Die statische Konfiguration definiert Entry Points und den ACME-Resolver für Let's Encrypt:
# /opt/pangolin/config/traefik/traefik_config.yml
api:
dashboard: true
insecure: true
entryPoints:
web:
address: ":80"
websecure:
address: ":443"
providers:
file:
filename: /etc/traefik/dynamic_config.yml
certificatesResolvers:
letsencrypt:
acme:
email: admin@example.com
storage: /letsencrypt/acme.json
httpChallenge:
entryPoint: web
log:
filePath: /var/log/traefik/traefik.log
level: INFO
accessLog:
filePath: /var/log/traefik/access.logDie dynamische Konfiguration legt die Route zum Pangolin-Dashboard an:
# /opt/pangolin/config/traefik/dynamic_config.yml
http:
routers:
pangolin:
entryPoints: ["websecure"]
rule: "Host(`pangolin.example.com`)"
service: pangolin
tls:
certResolver: letsencrypt
services:
pangolin:
loadBalancer:
servers:
- url: "http://pangolin:3000"Verifizieren: Beide Dateien müssen vorhanden sein: ls -la /opt/pangolin/config/traefik/ zeigt traefik_config.yml, dynamic_config.yml und das Unterverzeichnis logs/.
Schritt 4: compose.yaml anlegen
Der Stack besteht aus drei eng verzahnten Containern. Traefik teilt den Netzwerk-Namespace mit Gerbil über network_mode: service:gerbil – dadurch läuft der gesamte externe HTTPS-Traffic durch den WireGuard-Container. Gerbil wiederum startet erst, wenn Pangolin gesund ist (condition: service_healthy). Diese Abhängigkeitskette ist kritisch; ohne sie kommt es zu Race Conditions beim Start.
# /opt/pangolin/compose.yaml
services:
pangolin:
image: fosrl/pangolin:latest
container_name: pangolin
restart: unless-stopped
volumes:
- ./config:/app/config
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3001/api/v1/"]
interval: 3s
retries: 5
start_period: 20s
timeout: 5s
deploy:
resources:
limits:
memory: 1g
reservations:
memory: 256m
networks:
- pangolin
gerbil:
image: fosrl/gerbil:latest
container_name: gerbil
restart: unless-stopped
depends_on:
pangolin:
condition: service_healthy
command:
- --reachableAt=http://pangolin:3001
- --generateAndSaveKeyTo=/var/config/key
- --remoteConfig=http://pangolin:3001/api/v1/gerbil/get-config
volumes:
- ./config/:/var/config
ports:
- "51820:51820/udp"
- "21820:21820/udp"
- "443:443"
- "80:80"
cap_add:
- NET_ADMIN
- SYS_MODULE
networks:
- pangolin
traefik:
image: traefik:v3.6
container_name: traefik
restart: unless-stopped
network_mode: service:gerbil
depends_on:
gerbil:
condition: service_started
volumes:
- ./config/traefik:/etc/traefik:ro
- ./config/letsencrypt:/letsencrypt
- ./config/traefik/logs:/var/log/traefik
networks:
pangolin:
driver: bridge
name: pangolin
enable_ipv6: trueBeachte: Das Volume ./config/traefik wird mit :ro (read-only) eingebunden, ./config/letsencrypt hingegen ohne :ro – Traefik muss dort die acme.json-Datei schreiben können.
Verifizieren: Prüfe die Compose-Syntax vor dem Start: docker compose config im Projektordner. Bei einem fehlerfreien Ergebnis erscheint die ausgegebene, normalisierte Konfiguration ohne Fehlermeldung.
Schritt 5: Stack starten und Ersteinrichtung abschließen
Starte alle drei Container im Hintergrund:
docker compose up -dDer Startvorgang dauert etwa 20–40 Sekunden, da Pangolin erst seinen Healthcheck bestehen muss, bevor Gerbil hochfährt. Verfolge den Fortschritt mit:
docker compose psErwartete Ausgabe nach erfolgreichem Start:
NAME IMAGE STATUS
pangolin fosrl/pangolin:latest Up (healthy)
gerbil fosrl/gerbil:latest Up
traefik traefik:v3.6 UpHole dir jetzt das One-Time-Setup-Token aus den Pangolin-Logs – es erscheint nur einmal beim ersten Start:
docker compose logs pangolin | grep -i tokenRufe anschließend im Browser die Ersteinrichtungs-Seite auf:
https://pangolin.example.com/auth/initial-setupTrage dort das Token sowie deine gewünschten Admin-Zugangsdaten ein. Nach dem Absenden landest du direkt im Pangolin-Dashboard.
Verifizieren: docker compose ps zeigt alle drei Container mit Status Up, Pangolin zusätzlich mit (healthy). Die URL https://pangolin.example.com öffnet im Browser das Login-Formular mit gültigem HTTPS-Zertifikat von Let's Encrypt.
Schritt 6: Newt-Client auf dem internen Host deployen
Der eigentliche Mehrwert von Pangolin liegt im Newt-Client: ein leichtgewichtiger Container, der auf dem internen Host (Heimserver, NAS, Raspberry Pi) läuft und aktiv eine ausgehende WireGuard-Verbindung zum Pangolin-Server aufbaut. Du musst dafür keinen einzigen Port am Heimrouter freigeben.
Lege im Pangolin-Dashboard zunächst einen neuen Site Connector an: Connectors → New Connector. Notiere die angezeigte Connector ID und das Connector Secret.
Erstelle auf dem internen Host eine compose.yaml für den Newt-Client:
# ~/newt/compose.yaml (auf dem internen Host)
services:
newt:
image: fosrl/newt:latest
container_name: newt
restart: unless-stopped
environment:
- PANGOLIN_ENDPOINT=https://pangolin.example.com
- NEWT_ID=deine-connector-id-aus-dem-dashboard
- NEWT_SECRET=dein-connector-secret-aus-dem-dashboard
network_mode: hostStarte den Newt-Client auf dem internen Host:
docker compose up -d
docker compose logs -f newtIm Pangolin-Dashboard sollte der Connector nach wenigen Sekunden als Online erscheinen. Du kannst jetzt im Dashboard Ressourcen anlegen – zum Beispiel einen internen Dienst auf Port 8123 (Home Assistant) – und dem Connector zuweisen.
Verifizieren: Im Pangolin-Dashboard unter Connectors zeigt der neu angelegte Connector den Status Online. Die Logs des Newt-Containers (docker compose logs newt) enthalten keine Fehlermeldungen wie connection refused oder timeout.
Schritt 7: Updates und Backups
Für Updates aller drei Container genügt der übliche Compose-Workflow. Eine regelmäßige Backup-Routine einzurichten ist Pflicht – alle persistenten Daten liegen im ./config-Verzeichnis.
# Update (im Projektordner /opt/pangolin)
docker compose pull
docker compose up -d
# Logs im Fehlerfall prüfen
docker compose logs -f
# Backup: gesamtes config-Verzeichnis sichern
tar -czf pangolin-backup-$(date +%Y%m%d).tar.gz /opt/pangolin/configÄndere server.secret in der config.yml niemals nach dem ersten Start – alle aktiven Sessions werden sonst invalidiert. Eine Backup-Strategie für das config-Verzeichnis findest du in der Anleitung 3-2-1-Backup-Strategie umsetzen.
Verifizieren: Nach docker compose pull && docker compose up -d zeigt docker compose ps alle Container mit aktualisierten Image-IDs und Status Up (healthy) für Pangolin.
Eckdaten auf einen Blick
| Eigenschaft | Wert |
|---|---|
| Image (empfohlen) | fosrl/pangolin:latest (SQLite, Community Edition) |
| Varianten | latest, postgresql-latest, ee-latest, ee-postgresql-latest |
| Aktuelle Version | 1.19.1 (Juni 2026) |
| Lizenz | AGPL-3.0 (CE kostenlos bis 100 k USD Jahresumsatz) |
| Architektur | amd64, arm64 |
| RAM (min/empfohlen) | 512 MB / 1 GB+ |
| Port | Protokoll | Funktion | Extern? |
|---|---|---|---|
| 80 | tcp | HTTP-Eingang (HTTPS-Redirect) | ja |
| 443 | tcp | HTTPS/TLS (Traefik) | ja |
| 51820 | udp | WireGuard Site-Connector | ja |
| 21820 | udp | Newt-Client Relay/Hole-Punch | ja |
| 3000–3003 | tcp | Pangolin intern (nie am Host exponieren) | nein |
| Volume (Host) | Container-Pfad | Inhalt |
|---|---|---|
| ./config | /app/config | SQLite-DB, config.yml, Logs (Pangolin) |
| ./config/ | /var/config | WireGuard-Schlüssel (Gerbil) |
| ./config/traefik | /etc/traefik:ro | Traefik-Konfiguration (read-only) |
| ./config/letsencrypt | /letsencrypt | ACME-Zertifikate (schreibbar!) |
| ./config/traefik/logs | /var/log/traefik | Access- und Error-Logs |
Troubleshooting / Typische Fehler
- „failed to create wireguard interface" – Gerbil fehlen die Linux-Capabilities. Prüfe, ob
cap_add: [NET_ADMIN, SYS_MODULE]in dercompose.yamlvorhanden ist. Auf manchen Cloud-VMs (z. B. OpenVZ-Basis) muss das WireGuard-Kernelmodul zusätzlich auf dem Host geladen sein:modprobe wireguard. - „failed to parse config" in den Pangolin-Logs –
config.ymlenthält einen YAML-Syntaxfehler, häufig durch Tabs statt Leerzeichen. Validiere mitpython3 -c "import yaml; yaml.safe_load(open('config/config.yml'))". - HTTPS-Verbindungen schlagen fehl / kein Zertifikat – Traefik ist nicht über
network_mode: service:gerbilmit Gerbil verbunden. Prüfe diecompose.yaml. Außerdem muss Port 80/tcp für die HTTP-Challenge offen sein. - CORS-Fehler im Browser –
app.dashboard_urlinconfig.ymlstimmt nicht exakt mit dem aufgerufenen Hostnamen überein. Kein abschließender Schrägstrich, korrekte Domain eintragen, Container neu starten. - One-Time-Setup-Token nicht mehr in den Logs – Das Token erscheint nur einmal beim ersten Start. Lösung:
docker compose down && docker compose up -d, danach sofortdocker compose logs pangolin | grep -i tokenausführen. - Newt-Client meldet „connection timeout" – Port 51820/udp oder 21820/udp ist in der VPS-Firewall (UFW, AWS Security Group, Hetzner Firewall) nicht freigegeben. UDP-Ports werden von Firewalls oft vergessen. Prüfe:
ufw statusbzw. die Cloud-Konsole. - Traefik kann acme.json nicht schreiben – Das Volume
./config/letsencryptwurde versehentlich mit:rogemountet. Entferne das Flag und starte Traefik neu. - Gerbil startet, meldet aber „connection refused" – Pangolin war beim Gerbil-Start noch nicht gesund. Stelle sicher, dass der Healthcheck korrekt konfiguriert ist und
depends_on.pangolin.condition: service_healthygesetzt ist.
Häufige Fragen
Brauche ich wirklich eine eigene Domain?
Ja, zwingend. Let's Encrypt stellt keine TLS-Zertifikate für IP-Adressen aus, und Browser-Cookies sowie CORS-Prüfungen setzen einen Hostnamen voraus. Du benötigst mindestens einen A-Record, der auf die öffentliche IP deines VPS zeigt. Setze den DNS-Eintrag, warte bis die TTL abgelaufen ist, und starte Pangolin erst dann.
Funktioniert Pangolin ohne Portweiterleitung am Heimrouter?
Ja – das ist der eigentliche Hauptanwendungsfall. Der Newt-Client auf dem internen Host baut eine ausgehende WireGuard-Verbindung zum öffentlichen Pangolin-Server auf. Am Heimrouter oder in der Firewall des internen Netzes muss kein Port geöffnet werden.
Welche Image-Variante soll ich nehmen?
fosrl/pangolin:latest (SQLite, Community Edition) ist für den Einstieg richtig. SQLite reicht für die überwiegende Mehrheit der Self-Hosting-Szenarien. Die PostgreSQL-Variante lohnt sich nur, wenn bereits PostgreSQL-Infrastruktur vorhanden ist oder sehr hohes Traffic-Aufkommen erwartet wird. Die Enterprise Edition (ee-*) ist für Unternehmen mit kommerziellem Support gedacht.
Wie verbinde ich einen internen Dienst, z. B. Home Assistant auf Port 8123?
Deploye den Newt-Client auf dem internen Host (Schritt 6). Lege dann im Pangolin-Dashboard unter Resources → New Resource einen Eintrag mit Zielhost localhost:8123 an und weise ihn dem Connector zu. Pangolin erstellt automatisch eine Subdomain und beschafft ein TLS-Zertifikat – kein Port am Router nötig.
Kann ich Pangolin neben einer bestehenden Traefik-Instanz betreiben?
Ja, aber mit Vorsicht: Pangolin bringt eine eigene Traefik-Instanz mit. Entweder du nutzt Pangolin als einzigen Entry Point und konfigurierst alle Dienste als Pangolin-Ressourcen, oder du lässt Pangolin auf alternativen Ports (z. B. 8443/tcp statt 443) laufen und schaltest deinen vorhandenen Reverse Proxy davor. Wie du Traefik generell als Docker-Reverse-Proxy einsetzt, zeigt die Anleitung Traefik als Docker-Reverse-Proxy mit automatischem HTTPS.
Ist Pangolin produktionsreif?
Mit Version 1.19.1, 78 Releases und aktiver Entwicklung durch Fossorial: ja. Die Community Edition unter AGPL-3.0 ist kostenlos für Privatnutzer und Unternehmen unter 100.000 USD Jahresumsatz. Für kritische Umgebungen empfiehlt sich die PostgreSQL-Variante und ein regelmäßiges Backup des gesamten ./config-Verzeichnisses.
Was passiert, wenn ich server.secret ändere?
Alle aktiven Sessions werden sofort invalidiert – alle eingeloggten Benutzer werden ausgeloggt, und Ressourcen-Zugriffstoken verlieren ihre Gültigkeit. Das Secret darf nach dem ersten Start unter keinen Umständen geändert werden. Sichere es zusammen mit dem Backup des config-Verzeichnisses an einem sicheren Ort.
Fazit
Pangolin schließt eine echte Lücke im Self-Hosting-Ökosystem: Es liefert das, was Cloudflare Tunnel in der kostenlosen Stufe bietet – sicherer externer Zugriff ohne Portfreigabe – als vollständig selbstgehostete, AGPL-lizenzierte Lösung. Der Dreier-Stack aus Pangolin, Gerbil und Traefik ist nach einmaligem Einrichten wartungsarm, und der Newt-Client macht den Anschluss interner Dienste zur Sache von wenigen Minuten. Der einzige nicht verhandelbare Einstiegspreis: ein öffentlicher VPS und eine eigene Domain. Wer beides hat, bekommt mit Pangolin ein professionelles Zero-Trust-Zugangssystem für den eigenen Stack – inklusive RBAC, Einladungssystem und automatischem TLS. Wie du deinen VPS dabei grundsätzlich absicherst, erklärt die Anleitung VPS absichern und härten: UFW, SSH-Keys und Fail2Ban.
Weiterführende Anleitungen und Quellen
- Docker und Docker Compose auf Linux installieren (Ubuntu/Debian): die Self-Hosting-Grundlage
- Traefik als Docker-Reverse-Proxy mit automatischem HTTPS einrichten
- VPS absichern und härten: UFW, SSH-Keys und Fail2Ban
- 3-2-1-Backup-Strategie umsetzen
- WireGuard-VPN für Homeoffice und Standortvernetzung einrichten
- Headscale selbst hosten: Tailscale-Mesh-VPN ohne Cloud-Abhängigkeit für KMU
Offizielle Dokumentation und Quellen: Pangolin Docs – Docker Compose Setup · GitHub: fosrl/pangolin · Docker Hub: fosrl/pangolin