Portainer selbst hosten: Web-UI für dein Docker-Setup
Container per CLI starten, Stacks verwalten, Logs durchforsten – irgendwann nervt es. Portainer gibt dir eine übersichtliche Web-Oberfläche für all das: Container, Stacks (Docker Compose), Images, Volumes und Netzwerke lassen sich damit bequem per Klick verwalten. In diesem Tutorial richtest du Portainer CE mit Docker Compose ein – abgesichert über localhost-Bindung, hardened Docker-Socket und Reverse Proxy.
Warum Portainer?
Wer selbst hostet, sammelt schnell dutzende Container an – und verliert zwischen docker ps,
docker compose up und Logs langsam den Überblick. Portainer ist eine Web-Oberfläche
für Docker: Container starten/stoppen, Stacks per Compose anlegen, Images aktualisieren,
Volumes und Netzwerke verwalten – alles per Klick, ohne CLI-Wissen. Die Community Edition (CE)
ist kostenlos und deckt für einen einzelnen Host alles ab, was man im Homelab braucht.
Features auf einen Blick
- Dashboard: Ressourcen, Container-Status und Events des Docker-Hosts auf einen Blick.
- Stacks: Docker-Compose-Projekte direkt aus der UI anlegen, bearbeiten und aktualisieren – so entstehen die Setups aus unseren Artikeln per Klick.
- Container-Ansicht: Logs, Konsole (Web-Terminal), Statistiken, Neu-Start und Neubau ohne SSH.
- Images, Volumes & Netzwerke: listen, aufräumen (Pruning) und verwalten.
- Nutzer & Teams: mehrere Accounts mit Rechten – praktisch, wenn mehrere Personen am Server arbeiten.
- App Templates: vorkonfigurierte Stacks für viele bekannte Dienste als Startpunkt.
Vorbereitung: Socket & Daten
Portainer verwaltet Docker über den Docker-Socket (/var/run/docker.sock).
Das ist ein mächtiger Zugriff – wer den Socket hat, hat im Grunde Root auf dem Host. Deshalb gilt: nur an
localhost binden und den Zugriff ausschließlich über den eigenen Reverse Proxy erlauben:
mkdir -p ~/portainer/data
cd ~/portainer
./portainer/data→/data: hier liegen Datenbank, Einstellungen, Zertifikate und Nutzerkonten – dein komplettes Backup./var/run/docker.sockwird read-only gemountet – zusätzliche Härtung. Das offizielle Beispiel verzichtet auf:ro; falls bei Stack-Operationen unerwartete Fehler auftauchen, ist das der erste Kandidat zum Testen./etc/localtime(ro): sorgt dafür, dass Logs und Zeitangaben zur Host-Zeitzone passen.
Docker Compose – die Datei
So sieht das fertige Setup aus (deine Vorlage, aufgeräumt: leerer networks: {}-Block und überflüssiges network_mode entfernt, Ports in Anführungszeichen):
services:
portainer:
container_name: portainer
image: portainer/portainer-ce:latest
restart: unless-stopped
deploy:
resources:
limits:
cpus: "2.0"
memory: 2G
ports:
- "127.0.0.1:50512:9000" # Web-UI nur lokal
security_opt:
- no-new-privileges:true
volumes:
- /etc/localtime:/etc/localtime:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./portainer/data:/data
environment:
- TRUSTED_ORIGINS=https://pt.meine.domain
Warum die einzelnen Zeilen?
127.0.0.1:50512:9000: Die UI lauscht im Container auf Port 9000 (Portainer CE); gebunden wird nur an localhost, der Zugriff läuft über den Reverse Proxy.no-new-privileges:true: verhindert, dass Prozesse im Container zusätzliche Rechte anfordern (setuid/Setcap).TRUSTED_ORIGINS: erlaubt genau die Origin, über die du die UI aufrufst – verhindert CSRF-Fehler und Login-Schleifen hinter dem Proxy (Details unten).:latestfolgt der jeweils neuesten Version – für reproduzierbare Updates lässt sich stattdessen ein konkretes Versions-Tag pinnen (z. B.:2.21.x).
Konfiguration: TRUSTED_ORIGINS & Co.
Der wichtigste Schalter deiner Konfiguration ist TRUSTED_ORIGINS:
| Variable | Wert | Bedeutung |
|---|---|---|
TRUSTED_ORIGINS | https://pt.meine.domain | Erlaubte Origin(s) für die UI. Muss exakt zur öffentlichen URL passen (inkl. https://, ohne Pfad). Mehrere Origins kommasepariert angeben. |
- Rufst du die UI zusätzlich über eine zweite Adresse oder IP auf (z. B.
https://192.0.2.10für Tests), dort ebenfalls eintragen – sonst blockiert Portainer den Zugriff. - Fehlt die Variable, kann es hinter Reverse Proxys zu CSRF-Meldungen oder Endlos-Redirects beim Login kommen.
- Weitere Konfiguration erfolgt nach dem ersten Login in der Oberfläche (Einstellungen) – Umgebungsvariablen sind bei Portainer CE bewusst sparsam.
Reverse Proxy & WebSockets
Die UI spricht nur HTTP – also gehört ein TLS-terminierender Proxy davor. Da der Port nur auf localhost lauscht, reicht ein Proxy auf demselben Host. Wichtig: Portainer nutzt für Logs, Konsole und das Web-Terminal WebSockets – die müssen durchgereicht werden:
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name pt.meine.domain;
access_log off;
error_log /var/log/nginx/pt.meine.domain.error.log;
ssl_certificate /etc/ssl/private/pt.meine.domain_ecc/fullchain.cer;
ssl_certificate_key /etc/ssl/private/pt.meine.domain_ecc/pt.meine.domain.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_early_data on;
ssl_session_cache shared:SSL:50m;
ssl_session_timeout 1d;
# Sicherheits-Header
add_header Strict-Transport-Security "max-age=31536000; includeSubdomains; preload" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header Referrer-Policy "no-referrer" always;
location / {
proxy_http_version 1.1;
# WebSockets für Logs, Konsole & Terminal
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Scheme $scheme;
proxy_read_timeout 3600s;
proxy_pass http://127.0.0.1:50512;
}
}
docker compose up -d --force-recreate).
Erster Start: Admin-Konto
cd ~/portainer
docker compose up -d
docker compose logs -f portainer # bis "Starting Portainer" / ohne Fehler
Danach https://pt.meine.domain öffnen:
- Admin-Konto anlegen: Benutzername und ein starkes Passwort (mindestens 12 Zeichen) – dieses Konto wird nur einmal erstellt.
- Anschließend „Get Started“ wählen: Portainer verbindet sich automatisch mit dem lokalen Docker-Socket und zeigt deine laufenden Container.
- Im Menü „Stacks“ lassen sich jetzt Compose-Projekte aus der UI heraus anlegen – die Configs aus unseren Artikeln kannst du dort direkt einfügen.
- Wer mit mehreren Personen arbeitet, legt unter Einstellungen → Nutzer/Teams weitere Konten mit eingeschränkten Rechten an.
Backups, Updates & Härtung
Für Updates reicht docker compose pull && docker compose up -d –
Portainer legt beim Start eine neue Version der Datenbank an. Trotzdem gilt: vorher ein Backup machen,
denn ein Downgrade über mehrere Versionen ist nicht vorgesehen.
./portainer/data sichern. Beides zusammen deckt Nutzer,
Einstellungen und Zertifikate ab. Härtung: Admin-Passwort nur im Passwortmanager, Statistik aus,
UI ausschließlich hinter HTTPS.
Häufige Probleme (FAQ)
| Problem | Lösung |
|---|---|
| Login-Loop / CSRF-Fehler hinter Proxy | TRUSTED_ORIGINS exakt auf die öffentliche URL setzen und Container neu erstellen. |
| Port-Konflikt beim Start | Externer Port 50512 ist in unserem Stack bereits durch Open-WebUI (GPU-Variante) belegt – auf einen freien Port ändern. |
| Stack-Erstellung schlägt fehl | Bei read-only gemountetem docker.sock: kurz :ro entfernen und testen (offizielles Beispiel mountet ohne). |
| Admin-Passwort vergessen | Es gibt kein Reset über die CLI – letztes Backup unter Einstellungen → Backup wiederherstellen oder das Datenverzeichnis zurücksetzen (Einstellungen gehen verloren). |
| Terminal/Logs laden nicht | WebSocket-Upgrade im Proxy prüfen (Upgrade/Connection-Header, proxy_http_version 1.1). |
| UI zeigt „Environment nicht verbunden“ | Socket-Mount prüfen (docker compose exec portainer ls -la /var/run/docker.sock) und ggf. Container neu erstellen. |
Fazit
Portainer macht aus der Docker-Verwaltung eine Sache von Klicks statt Kommandozeilen-Suche: Container,
Stacks und Volumes auf einen Blick, Logs und Konsolen direkt im Browser. Dank localhost-Bindung,
read-only-Socket und no-new-privileges bleibt das Setup dabei erstaunlich schlank – der
einzige Preis ist der mächtige Socket-Zugriff, den man mit starkem Passwort und HTTPS davor im Zaum hält.
TRUSTED_ORIGINS exakt zur Proxy-URL setzen. ③ WebSockets im Proxy durchreichen
(Logs/Terminal). ④ Vor Updates Backup ziehen (Einstellungen → Backup).