Skip to main content

NPM Docker Setup mit NetBird

Diese Anleitung beschreibt die Einrichtung von Nginx Proxy Manager (NPM) in Docker auf sowohl dem externen VPS als auch dem Heimserver, verbunden über einen sicheren NetBird-Tunnel. NPM bietet eine benutzerfreundliche Web-Oberfläche zur Verwaltung von Reverse Proxies und SSL-Zertifikaten.

Anpassbare Werte in dieser Anleitung:

  • luna → Dein Benutzername
  • 226 → Dein SSH-Port
  • 100.64.0.1 → NetBird-IP des Heimservers
  • 100.64.0.2 → NetBird-IP des VPS
  • deine-domain.de → Deine Domain

Architektur-Überblick

┌─────────────────────────────────────────────────────────────────────────────┐
│                                 INTERNET                                     │
│                                     │                                        │
│                                     ▼                                        │
│                          ┌───────────────────┐                              │
│                          │       VPS         │                              │
│                          │   (Hetzner etc.)  │                              │
│                          │                   │                              │
│                          │  ┌─────────────┐  │                              │
│                          │  │   Docker    │  │                              │
│                          │  │  ┌───────┐  │  │                              │
│            Port 80/443 ──┼──┼─►│  NPM  │  │  │ ← SSL-Terminierung          │
│                          │  │  └───┬───┘  │  │                              │
│                          │  └─────┼───────┘  │                              │
│                          │        │          │                              │
│                          │  ┌─────▼───────┐  │                              │
│                          │  │  NetBird    │  │                              │
│                          │  │ 100.64.0.2  │  │                              │
│                          │  └─────┬───────┘  │                              │
│                          └────────┼──────────┘                              │
│                                   │                                          │
│                     ══════════════╪══════════════                           │
│                      Verschlüsselter NetBird-Tunnel                         │
│                     ══════════════╪══════════════                           │
│                                   │                                          │
│  ┌────────────────────────────────┼─────────────────────────────────────┐   │
│  │                           HEIMNETZ                                    │   │
│  │                                │                                      │   │
│  │                     ┌──────────▼──────────┐                          │   │
│  │                     │     Heimserver      │                          │   │
│  │                     │                     │                          │   │
│  │                     │   ┌─────────────┐   │                          │   │
│  │                     │   │  NetBird    │   │                          │   │
│  │                     │   │ 100.64.0.1  │   │                          │   │
│  │                     │   └─────┬───────┘   │                          │   │
│  │                     │         │           │                          │   │
│  │                     │   ┌─────▼───────┐   │                          │   │
│  │                     │   │   Docker    │   │                          │   │
│  │                     │   │             │   │                          │   │
│  │                     │   │ ┌─────────┐ │   │                          │   │
│  │                     │   │ │NPM (opt)│ │   │ ← Lokale Verwaltung      │   │
│  │                     │   │ └────┬────┘ │   │                          │   │
│  │                     │   │      │      │   │                          │   │
│  │                     │   │ ┌────▼────┐ │   │                          │   │
│  │                     │   │ │ Dienste │ │   │                          │   │
│  │                     │   │ │Wiki,Git,│ │   │                          │   │
│  │                     │   │ │Vaultw...│ │   │                          │   │
│  │                     │   │ └─────────┘ │   │                          │   │
│  │                     │   └─────────────┘   │                          │   │
│  │                     └─────────────────────┘                          │   │
│  └──────────────────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────────────────┘

Zwei Setup-Varianten

Variante Beschreibung Empfohlen für
A: NPM nur auf VPS VPS hat NPM, leitet direkt zu Heimserver-Diensten Einfaches Setup, wenige Dienste
B: NPM auf beiden VPS-NPM → Heimserver-NPM → Dienste Viele Dienste, lokale Verwaltung gewünscht

Teil 1: Voraussetzungen

Docker & Docker Compose installieren

Auf beiden Systemen (VPS und Heimserver) ausführen:

# Docker installieren
curl -fsSL https://get.docker.com | sudo sh

# User zur Docker-Gruppe hinzufügen (logout/login nötig)
sudo usermod -aG docker $USER

# Docker Compose ist bei aktuellen Docker-Versionen integriert
docker compose version

NetBird installieren

Auf beiden Systemen:

# NetBird installieren
curl -fsSL https://pkgs.netbird.io/install.sh | sudo sh

# Mit Account verbinden
sudo netbird up --setup-key DEIN-SETUP-KEY

# Status prüfen
sudo netbird status

Wichtig: Notiere die NetBird-IPs beider Systeme (z.B. 100.64.0.1 für Heimserver, 100.64.0.2 für VPS).


Teil 2: Variante A – NPM nur auf VPS

Einfachste Variante: NPM läuft nur auf dem VPS und leitet Traffic direkt an die Dienste auf dem Heimserver weiter.

NPM auf dem VPS einrichten

# Verzeichnis erstellen
mkdir -p ~/nginx-proxy-manager && cd ~/nginx-proxy-manager

# Docker Compose Datei erstellen
nano docker-compose.yml
version: '3.8'

services:
  npm:
    image: 'jc21/nginx-proxy-manager:latest'
    container_name: nginx-proxy-manager
    restart: unless-stopped
    ports:
      - '80:80'                         # HTTP (öffentlich)
      - '443:443'                       # HTTPS (öffentlich)
      - '127.0.0.1:81:81'               # Admin-UI (nur localhost)
    volumes:
      - ./data:/data
      - ./letsencrypt:/etc/letsencrypt
    environment:
      - TZ=Europe/Berlin
    networks:
      - proxy
    # Wichtig: NetBird-Netzwerk muss erreichbar sein
    extra_hosts:
      - "heimserver:100.64.0.1"         # ← Heimserver NetBird-IP anpassen

networks:
  proxy:
    name: proxy
    driver: bridge
# Container starten
docker compose up -d

# Logs prüfen
docker compose logs -f

Zugang zur Admin-Oberfläche

Da Port 81 nur auf localhost hört, Zugriff via SSH-Tunnel:

# Vom lokalen PC:
ssh -L 8181:127.0.0.1:81 luna@VPS-IP -p 226

# Dann im Browser öffnen:
# http://localhost:8181

Standard-Login:

  • E-Mail: admin@example.com
  • Passwort: changeme

Beim ersten Login wirst du aufgefordert, beides zu ändern.

Firewall auf dem VPS

# UFW konfigurieren
sudo ufw allow 80/tcp comment 'HTTP'
sudo ufw allow 443/tcp comment 'HTTPS'

# Port 81 NICHT öffnen (bleibt nur lokal erreichbar)

sudo ufw reload

Dienste auf dem Heimserver

Beispiel: BookStack, Vaultwarden und Gitea als Docker-Container:

# Verzeichnis erstellen
mkdir -p ~/services && cd ~/services

nano docker-compose.yml
version: '3.8'

services:
  # ══════════════════════════════════════════════════════════════
  # BookStack Wiki
  # ══════════════════════════════════════════════════════════════
  bookstack:
    image: lscr.io/linuxserver/bookstack:latest
    container_name: bookstack
    restart: unless-stopped
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Europe/Berlin
      - APP_URL=https://wiki.deine-domain.de
      - DB_HOST=bookstack-db
      - DB_USER=bookstack
      - DB_PASS=sicheres-passwort                # ← Anpassen!
      - DB_DATABASE=bookstack
    volumes:
      - ./bookstack/config:/config
    ports:
      - "100.64.0.1:3000:80"                     # ← Nur auf NetBird-IP
    depends_on:
      - bookstack-db
    networks:
      - internal

  bookstack-db:
    image: mariadb:10
    container_name: bookstack-db
    restart: unless-stopped
    environment:
      - MYSQL_ROOT_PASSWORD=root-passwort        # ← Anpassen!
      - MYSQL_DATABASE=bookstack
      - MYSQL_USER=bookstack
      - MYSQL_PASSWORD=sicheres-passwort         # ← Anpassen!
    volumes:
      - ./bookstack/db:/var/lib/mysql
    networks:
      - internal

  # ══════════════════════════════════════════════════════════════
  # Vaultwarden (Bitwarden-Alternative)
  # ══════════════════════════════════════════════════════════════
  vaultwarden:
    image: vaultwarden/server:latest
    container_name: vaultwarden
    restart: unless-stopped
    environment:
      - TZ=Europe/Berlin
      - DOMAIN=https://vault.deine-domain.de
      - SIGNUPS_ALLOWED=false
      - ADMIN_TOKEN=admin-token-hier             # ← Generieren mit: openssl rand -base64 48
    volumes:
      - ./vaultwarden:/data
    ports:
      - "100.64.0.1:8080:80"                     # ← Nur auf NetBird-IP
    networks:
      - internal

  # ══════════════════════════════════════════════════════════════
  # Gitea (Git-Server)
  # ══════════════════════════════════════════════════════════════
  gitea:
    image: gitea/gitea:latest
    container_name: gitea
    restart: unless-stopped
    environment:
      - USER_UID=1000
      - USER_GID=1000
      - GITEA__server__DOMAIN=git.deine-domain.de
      - GITEA__server__ROOT_URL=https://git.deine-domain.de/
    volumes:
      - ./gitea:/data
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    ports:
      - "100.64.0.1:3001:3000"                   # ← Nur auf NetBird-IP
      - "100.64.0.1:2222:22"                     # ← Git SSH (optional)
    networks:
      - internal

networks:
  internal:
    name: services-internal
# Starten
docker compose up -d

Wichtig: Die Dienste sind an 100.64.0.1 (NetBird-IP) gebunden – sie sind nur über den NetBird-Tunnel erreichbar, nicht aus dem lokalen Netzwerk oder Internet!

Dienste auch lokal erreichbar machen (optional)

Falls du die Dienste auch im lokalen Netzwerk nutzen willst:

ports:
  - "100.64.0.1:3000:80"     # NetBird
  - "192.168.1.50:3000:80"   # Lokales Netzwerk (IP anpassen)
  # ODER einfach:
  - "3000:80"                # Alle Interfaces (weniger sicher)

Proxy Hosts in NPM konfigurieren

In der NPM Web-Oberfläche (http://localhost:8181 via SSH-Tunnel):

1. SSL-Zertifikate einrichten

  1. SSL CertificatesAdd SSL Certificate
  2. Let's Encrypt auswählen
  3. Domain: *.deine-domain.de (Wildcard) oder einzeln
  4. E-Mail eingeben
  5. DNS Challenge aktivieren (für Wildcard erforderlich)

2. Proxy Host für Wiki

  1. HostsProxy HostsAdd Proxy Host
  2. Details:
    • Domain Names: wiki.deine-domain.de
    • Scheme: http
    • Forward Hostname/IP: 100.64.0.1
    • Forward Port: 3000
    • ☑ Block Common Exploits
    • ☑ Websockets Support
  3. SSL:
    • SSL Certificate: (dein Zertifikat auswählen)
    • ☑ Force SSL
    • ☑ HTTP/2 Support
    • ☑ HSTS Enabled
  4. Save

3. Proxy Host für Vaultwarden

  • Domain: vault.deine-domain.de
  • Forward Hostname/IP: 100.64.0.1
  • Forward Port: 8080
  • Websockets aktivieren (wichtig für Vaultwarden!)

4. Proxy Host für Gitea

  • Domain: git.deine-domain.de
  • Forward Hostname/IP: 100.64.0.1
  • Forward Port: 3001

DNS konfigurieren

Bei deinem DNS-Provider:

Typ Name Wert TTL
A wiki VPS-IPv4 3600
AAAA wiki VPS-IPv6 3600
A vault VPS-IPv4 3600
A git VPS-IPv4 3600

Teil 3: Variante B – NPM auf beiden Systemen

Komplexeres Setup mit NPM auf beiden Seiten – nützlich wenn du viele Dienste hast und diese lokal verwalten willst.

NPM auf dem Heimserver

mkdir -p ~/nginx-proxy-manager && cd ~/nginx-proxy-manager

nano docker-compose.yml
version: '3.8'

services:
  npm:
    image: 'jc21/nginx-proxy-manager:latest'
    container_name: nginx-proxy-manager
    restart: unless-stopped
    ports:
      - '100.64.0.1:80:80'              # HTTP auf NetBird-IP
      - '100.64.0.1:443:443'            # HTTPS auf NetBird-IP
      - '192.168.1.50:81:81'            # Admin-UI im lokalen Netz (IP anpassen!)
    volumes:
      - ./data:/data
      - ./letsencrypt:/etc/letsencrypt
    environment:
      - TZ=Europe/Berlin
    networks:
      - proxy

networks:
  proxy:
    name: proxy
    driver: bridge
docker compose up -d

Dienste auf dem Heimserver (Variante B)

Dienste binden jetzt an 127.0.0.1, NPM leitet lokal weiter:

version: '3.8'

services:
  bookstack:
    image: lscr.io/linuxserver/bookstack:latest
    container_name: bookstack
    restart: unless-stopped
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Europe/Berlin
      - APP_URL=https://wiki.deine-domain.de
      - DB_HOST=bookstack-db
      - DB_USER=bookstack
      - DB_PASS=sicheres-passwort
      - DB_DATABASE=bookstack
    volumes:
      - ./bookstack/config:/config
    expose:
      - "80"                             # Nur intern erreichbar
    depends_on:
      - bookstack-db
    networks:
      - proxy
      - internal

  bookstack-db:
    image: mariadb:10
    container_name: bookstack-db
    restart: unless-stopped
    environment:
      - MYSQL_ROOT_PASSWORD=root-passwort
      - MYSQL_DATABASE=bookstack
      - MYSQL_USER=bookstack
      - MYSQL_PASSWORD=sicheres-passwort
    volumes:
      - ./bookstack/db:/var/lib/mysql
    networks:
      - internal

  vaultwarden:
    image: vaultwarden/server:latest
    container_name: vaultwarden
    restart: unless-stopped
    environment:
      - TZ=Europe/Berlin
      - DOMAIN=https://vault.deine-domain.de
    volumes:
      - ./vaultwarden:/data
    expose:
      - "80"
    networks:
      - proxy

networks:
  proxy:
    external: true
    name: proxy
  internal:
    name: services-internal

NPM auf Heimserver konfigurieren

Proxy Hosts im lokalen NPM (Port 81):

Domain/Hostname Forward To Port
wiki (interner Name) bookstack 80
vault vaultwarden 80

Hinweis: Im gleichen Docker-Netzwerk können Container über ihren Namen erreicht werden.

NPM auf VPS (Variante B)

version: '3.8'

services:
  npm:
    image: 'jc21/nginx-proxy-manager:latest'
    container_name: nginx-proxy-manager
    restart: unless-stopped
    ports:
      - '80:80'
      - '443:443'
      - '127.0.0.1:81:81'
    volumes:
      - ./data:/data
      - ./letsencrypt:/etc/letsencrypt
    environment:
      - TZ=Europe/Berlin
    extra_hosts:
      - "heimserver:100.64.0.1"

NPM auf VPS konfigurieren (Variante B)

Leitet zum Heimserver-NPM weiter:

Domain Forward To Port SSL
wiki.deine-domain.de 100.64.0.1 80 oder 443 Auf VPS terminieren
vault.deine-domain.de 100.64.0.1 80 oder 443 Auf VPS terminieren

Teil 4: Erweiterte Konfiguration

Custom Nginx-Konfiguration in NPM

Für spezielle Anforderungen kannst du in NPM unter Advanced eigene Nginx-Direktiven hinzufügen:

Security Headers

# Im "Advanced" Tab des Proxy Hosts:
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;

Rate Limiting

# Benötigt Anpassung der nginx.conf im Container
# Einfacher: Fail2ban auf Host-Ebene nutzen

Größere Uploads erlauben

# Im "Advanced" Tab:
client_max_body_size 100M;

Access Lists (IP-Beschränkung)

NPM hat eingebaute Access Lists:

  1. Access ListsAdd Access List
  2. Name eingeben
  3. Access Tab:
    • Satisfy: Any/All
    • Allow: IP-Bereiche die zugreifen dürfen
    • Deny: Alles andere
  4. Beim Proxy Host diese Access List auswählen

HTTP Basic Auth

Für zusätzlichen Schutz sensibler Dienste:

  1. Access ListsAdd Access List
  2. Authorization Tab:
    • Username und Passwort hinzufügen
  3. Beim Proxy Host zuweisen

Wildcard SSL-Zertifikate

Für alle Subdomains ein Zertifikat:

  1. SSL CertificatesAdd SSL CertificateLet's Encrypt
  2. Domain Names: *.deine-domain.de und deine-domain.de
  3. ☑ Use a DNS Challenge
  4. DNS Provider auswählen (z.B. Cloudflare, Hetzner DNS, etc.)
  5. API-Credentials eingeben

Hetzner DNS API-Beispiel

# In NPM unter DNS Provider:
Provider: Hetzner
API Token: dein-hetzner-dns-api-token

Teil 5: Backup und Wartung

NPM-Daten sichern

# Backup erstellen
cd ~/nginx-proxy-manager
docker compose stop
tar -czvf npm-backup-$(date +%Y%m%d).tar.gz data letsencrypt
docker compose start

NPM aktualisieren

cd ~/nginx-proxy-manager

# Neues Image holen
docker compose pull

# Container neu starten
docker compose up -d

# Alte Images aufräumen
docker image prune -f

Logs prüfen

# NPM-Logs
docker compose logs -f npm

# Nur Fehler
docker compose logs npm | grep -i error

# Access-Logs
docker exec nginx-proxy-manager tail -f /data/logs/proxy-host-1_access.log

Teil 6: Troubleshooting

Häufige Probleme

Problem Ursache Lösung
502 Bad Gateway Backend nicht erreichbar NetBird-Verbindung prüfen: ping 100.64.0.1
SSL-Fehler Zertifikat nicht ausgestellt DNS prüfen, Port 80 offen?
504 Gateway Timeout Backend antwortet zu langsam Timeout in Advanced erhöhen
Admin-UI nicht erreichbar Port 81 nicht weitergeleitet SSH-Tunnel prüfen
Container startet nicht Port bereits belegt sudo lsof -i :80
DNS Challenge fehlgeschlagen API-Token falsch Token und Provider prüfen

NetBird-Verbindung debuggen

# Status
sudo netbird status

# Detailliert
sudo netbird status -d

# Neuverbinden
sudo netbird down && sudo netbird up

# Logs
sudo journalctl -u netbird -f

Container debuggen

# In Container einloggen
docker exec -it nginx-proxy-manager /bin/bash

# Nginx-Config testen
docker exec nginx-proxy-manager nginx -t

# Nginx neu laden (ohne Neustart)
docker exec nginx-proxy-manager nginx -s reload

Zusammenfassung: Checkliste

VPS

  • ☐ Docker & Docker Compose installiert
  • ☐ NetBird installiert und verbunden
  • ☐ NPM Container läuft
  • ☐ Firewall: Port 80, 443 offen
  • ☐ Admin-UI nur via SSH-Tunnel erreichbar
  • ☐ Proxy Hosts konfiguriert
  • ☐ SSL-Zertifikate aktiv

Heimserver

  • ☐ Docker & Docker Compose installiert
  • ☐ NetBird installiert und verbunden
  • ☐ Dienste-Container laufen
  • ☐ Dienste nur auf NetBird-IP gebunden
  • ☐ (Optional) Lokaler NPM für Verwaltung

DNS

  • ☐ A/AAAA-Records zeigen auf VPS-IP
  • ☐ DNS-Propagation abgeschlossen

Testen

  • ping 100.64.0.1 vom VPS funktioniert
  • curl http://100.64.0.1:3000 vom VPS funktioniert
  • ☐ HTTPS-Aufruf der Domain funktioniert
  • ☐ SSL-Zertifikat gültig (Browser-Check)

Letzte Aktualisierung: 2025