Zum Hauptinhalt springen
S-EDV news
← Alle Anleitungen
📘 Anleitung Server & Netzwerk 04.08.2026 · 11 min Lesezeit

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.

Geprüft am 22.10.2026 · für Pangolin 1.25.1

WerbelinksMit * markierte Links sind Werbelinks: Bei einem Kauf erhalten wir eine Provision, der Preis bleibt gleich. Als Amazon-Partner verdiene ich an qualifizierten Verkäufen. Mehr dazu

Zwei Serverschränke am Wasser, verbunden durch leuchtende Lichtfasern mit Schutzschilden, Berge im Abendlicht

Interne Dienste wie Home Assistant oder Nextcloud sollen ohne Portfreigabe am Router von außen erreichbar sein. Pangolin ist die selbst gehostete Alternative: Der identitätsbasierte Reverse Proxy (Identity-aware Proxy, prüft vor jedem Zugriff den angemeldeten Benutzer) verbindet einen öffentlichen VPS über WireGuard-Tunnel mit internen Servern hinter NAT. Dazu kommen Web-Dashboard, rollenbasierte Zugriffskontrolle (RBAC) und Let's-Encrypt-Zertifikate. Die Anleitung beschreibt die manuelle Installation mit Docker Compose nach der offiziellen Dokumentation (Stand Oktober 2026, Pangolin 1.25.1).

Voraussetzungen

  1. VPS oder Cloud-Server mit öffentlicher IPv4-Adresse und Linux (Ubuntu 22.04 oder 24.04 empfohlen)
  2. Docker Engine 24+ und Docker Compose v2, siehe Docker und Docker Compose auf Linux installieren
  3. Eigene Domain mit Zugriff auf die DNS-Einstellungen (A-Record auf Server-IP gesetzt)
  4. Ports offen in der VPS-Firewall: 80/tcp, 443/tcp, 51820/udp, 21820/udp
  5. Mindestens 512 MB RAM (empfohlen: 1 GB+), 1 vCPU, 5 GB freier Speicher, x86_64 oder arm64
  6. Ports 80 und 443 dürfen auf dem VPS nicht von einem anderen Reverse Proxy belegt sein
  7. Interner Host für den Newt-Client (Heimserver, NAS, Raspberry Pi o. ä.)
  8. openssl und curl auf dem VPS verfügbar

Schritt 1: Projektordner und Verzeichnisstruktur anlegen

Pangolin erwartet eine feste Verzeichnisstruktur. Legen Sie die Ordner vorab an:

mkdir -p /opt/pangolin/config/db
mkdir -p /opt/pangolin/config/letsencrypt
mkdir -p /opt/pangolin/config/traefik/logs
cd /opt/pangolin

Zielstruktur; config/key legt Gerbil beim ersten Start an:

/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 Routen

Verifizieren: Prüfen Sie 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

Die Einstellungen stehen in config/config.yml. Pflichtfeld ist server.secret; Pangolin verschlüsselt damit sensible Daten in der Datenbank. Erzeugen Sie ihn einmalig:

openssl rand -hex 32

Tragen Sie die Ausgabe ein und ersetzen Sie pangolin.example.com (Dashboard-Hostname) und example.com (Basisdomain) durch Ihre Werte:

# /opt/pangolin/config/config.yml
gerbil:
  start_port: 51820
  base_endpoint: "pangolin.example.com"

app:
  dashboard_url: "https://pangolin.example.com"
  log_level: "info"

domains:
  domain1:
    base_domain: "example.com"

server:
  secret: "HIER-openssl-rand-hex-32-Ausgabe-einfuegen"
  cors:
    origins: ["https://pangolin.example.com"]
    methods: ["GET", "POST", "PUT", "DELETE", "PATCH"]
    allowed_headers: ["X-CSRF-Token", "Content-Type"]
    credentials: false

flags:
  require_email_verification: false
  disable_signup_without_invite: true
  disable_user_create_org: false
  allow_raw_resources: true

YAML erlaubt nur Leerzeichen zur Einrückung. Die dashboard_url entspricht exakt dem Hostnamen des Dashboards, ohne abschließenden Schrägstrich. disable_signup_without_invite: true verhindert, dass sich Fremde selbst registrieren.

Verifizieren: Prüfen Sie 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 braucht eine statische Konfiguration (Entry Points, Let's Encrypt, das Pangolin-Plugin Badger für die Anmeldeprüfung und den HTTP-Provider, über den Pangolin die Routen der Ressourcen liefert) und eine dynamische Konfiguration für das Dashboard. Ersetzen Sie die E-Mail-Adresse:

# /opt/pangolin/config/traefik/traefik_config.yml
api:
  insecure: true
  dashboard: true

providers:
  http:
    endpoint: "http://pangolin:3001/api/v1/traefik-config"
    pollInterval: "5s"
  file:
    filename: "/etc/traefik/dynamic_config.yml"

experimental:
  plugins:
    badger:
      moduleName: "github.com/fosrl/badger"
      version: "v1.7.0" # aktuelle Version: github.com/fosrl/badger

log:
  level: "INFO"
  format: "common"
  maxSize: 100
  maxBackups: 3
  maxAge: 3
  compress: true

certificatesResolvers:
  letsencrypt:
    acme:
      httpChallenge:
        entryPoint: web
      email: "admin@example.com" # ERSETZEN
      storage: "/letsencrypt/acme.json"
      caServer: "https://acme-v02.api.letsencrypt.org/directory"

entryPoints:
  web:
    address: ":80"
  websecure:
    address: ":443"
    transport:
      respondingTimeouts:
        readTimeout: "30m"
    http:
      tls:
        certResolver: "letsencrypt"
      encodedCharacters:
        allowEncodedSlash: true
        allowEncodedQuestionMark: true

serversTransport:
  insecureSkipVerify: true

ping:
  entryPoint: "web"

Die dynamische Konfiguration leitet die Weboberfläche an Port 3002 und die API an Port 3000 von Pangolin weiter. Ersetzen Sie den Hostnamen an allen vier Stellen:

# /opt/pangolin/config/traefik/dynamic_config.yml
http:
  middlewares:
    badger:
      plugin:
        badger:
          disableForwardAuth: true
    redirect-to-https:
      redirectScheme:
        scheme: https

  routers:
    main-app-router-redirect:
      rule: "Host(`pangolin.example.com`)" # ERSETZEN
      service: next-service
      entryPoints:
        - web
      middlewares:
        - redirect-to-https
        - badger
    next-router:
      rule: "Host(`pangolin.example.com`) && !PathPrefix(`/api/v1`)" # ERSETZEN
      service: next-service
      entryPoints:
        - websecure
      middlewares:
        - badger
      tls:
        certResolver: letsencrypt
    api-router:
      rule: "Host(`pangolin.example.com`) && PathPrefix(`/api/v1`)" # ERSETZEN
      service: api-service
      entryPoints:
        - websecure
      middlewares:
        - badger
      tls:
        certResolver: letsencrypt
    ws-router:
      rule: "Host(`pangolin.example.com`)" # ERSETZEN
      service: api-service
      entryPoints:
        - websecure
      middlewares:
        - badger
      tls:
        certResolver: letsencrypt

  services:
    next-service:
      loadBalancer:
        servers:
          - url: "http://pangolin:3002" # Weboberfläche
    api-service:
      loadBalancer:
        servers:
          - url: "http://pangolin:3000" # API

tcp:
  serversTransports:
    pp-transport-v1:
      proxyProtocol:
        version: 1
    pp-transport-v2:
      proxyProtocol:
        version: 2

Verifizieren: ls -la /opt/pangolin/config/traefik/ zeigt traefik_config.yml, dynamic_config.yml und logs/; grep -rn example.com /opt/pangolin/config liefert keine Treffer mehr.

Schritt 4: compose.yaml anlegen

Traefik teilt über network_mode: service:gerbil den Netzwerk-Namespace mit Gerbil, der gesamte externe Verkehr läuft also durch den WireGuard-Container. Gerbil und Traefik starten erst, wenn Pangolin gesund ist. Pangolin ist auf eine Version festgeschrieben, damit Updates bewusst erfolgen.

# /opt/pangolin/compose.yaml
name: pangolin
services:
  pangolin:
    image: docker.io/fosrl/pangolin:1.25.1
    container_name: pangolin
    restart: unless-stopped
    volumes:
      - ./config:/app/config
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3001/api/v1/"]
      interval: "10s"
      timeout: "10s"
      retries: 15

  gerbil:
    image: docker.io/fosrl/gerbil:latest
    container_name: gerbil
    restart: unless-stopped
    depends_on:
      pangolin:
        condition: service_healthy
    command:
      - --reachableAt=http://gerbil:3004
      - --generateAndSaveKeyTo=/var/config/key
      - --remoteConfig=http://pangolin:3001/api/v1/
    volumes:
      - ./config/:/var/config
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    ports:
      - 51820:51820/udp
      - 21820:21820/udp
      - 443:443
      - 80:80

  traefik:
    image: docker.io/traefik:v3.7
    container_name: traefik
    restart: unless-stopped
    network_mode: service:gerbil
    depends_on:
      pangolin:
        condition: service_healthy
    command:
      - --configFile=/etc/traefik/traefik_config.yml
    volumes:
      - ./config/traefik:/etc/traefik:ro
      - ./config/letsencrypt:/letsencrypt
      - ./config/traefik/logs:/var/log/traefik

networks:
  default:
    driver: bridge
    name: pangolin
    # enable_ipv6: true

./config/traefik ist schreibgeschützt (:ro) eingebunden, ./config/letsencrypt nicht, denn Traefik schreibt dort die acme.json.

Verifizieren: docker compose config --quiet im Projektordner meldet keinen Fehler.

Schritt 5: Stack starten und Ersteinrichtung abschließen

Starten Sie die Container im Hintergrund:

docker compose up -d

Gerbil und Traefik warten, bis Pangolin seinen Healthcheck besteht. Den Fortschritt zeigt:

docker compose ps

Erwartete Ausgabe:

NAME        IMAGE                    STATUS
pangolin    fosrl/pangolin:1.25.1    Up (healthy)
gerbil      fosrl/gerbil:latest      Up
traefik     traefik:v3.7             Up

Lesen Sie das einmalige Setup-Token aus dem Pangolin-Log:

docker compose logs pangolin | grep -i token

Tragen Sie es mit den Administrator-Zugangsdaten auf der Einrichtungsseite ein:

https://pangolin.example.com/auth/initial-setup

Verifizieren: docker compose ps zeigt alle drei Container mit Up, Pangolin zusätzlich (healthy). config/db/db.sqlite und config/key existieren. https://pangolin.example.com öffnet das Login-Formular mit gültigem Let's-Encrypt-Zertifikat.

Schritt 6: Newt-Client auf dem internen Host deployen

Newt läuft auf dem internen Host (Heimserver, NAS, Raspberry Pi) und baut eine ausgehende WireGuard-Verbindung zum Pangolin-Server auf; am Heimrouter geben Sie keinen Port frei. Für neue Standorte empfiehlt Pangolin inzwischen die Pangolin CLI; Newt wird weiter gepflegt.

Legen Sie im Dashboard unter Sites einen neuen Standort mit Newt an und notieren Sie ID und Secret. Erstellen Sie dann auf dem internen Host eine compose.yaml:

# ~/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=ID-aus-dem-Dashboard
      - NEWT_SECRET=Secret-aus-dem-Dashboard
    network_mode: host

Starten Sie Newt:

docker compose up -d
docker compose logs -f newt

Danach legen Sie im Dashboard Ressourcen an, etwa einen internen Dienst auf Port 8123 (Home Assistant), und weisen sie dem Standort zu.

Verifizieren: Im Dashboard unter Sites zeigt der neue Standort 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 ein Update passen Sie den Versions-Tag von Pangolin in der compose.yaml an und lesen vorher die Release Notes. Sichern Sie ./config vor jedem Update, denn die Datenbank wird beim Start migriert und ein Downgrade ist laut Hersteller nicht ohne Weiteres möglich. Alle persistenten Daten liegen in ./config. Ab 1.24 setzen private Exit-Node-Ressourcen auf den Standorten Newt ab Version 1.18.0 voraus; aktualisieren Sie Newt daher vor der Nutzung dieser Funktion.

Version 1.25 bringt Weiterleitungen (Redirects), mTLS als Anmeldemethode für öffentliche Ressourcen, eine wählbare Lastverteilung sowie das Neuerzeugen von Zugangsdaten für Standorte und Clients auch in der Community Edition; 1.25.1 behebt Relay-Probleme aktualisierter Clients. Laut Release Notes funktionieren alle Lastverteilungsoptionen erst ab Traefik 3.6, die Compose-Datei oben nutzt bereits traefik:v3.7. Für dauerhafte Weiterleitungen nennt das Projekt Badger v1.8.0, rät aber ausdrücklich, vorerst bei v1.7.0 zu bleiben, weil v1.8.0 die Integritätsprüfung für Traefik-Plugins nicht besteht und Traefik das Plugin dann abschaltet. Lassen Sie version: "v1.7.0" in der traefik_config.yml deshalb unverändert. Das Update von 1.24.0 auf 1.25.1 lief am 22.10.2026 auf einem Testsystem mit genau diesem Ablauf: Pangolin spielte die Migration 1.25.0 automatisch ein und meldete All migrations completed successfully, der Container war wieder healthy, Traefik lud das Plugin Badger v1.7.0, die Anmeldung des zuvor eingerichteten Administrators funktionierte (HTTP 200), ein falsches Passwort wurde mit 401 abgelehnt. Ohne öffentliche Domain blieb acme.json im Test leer, was Pangolin mit einer Warnung acmeCertSync: could not parse quittiert; mit ausgestelltem Zertifikat entfällt die Meldung.

# 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

Ändern Sie server.secret nicht direkt in der config.yml; verschlüsselte Daten wären sonst unlesbar. Zum Wechsel dient docker exec -it pangolin pangctl rotate-server-secret. Eine Backup-Strategie beschreibt die 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

EigenschaftWert
Image (empfohlen)fosrl/pangolin:latest (SQLite, Community Edition)
Variantenlatest, postgresql-latest, ee-latest, ee-postgresql-latest
Aktuelle Version1.25.1 (21. Oktober 2026)
LizenzCommunity Edition AGPL-3.0; Enterprise Edition kommerziell, kostenlos privat und bis 100.000 USD Jahresumsatz
Architekturamd64, arm64
RAM (min/empfohlen)512 MB / 1 GB+
PortProtokollFunktionExtern?
80tcpHTTP-Eingang (HTTPS-Redirect)ja
443tcpHTTPS/TLS (Traefik)ja
51820udpWireGuard Site-Connectorja
21820udpNewt-Client Relay/Hole-Punchja
3000–3002tcpPangolin intern: API, interne API, Weboberfläche (nie am Host exponieren)nein
Volume (Host)Container-PfadInhalt
./config/app/configSQLite-DB, config.yml, Logs (Pangolin)
./config//var/configWireGuard-Schlüssel (Gerbil)
./config/traefik/etc/traefik:roTraefik-Konfiguration (read-only)
./config/letsencrypt/letsencryptACME-Zertifikate (schreibbar!)
./config/traefik/logs/var/log/traefikAccess- und Error-Logs

Troubleshooting / Typische Fehler

  1. „failed to create wireguard interface“: Gerbil fehlen die Linux-Capabilities. Prüfen Sie, ob cap_add: [NET_ADMIN, SYS_MODULE] in der compose.yaml vorhanden ist. Auf manchen Cloud-VMs (z. B. OpenVZ-Basis) muss das WireGuard-Kernelmodul zusätzlich auf dem Host geladen sein: modprobe wireguard.
  2. „failed to parse config“ im Pangolin-Log: config.yml enthält einen YAML-Fehler, häufig Tabs statt Leerzeichen. Prüfen Sie mit python3 -c "import yaml; yaml.safe_load(open('config/config.yml'))".
  3. HTTPS scheitert oder kein Zertifikat: Traefik hängt nicht per network_mode: service:gerbil an Gerbil, lädt ohne --configFile seine Konfiguration nicht, oder Port 80/tcp ist für die HTTP-Challenge gesperrt. docker compose logs traefik zeigt die Ursache.
  4. CORS-Fehler im Browser: app.dashboard_url oder server.cors.origins weicht vom aufgerufenen Hostnamen ab. Korrigieren und docker compose restart pangolin ausführen.
  5. Setup-Token nicht mehr im Log: Das Token steht nur im Log des ersten Starts. Starten Sie Pangolin mit docker compose restart pangolin neu und prüfen Sie sofort docker compose logs pangolin | grep -i token.
  6. Newt meldet „connection timeout“: Port 51820/udp oder 21820/udp ist in der VPS-Firewall (UFW, Security Group des Anbieters) nicht freigegeben. Prüfen Sie ufw status bzw. die Cloud-Konsole.
  7. Traefik kann acme.json nicht schreiben: ./config/letsencrypt ist mit :ro eingebunden. Flag entfernen, Traefik neu starten.
  8. Gerbil meldet „connection refused“: Pangolin war beim Start noch nicht gesund. Prüfen Sie Healthcheck und depends_on.pangolin.condition: service_healthy.

Häufige Fragen

Brauche ich wirklich eine eigene Domain?

Ja. Cookies, CORS und die Zertifikate setzen einen Hostnamen voraus. Sie brauchen mindestens einen A-Record auf die öffentliche IP des VPS, für Ressourcen zusätzlich deren Subdomains. Starten Sie Pangolin erst, wenn der DNS-Eintrag auflöst.

Funktioniert Pangolin ohne Portweiterleitung am Heimrouter?

Ja, das ist der Hauptanwendungsfall. Newt baut eine ausgehende WireGuard-Verbindung zum Pangolin-Server auf; im internen Netz öffnen Sie keinen Port.

Welche Image-Variante soll ich nehmen?

Die Standardvariante fosrl/pangolin:<version> (SQLite, Community Edition) reicht für die meisten Installationen. Die PostgreSQL-Variante lohnt sich bei vorhandener PostgreSQL-Infrastruktur oder hoher Last. Die Enterprise Edition (ee-*) enthält Zusatzfunktionen unter kommerzieller Lizenz.

Wie verbinde ich einen internen Dienst, z. B. Home Assistant auf Port 8123?

Installieren Sie Newt auf dem internen Host (Schritt 6). Legen Sie dann unter Resources eine Ressource mit Ziel localhost:8123 an und weisen Sie sie dem Standort zu. Pangolin richtet die Subdomain ein und beschafft das Zertifikat.

Kann ich Pangolin neben einer bestehenden Traefik-Instanz betreiben?

Ja, mit Einschränkungen: Pangolin bringt eine eigene Traefik-Instanz mit. Nutzen Sie Pangolin als einzigen Einstiegspunkt, oder legen Sie es auf andere Ports hinter den vorhandenen Proxy. Traefik allgemein erklärt die Anleitung Traefik als Docker-Reverse-Proxy mit automatischem HTTPS.

Ist Pangolin produktionsreif?

Das Projekt wird aktiv entwickelt (Version 1.25.1, Oktober 2026). Die Community Edition steht unter AGPL-3.0 und ist frei nutzbar; die Umsatzgrenze von 100.000 USD betrifft nur die kostenlose Nutzung der Enterprise Edition.

Was passiert, wenn ich server.secret ändere?

Mit dem Secret verschlüsselt Pangolin unter anderem OIDC-Zugangsdaten; eine Änderung nur in der config.yml macht sie unlesbar. Wechseln Sie es deshalb ausschließlich mit docker exec -it pangolin pangctl rotate-server-secret --old-secret "alt" --new-secret "neu".

Fazit

Pangolin bietet externen Zugriff auf interne Dienste ohne Portfreigabe, vergleichbar mit Cloudflare Tunnel, aber vollständig selbst gehostet. Voraussetzung sind ein öffentlicher VPS und eine eigene Domain. Die Grundabsicherung des VPS beschreibt die Anleitung VPS absichern und härten: UFW, SSH-Keys und Fail2Ban.

Weiterführende Anleitungen und Quellen

  1. Docker und Docker Compose auf Linux installieren (Ubuntu/Debian): die Self-Hosting-Grundlage
  2. Traefik als Docker-Reverse-Proxy mit automatischem HTTPS einrichten
  3. VPS absichern und härten: UFW, SSH-Keys und Fail2Ban
  4. 3-2-1-Backup-Strategie umsetzen
  5. WireGuard-VPN für Homeoffice und Standortvernetzung einrichten
  6. 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