Fehler-Finder: Selfhosting-Fehlermeldungen nachschlagen
Container startet nicht, Zertifikat fehlt, Mail hängt? Such deine Fehlermeldung – jede Antwort stammt aus einem Setup, das wir selbst zum Laufen gebracht haben.
Jede Karte hier stammt aus einem Tutorial dieser Seite – aus einem Fehler, der uns beim Aufsetzen
auf dem Test-Server tatsächlich begegnet ist. Tipp die Fehlermeldung ein (address already in use, NXDOMAIN, Unauthorized) oder beschreib das Symptom in eigenen Worten.
264 Fundstellen aus echten Setups
In den Logs steht „middleware … does not exist" und der Dienst antwortet mit 404.
Fast immer
fehlt der Provider-Zusatz: Eine im File-Provider definierte Middleware heißt aus Sicht der
Docker-Labels
Nachlesen: Traefik härten →name@file. Ohne Zusatz sucht Traefik sie unter den Docker-Labels – und findet
nichts. Umgekehrt gilt dasselbe für name@docker.BasicAuth lehnt das richtige Passwort ab.
Die
Nachlesen: Traefik härten →$-Zeichen im bcrypt-Hash wurden von Docker
Compose als Variablen interpretiert. Im Compose müssen sie verdoppelt werden ($$2y$$05$$…).
Mit docker compose config siehst du den Wert, der wirklich ankommt.Das Rate-Limit scheint nicht zu greifen.
Sequenzielle
Nachlesen: Traefik härten →curl-Aufrufe sind zu langsam: Jeder
Prozess baut eine neue Verbindung auf, damit bleibst du unter dem Limit. Teste parallel, etwa mit
seq 40 | xargs -P 8 -I{} curl … – dann erscheinen die 429.Nach dem Setzen der IP-Allowlist bekommst du selbst 403.
Traefik sieht nicht deine IP, sondern
die des davorstehenden Proxys (Cloudflare, Load-Balancer). Prüfe mit
Nachlesen: Traefik härten →traefik/whoami, was in
X-Forwarded-For steht, und arbeite bei mehrstufigen Aufbauten mit
ipallowlist.ipstrategy.depth.Eine v2-Konfiguration mit ipWhiteList funktioniert nach dem Upgrade nicht mehr.
Die Middleware
heißt in Traefik v3
Nachlesen: Traefik härten →ipAllowList; der alte Name wurde entfernt, die Regel greift damit nicht mehr.
Beim Umstieg alle Vorkommen umbenennen.Der Browser kommt trotz korrigierter Konfiguration nicht mehr per HTTP durch.
Das ist HSTS und
kein Fehler: Der Browser hat sich
Nachlesen: Traefik härten →max-age gemerkt und erzwingt HTTPS selbst dann, wenn dein Server
es nicht mehr anbietet. Zum Testen hilft ein privates Fenster oder ein anderer Browser – und deshalb
die Warnung zu preload oben.Traefik antwortet mit 404, obwohl der Container healthy ist.
Meist fehlt
Nachlesen: Dockge: Compose-Stacks im Browser verwalten →traefik.http.services.dockge.loadbalancer.server.port=5001. Dockge lauscht im Container auf
5001; ohne die Zeile rät Traefik. Prüfe außerdem, dass der Container im proxy-Netz hängt.Der Deploy bricht mit „no such file or directory" ab.
Host- und Container-Pfad des
Stacks-Verzeichnisses stimmen nicht überein. Es muss
Nachlesen: Dockge: Compose-Stacks im Browser verwalten →/opt/stacks:/opt/stacks gemountet und
DOCKGE_STACKS_DIR=/opt/stacks gesetzt sein – Dockge lässt den Docker-Daemon des Hosts arbeiten,
und der kennt nur Host-Pfade.Ein Stack ist sichtbar, aber alle Knöpfe fehlen.
Dann liegt er außerhalb von
Nachlesen: Dockge: Compose-Stacks im Browser verwalten →/opt/stacks,
und Dockge zeigt „Dieser Stack wird nicht von Dockge verwaltet." Verschiebe den Ordner wie in
Schritt 7 – Dockge übernimmt ihn nicht von selbst und legt auch keine Kopie an.Der Stack-Name wird abgelehnt.
Erlaubt sind nur Kleinbuchstaben, Ziffern und Bindestriche,
weil daraus Ordner- und Compose-Projektname werden.
Nachlesen: Dockge: Compose-Stacks im Browser verwalten →Meine App geht nicht, meine-app schon.Nach einem Neustart ist die Anmeldung weg.
Dann wurde
Nachlesen: Dockge: Compose-Stacks im Browser verwalten →./data nicht persistent gemountet –
dort liegen Datenbank und JWT-Secret. Prüfe, dass /opt/dockge/data existiert und im Compose
eingebunden ist.Die Oberfläche ist englisch, obwohl der Browser auf Deutsch steht.
Dockge richtet sich nach
dem Browser und fällt bei unbekannten Kombinationen auf Englisch zurück; in den Einstellungen
lässt sich die Sprache fest wählen.
Nachlesen: Dockge: Compose-Stacks im Browser verwalten →Die Bibliothek bleibt nach dem Anlegen leer.
Der erste Scan läuft nicht automatisch – das
ist kein Fehler, sondern Audiobookshelfs Verhalten. Klick in der Bibliotheksansicht auf
Bibliothek scannen. Bleibt sie danach leer, prüfe mit
Nachlesen: Audiobookshelf: Hörbücher & Podcasts selbst hosten →docker compose exec audiobookshelf ls -R /audiobooks, ob der Container die Dateien überhaupt
sieht, und mit ls -ln /opt/audiobookshelf/audiobooks, dass alles UID 1000 gehört.Aus vier MP3-Dateien werden vier Hörbücher statt vier Kapitel.
Die Dateien liegen direkt im
Autoren-Ordner statt in einem gemeinsamen Titel-Ordner. Audiobookshelf gruppiert nach
Nachlesen: Audiobookshelf: Hörbücher & Podcasts selbst hosten →Autor/Titel/ – Dateien in einen Unterordner mit dem Buchtitel legen und erneut scannen.Traefik antwortet mit 404, obwohl der Container läuft.
Meist fehlt
Nachlesen: Audiobookshelf: Hörbücher & Podcasts selbst hosten →traefik.http.services.abs.loadbalancer.server.port=80. Audiobookshelf lauscht im Container auf
80; ohne diese Zeile rät Traefik und trifft daneben. Prüfe außerdem, dass der Container
wirklich im proxy-Netz hängt.Die Adresse springt auf /audiobookshelf/.
Das ist normal: Das Frontend wird mit diesem
festen Router-Pfad ausgeliefert, und
Nachlesen: Audiobookshelf: Hörbücher & Podcasts selbst hosten →ROUTER_BASE_PATH ändert daran zur Laufzeit nichts, weil
der Pfad im Image eingebaut ist. https://DEINE_DOMAIN bleibt als Einstieg gültig.Nach dem Gerätewechsel ist die Oberfläche wieder englisch.
Die Sprachwahl liegt lokal im
Browser, nicht am Konto. Auf dem neuen Gerät einmal über den Benutzernamen →
Nachlesen: Audiobookshelf: Hörbücher & Podcasts selbst hosten →Language →
„Deutsch" setzen.Der Podcast wird nicht gefunden.
Die Suche fragt den iTunes-Katalog ab; ein Tippfehler oder
ein dort fehlender Eintrag führt zu „Keine Suchergebnisse". Nimm stattdessen die RSS-URL des
Podcasts – dasselbe Feld akzeptiert beides.
Nachlesen: Audiobookshelf: Hörbücher & Podcasts selbst hosten →Redirect-Schleife (ERR_TOO_MANY_REDIRECTS) oder Mixed-Content-Warnungen.
Die HTTPS-Erkennung fehlt. Prüfe, dass der
Nachlesen: WordPress mit Docker & Traefik sauber betreiben →WORDPRESS_CONFIG_EXTRA-Block mit HTTP_X_FORWARDED_PROTO und den $$-Zeichen exakt gesetzt ist (siehe Warnung in Schritt 2), und starte den WordPress-Container neu.WordPress startet nicht, meldet „Error establishing a database connection“.
Meist eine Race Condition oder ein Passwort-Mismatch. Prüfe, dass
Nachlesen: WordPress mit Docker & Traefik sauber betreiben →depends_on: condition: service_healthy gesetzt ist und WORDPRESS_DB_PASSWORD exakt MARIADB_PASSWORD entspricht. Logs: docker compose logs db.Der erste Start scheitert, obwohl später alles läuft.
Die Datenbank braucht beim allerersten Start einige Sekunden zur Initialisierung. Mit dem Healthcheck ist das abgedeckt; ohne ihn hilft ein erneutes
Nachlesen: WordPress mit Docker & Traefik sauber betreiben →docker compose up -d.Medien-Uploads schlagen bei großen Dateien fehl.
PHP begrenzt die Upload-Größe. Lege eine eigene
Nachlesen: WordPress mit Docker & Traefik sauber betreiben →uploads.ini an und mounte sie nach /usr/local/etc/php/conf.d/ mit z. B. upload_max_filesize = 64M und post_max_size = 64M.Nach einem Domainwechsel zeigt die Seite ins Leere.
WP_HOME/WP_SITEURL in der Compose-Datei stehen fest verdrahtet – bei einer neuen Domain dort anpassen und Container neu starten (die Werte überschreiben die Datenbank-Einstellung).Login scheitert mit CSRF-Fehler.
LD_CSRF_TRUSTED_ORIGINS: https://DEINE_DOMAIN fehlt oder ist falsch (muss mit https:// und ohne Pfad angegeben sein). Ergänzen und docker compose up -d (siehe Warnung in Schritt 1).Die Seite kommt nicht (Traefik-404), obwohl der Container läuft.
Der Healthcheck ist noch nicht
Nachlesen: linkding: Lesezeichen selbst hosten →healthy – Traefik leitet dann bewusst nicht. Rund 30 Sekunden nach dem Start abwarten; Status mit docker inspect -f '{{.State.Health.Status}}' linkding-linkding-1 prüfen.Titel/Beschreibung werden nicht automatisch geholt.
Die Zielseite blockiert automatisierte Zugriffe oder antwortet zu langsam. Du kannst Titel und Beschreibung dann einfach von Hand eintragen – die Felder stehen im selben Formular.
Nachlesen: linkding: Lesezeichen selbst hosten →Das Admin-Konto wurde nicht angelegt.
LD_SUPERUSER_NAME/LD_SUPERUSER_PASSWORD greifen nur beim ersten Start mit leerer Datenbank. Existiert die data-Datenbank schon, ändert eine spätere Anpassung nichts. Konto nachträglich anlegen: docker compose exec linkding python manage.py createsuperuser.Die Extension verbindet sich nicht.
Fast immer der API-Token oder die URL. Token unter Settings → Integrations neu erzeugen und exakt
Nachlesen: linkding: Lesezeichen selbst hosten →https://DEINE_DOMAIN als Server eintragen.Die Bibliothek bleibt leer.
Entweder liegen keine Dateien im gemounteten
Nachlesen: Navidrome: die eigene Musik streamen wie mit Spotify →music-Ordner, oder die Rechte stimmen nicht. Prüfe: docker compose logs | grep -i scan zeigt tracksImported. Ist es 0, kontrolliere den Pfad und dass der music-Ordner UID 1000 gehört (siehe Benutzer & Rechte).Titel erscheinen unsortiert oder ohne Cover.
Die Metadaten der Dateien sind unvollständig. Navidrome sortiert nach Tags, nicht nach Dateinamen – tagge die Dateien nach (z. B. mit Picard) und lass Navidrome erneut scannen.
Nachlesen: Navidrome: die eigene Musik streamen wie mit Spotify →Neue Musik taucht nicht auf.
Der Scan läuft nur stündlich (
Nachlesen: Navidrome: die eigene Musik streamen wie mit Spotify →ND_SCANNER_SCHEDULE). Einen sofortigen Scan stößt du in der Weboberfläche über das Aktualisieren-Symbol oben an, oder du wartest bis zum nächsten Intervall.Die App verbindet sich nicht.
Fast immer die Server-URL: Sie muss
Nachlesen: Navidrome: die eigene Musik streamen wie mit Spotify →https://DEINE_DOMAIN lauten (mit https://, ohne Pfad). Prüfe außerdem, dass Benutzername/Passwort exakt stimmen – manche Apps verlangen zusätzlich die Aktivierung der Subsonic-Kompatibilität, die bei Navidrome standardmäßig an ist.Wiedergabe stockt bei großen FLAC-Dateien mobil.
Die Bandbreite reicht nicht fürs Original. Transcoding für den mobilen Player aktivieren (siehe Tipp in Schritt 7).
Nachlesen: Navidrome: die eigene Musik streamen wie mit Spotify →Container startet nicht: „unable to open database file“.
DB_NAME: /data/hc.sqlite fehlt oder der data-Ordner gehört nicht UID 1000. Pfad setzen und chown -R 1000:1000 /opt/healthchecks/data (siehe Warnung in Schritt 2).Die Seite antwortet mit HTTP 500.
Häufigste Ursache: ein Umlaut in
Nachlesen: Healthchecks einrichten →SITE_NAME (oder einer anderen Text-Umgebungsvariable). Auf reines ASCII umstellen und neu starten. Zur Diagnose vorübergehend DEBUG: "True" setzen – aber danach wieder auf False.Login schlägt fehl / CSRF-Fehler beim Absenden.
CSRF_TRUSTED_ORIGINS: https://DEINE_DOMAIN muss gesetzt sein – Django lehnt sonst POST-Anfragen hinter dem Reverse Proxy ab. Und ALLOWED_HOSTS muss exakt deine Domain enthalten.Der Check wird nicht „grün“, obwohl der Job läuft.
Prüfe, ob der
Nachlesen: Healthchecks einrichten →curl-Ping wirklich ausgeführt wird und die richtige UUID trifft: curl -v https://DEINE_DOMAIN/ping/UUID sollte OK zurückgeben. Auf der Detailseite siehst du im Protokoll, ob und von welcher IP Pings ankommen.Ich bekomme keine Benachrichtigung bei „down“.
Es ist kein Integrations-Kanal zugewiesen, oder (bei E-Mail) fehlen die SMTP-Einstellungen. Unter „Integrations“ einen Kanal einrichten und dem Check zuweisen.
Nachlesen: Healthchecks einrichten →Die Seite kommt nicht (Traefik-404), obwohl der Container läuft.
Der Healthcheck ist noch nicht
Nachlesen: Stirling-PDF einrichten →healthy – Traefik leitet dann bewusst nicht. Nach dem Start 20–30 Sekunden warten; Status mit docker inspect -f '{{.State.Health.Status}}' stirling-stirling-pdf-1 prüfen.Login mit admin/stirling scheitert.
Entweder wurde das Passwort schon geändert (dann das neue nutzen), oder die Konfiguration im
Nachlesen: Stirling-PDF einrichten →configs-Volume ist inkonsistent. Zum Zurücksetzen die Anwendung stoppen und die Nutzerkonfiguration im configs-Ordner prüfen; im Zweifel den Ordner leeren (Achtung: setzt alle Einstellungen zurück).OCR findet meine Sprache nicht.
Die passende
Nachlesen: Stirling-PDF einrichten →.traineddata fehlt im tessdata-Volume. Die Datei von den Tesseract-Sprachpaketen holen und in den data-Ordner legen (siehe Schritt 5).Eine Umwandlung (z. B. Office → PDF) schlägt fehl.
Solche Konvertierungen brauchen zusätzliche Werkzeuge (LibreOffice), die nur in den größeren Image-Varianten enthalten sind. Für den vollen Funktionsumfang die
Nachlesen: Stirling-PDF einrichten →-fat-Variante des Images verwenden (stirlingtools/stirling-pdf:2.14.3-fat).Große Dateien führen zu Fehlern oder langer Wartezeit.
OCR und Konvertierung sind speicherintensiv. Auf einem kleinen VPS kann RAM knapp werden – dann entweder kleinere Dateien verarbeiten oder auf ein größeres Produkt wechseln.
Nachlesen: Stirling-PDF einrichten →Der Container startet nicht / Neustart-Schleife mit permission denied.
Die Rechte am
Nachlesen: Syncthing einrichten →config- oder data-Ordner stimmen nicht. chown -R 1000:1000 /opt/syncthing/config /opt/syncthing/data und neu starten (siehe Warnung in Schritt 1).Die Oberfläche gibt eine Traefik-404, obwohl der Container läuft.
Der Healthcheck ist noch nicht
Nachlesen: Syncthing einrichten →healthy – Traefik leitet dann bewusst nicht. Bis zu 60 Sekunden nach dem Start abwarten und den Status prüfen (siehe Warnung in Schritt 3).Zwei Geräte verbinden sich nicht.
Prüfe drei Dinge: Ist Port 22000 (TCP+UDP) in der Firewall offen? Hast du die ID auf beiden Geräten eingetragen (die Kopplung ist beidseitig)? Und stimmt die ID exakt (Buchstabendreher fallen leicht auf, weil eine Prüfsumme eingebaut ist)? Der Status „Getrennt“ mit korrekt eingetragenen IDs deutet fast immer auf den Firewall-Port.
Nachlesen: Syncthing einrichten →Ein Ordner bleibt bei „Synchronisiere 0 %" hängen.
Meist fehlt auf der Gegenseite die Bestätigung der Freigabe, oder die Ordner-ID stimmt nicht überein – sie muss auf beiden Geräten identisch sein. Prüfe außerdem die Schreibrechte im Zielordner.
Nachlesen: Syncthing einrichten →Nach dem Setzen des GUI-Passworts kein Zugriff mehr.
Passwort vergessen? Du kannst es in der
Nachlesen: Syncthing einrichten →config.xml (<gui>-Block) zurücksetzen, indem du die <user>- und <password>-Zeilen entfernst und Syncthing neu startest – danach ist die Oberfläche wieder ohne Login erreichbar (und du setzt es sofort neu).Der Assistent meldet Schreibrechte-Fehler beim data-Ordner.
Der Container läuft als
Nachlesen: FreshRSS: der eigene RSS-Reader →www-data (UID 33). Bei bind-gemountetem ./data müssen die Rechte passen: chown -R 33:33 /opt/freshrss/data (siehe Benutzer & Rechte).Feeds werden nicht automatisch aktualisiert.
Prüfe, ob
Nachlesen: FreshRSS: der eigene RSS-Reader →CRON_MIN gesetzt ist und der interne Cron läuft: docker compose logs freshrss | grep -i cron. Manuell anstoßen kannst du jederzeit über den Aktualisieren-Knopf oben rechts oder docker compose exec -u www-data freshrss ./cli/actualize-user.php --user admin.Ein Feed bleibt leer / wird als „inaktiv" markiert.
Die Quelle liefert kein gültiges RSS/Atom, oder die URL ist eine HTML-Seite statt des Feeds. Viele Seiten verstecken den Feed – suche im Seitenquelltext nach
Nachlesen: FreshRSS: der eigene RSS-Reader →application/rss+xml. Unter „Statistiken → Inaktive Feeds“ findest du Problemquellen gebündelt.Login klappt nicht, obwohl das Passwort stimmt.
FreshRSS verschlüsselt das Passwort im Browser (JavaScript). Ist JavaScript deaktiviert oder die Verbindung nicht wirklich HTTPS (Zertifikatswarnung), scheitert der Login. Über Traefik ist HTTPS gegeben – prüfe im Zweifel das Zertifikat.
Nachlesen: FreshRSS: der eigene RSS-Reader →Nach einem Update fehlen Artikel.
FreshRSS bereinigt alte Artikel nach einer einstellbaren Frist (Standard: einige Wochen). Das ist gewollt und hält die Datenbank klein; erhöhe bei Bedarf die Aufbewahrung pro Feed in dessen Einstellungen.
Nachlesen: FreshRSS: der eigene RSS-Reader →systemctl start schlägt fehl, status zeigt status=203/EXEC.
systemd konnte das Programm aus
Nachlesen: systemd verstehen: Units, Journal & Timer (statt Cron) →ExecStart nicht ausführen; im Journal steht dazu Unable to locate executable. Entweder stimmt der Pfad nicht, oder der Datei fehlt das Ausführbar-Bit (chmod +x). Ohne führenden / sucht systemd nur in /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin (nachzusehen mit systemd-path search-binaries-default) – ein eigenes Skript unter /opt oder /root musst du deshalb mit absolutem Pfad eintragen.systemd warnt „The unit file, source configuration file or drop-ins of … changed on disk".
Du hast eine Unit-Datei bearbeitet, aber systemd liest Änderungen nicht automatisch. Nach jeder Änderung an
Nachlesen: systemd verstehen: Units, Journal & Timer (statt Cron) →/etc/systemd/system/ gilt: systemctl daemon-reload.Der Timer taucht in list-timers nicht auf.
Er wurde nicht aktiviert.
Nachlesen: systemd verstehen: Units, Journal & Timer (statt Cron) →systemctl enable --now DIENST.timer – und daran denken, dass der Timer den Service auslöst, du also beide Dateien brauchst (.service und .timer).systemctl enable antwortet „The unit files have no installation config".
Der Unit fehlt der Abschnitt
Nachlesen: systemd verstehen: Units, Journal & Timer (statt Cron) →[Install] mit WantedBy=; in systemctl status erkennst du sie am static in der Loaded:-Zeile. Ohne [Install] weiß systemd nicht, wann die Unit automatisch starten soll – bei Timern gehört WantedBy=timers.target hinein.Das Journal ist riesig / frisst Platz.
Standardmäßig wächst es begrenzt, aber du kannst es beschneiden:
Nachlesen: systemd verstehen: Units, Journal & Timer (statt Cron) →journalctl --vacuum-time=14d löscht Einträge älter als 14 Tage, journalctl --disk-usage zeigt den Verbrauch.„Host validation failed" statt Dashboard.
Die häufigste Stolperfalle:
Nachlesen: Homepage-Dashboard einrichten →HOMEPAGE_ALLOWED_HOSTS fehlt oder enthält die falsche Domain. Genau die Domain eintragen, unter der du zugreifst, dann docker compose up -d.Die Ressourcen-Widgets zeigen keine oder falsche Werte.
CPU und RAM liest Homepage aus dem Container heraus (kein Socket nötig). Zeigt
Nachlesen: Homepage-Dashboard einrichten →disk: / das Container-Dateisystem statt der Host-Platte, binde den gewünschten Pfad zusätzlich als Volume ein (z. B. - /:/host:ro und disk: /host).Ein Icon wird nicht geladen.
Der Name passt nicht zum Icon-Katalog. Schreibe den Dienstnamen klein und ohne Leerzeichen (
Nachlesen: Homepage-Dashboard einrichten →nextcloud.png), oder lege ein eigenes Bild in den icons-Ordner (gemountet nach /app/public/icons) und referenziere es als /icons/name.png.Die Container-Kachel zeigt keinen Status.
Der Wert bei
Nachlesen: Homepage-Dashboard einrichten →container: muss der exakte Container-Name sein. Finde ihn mit docker ps --format '{{.Names}}' – bei Compose ist das meist ordner-dienst-1 (z. B. traefik-traefik-1).Änderungen an den YAML-Dateien greifen nicht.
Ein Syntaxfehler bricht das Einlesen ab. YAML ist einrückungsempfindlich – prüfe die Logs mit
Nachlesen: Homepage-Dashboard einrichten →docker compose logs homepage auf error-Zeilen und achte auf konsequente Leerzeichen (keine Tabs).Statt der Anmeldemaske kommt „Authentication error – Auth is disabled or misconfigured".
Dann ist
Nachlesen: Homepage-Dashboard einrichten →HOMEPAGE_AUTH_ENABLED gesetzt, aber Secret oder Passwort kommen leer im Container an – meist, weil die .env im falschen Ordner liegt oder eine Zeile daraus fehlt. Im Log steht dazu Password auth is enabled but required settings are missing; docker compose config zeigt dir, welche Werte Compose wirklich einsetzt.Der Container bleibt unhealthy.
Fast immer der IPv6-Fallstrick aus Schritt 4: Der Healthcheck fragt
Nachlesen: Website mit Hugo hosten →localhost ab, nginx lauscht aber nur auf IPv4. Auf http://127.0.0.1/ umstellen. Prüfen mit docker inspect --format '{{.State.Health.Status}}' CONTAINER.Traefik zeigt 404 page not found (statt deiner Seite).
Das ist die Traefik-404, nicht die von nginx – Traefik findet keinen passenden Router. Häufigste Ursachen: Der Container ist noch nicht
Nachlesen: Website mit Hugo hosten →healthy, die Host()-Regel enthält die falsche Domain, oder das proxy-Netz ist nicht external. Siehe das 502/404-Kapitel in Docker-Netzwerke verstehen.Alle Links und Bilder sind kaputt.
Die
Nachlesen: Website mit Hugo hosten →baseURL in hugo.toml stimmt nicht mit der echten Domain überein. Hugo backt absolute URLs auf Basis dieses Werts ein – korrigieren und neu bauen.Ein Beitrag erscheint nicht.
Prüfe das
Nachlesen: Website mit Hugo hosten →date im Front Matter: Liegt es in der Zukunft, baut Hugo den Beitrag nicht (siehe Warn-Box in Schritt 3). Auch ein draft: true versteckt Inhalte im normalen Build.theme "PaperMod" not found beim Build.
Der Theme-Ordner fehlt im Build-Kontext – meist, weil er ein Git-Submodul ist, das nicht mitkopiert wurde, oder eine
Nachlesen: Website mit Hugo hosten →.dockerignore ihn ausschließt. Theme wie in Schritt 1 als echten Ordner ablegen.Container erreicht anderen nicht per Name (bad address).
Beide hängen nicht im selben benannten Netz, oder einer nutzt das Standard-
Nachlesen: Docker-Netzwerke verstehen →bridge (kein DNS). Prüfe mit docker inspect -f '{{range $k,$v := .NetworkSettings.Networks}}{{$k}} {{end}}' CONTAINER, in welchen Netzen ein Container hängt.Traefik gibt 502 Bad Gateway.
Fast immer sind Traefik und die App in verschiedenen
Nachlesen: Docker-Netzwerke verstehen →proxy-Netzen, weil das Netz doppelt angelegt wurde. external: true im Compose sicherstellen und mit docker network inspect proxy prüfen, ob beide Container gelistet sind.network proxy declared as external, but could not be found beim up.
Das externe Netz existiert noch nicht. Einmalig anlegen:
Nachlesen: Docker-Netzwerke verstehen →docker network create --ipv6 --subnet fd00:cafe::/64 proxy. Lass Traefik das Netz nicht selbst erzeugen – dann entsteht es ohne IPv6, und hinter dem Proxy steht bei IPv6-Besuchern die Gateway-Adresse statt der echten IP.Datenbank hat trotz internal Internet.
Sie hängt zusätzlich in einem nicht-internen Netz (z. B.
Nachlesen: Docker-Netzwerke verstehen →proxy). Ein Container hat die Summe der Zugriffe aller seiner Netze – die DB gehört nur ins interne Netz, nie ins proxy-Netz.Zwei Stacks kollidieren beim Subnetz.
Docker vergibt
Nachlesen: Docker-Netzwerke verstehen →172.x-Bereiche automatisch, aber bei vielen Netzen kann der Pool knapp werden (could not find an available, non-overlapping IPv4 address pool). Ungenutzte Netze aufräumen: docker network prune.Permission denied, obwohl die Rechte stimmen.
Prüfe die Rechte des übergeordneten Verzeichnisses: Fehlt dort das
Nachlesen: Linux-Benutzer, Gruppen & Dateirechte verstehen →x-Recht, kommst du gar nicht erst an die Datei heran, egal wie ihre eigenen Rechte aussehen. ls -ld /pfad/zum/ordner zeigt es.docker ps sagt weiter „permission denied“ nach usermod -aG docker.
Die neue Gruppe ist in der aktuellen Sitzung noch nicht aktiv – aus- und wieder einloggen (siehe Warn-Box in Schritt 7).
Nachlesen: Linux-Benutzer, Gruppen & Dateirechte verstehen →id in der neuen Sitzung muss docker anzeigen.Neue Dateien haben unerwartete Rechte.
Das bestimmt die
Nachlesen: Linux-Benutzer, Gruppen & Dateirechte verstehen →umask – sie zieht Rechte von den Vorgaben ab. Der Debian-Standard umask 0022 führt zu 644 für Dateien und 755 für Verzeichnisse. Prüfen mit dem Befehl umask (ohne Argument).Ein Container schreibt nicht ins Volume.
Der Prozess im Container läuft unter einer bestimmten UID (oft nicht root). Setze den Besitzer des Host-Verzeichnisses passend:
Nachlesen: Linux-Benutzer, Gruppen & Dateirechte verstehen →chown -R 1000:1000 ./data – die richtige UID nennt die Doku des Images (Umgebungsvariablen wie PUID/PGID).usermod hat den Benutzer aus Gruppen geworfen.
Du hast
Nachlesen: Linux-Benutzer, Gruppen & Dateirechte verstehen →-G ohne -a benutzt. -G ersetzt die Nebengruppen. Immer usermod -aG verwenden. Reparatur: die fehlenden Gruppen mit usermod -aG gruppe1,gruppe2 benutzer wieder ergänzen.Die deutsche Suche liefert nach dem Modellwechsel wirre Treffer.
Die Fotos sind noch (oder teilweise) mit dem alten Modell indexiert – alte und neue Vektoren vertragen sich nicht. Unter Auftrags-Schlangen → Intelligente Suche den Lauf Alle starten und abwarten, bis die Warteschlange leer ist. Genau dieser gemischte Zustand entsteht auch, wenn du nur speicherst und den Neu-Index vergisst.
Nachlesen: Immich optimieren (Teil 2) →Mit einem nllb-…-Modell ist die Suche nicht besser als vorher.
Bekanntes Verhalten in v3.1.0: Die Sprachangabe, die diese Modelle erwarten, lässt sich in Immich nicht setzen (siehe Warn-Box in Schritt 3). Auf ein
Nachlesen: Immich optimieren (Teil 2) →XLM-…- oder SigLIP2-Modell wechseln und neu indexieren.Der ML-Container beendet sich nach dem Modellwechsel mit exit 137.
Out of Memory: Das neue Modell passt nicht mehr neben Server, Datenbank und deine übrigen Dienste. Entweder ein kleineres Modell wählen oder mehr RAM – das XLM-Basis-Modell braucht im Betrieb real rund 2 GB nur für den ML-Container.
Nachlesen: Immich optimieren (Teil 2) →Die externe Bibliothek bleibt nach dem Scan leer.
Fast immer stimmt der Pfad nicht: Als Importpfad gehört der Container-Pfad (
Nachlesen: Immich optimieren (Teil 2) →/mnt/archiv) hinein, nicht der Host-Pfad. Prüfe mit docker compose exec immich-server ls /mnt/archiv, ob der Container die Dateien überhaupt sieht – kommt dort nichts, fehlt der Volume-Eintrag oder das docker compose up -d nach der Änderung.Das Handy sichert nur, wenn die App offen ist.
Auf Android killt die Akku-Optimierung den Hintergrund-Dienst (App ausnehmen, siehe Schritt 1); auf iOS fehlt die Hintergrundaktualisierung oder iOS priorisiert die App herunter – öfter öffnen hilft tatsächlich. Und: Standardmäßig wird nur im WLAN gesichert – unterwegs „fehlen" Fotos also nur scheinbar.
Nachlesen: Immich optimieren (Teil 2) →Browser meldet NET::ERR_CERT_AUTHORITY_INVALID, curl sagt self-signed certificate.
Der Server liefert das eingebaute Traefik-Notzertifikat (
Nachlesen: Wie HTTPS funktioniert →TRAEFIK DEFAULT CERT) aus, weil die Ausstellung fehlschlug. Fast immer: Der A-/AAAA-Record zeigt auf die falsche IP (dig DEINE_DOMAIN prüfen) oder Port 80 ist in der Firewall zu – die HTTP-01-Challenge kommt nie an. Die genaue Ursache steht in den Traefik-Logs: docker compose logs traefik | grep -i acme.Im issuer steht (STAGING) Ersatz Emmer YR2.
Die Test-CA von Let’s Encrypt ist noch aktiv – Browser vertrauen ihr absichtlich nicht. Staging-Zeile aus der Traefik-Konfiguration entfernen,
Nachlesen: Wie HTTPS funktioniert →acme.json leeren, Container neu starten (Details im Traefik-Tutorial).certificate has expired.
Die automatische Erneuerung scheitert seit mindestens 30 Tagen – gleiche Ursachenliste wie beim ersten Fehler, nur lange unbemerkt. Falls die Meldung nur auf einem Gerät auftaucht: dessen Systemuhr prüfen, TLS ist zeitkritisch.
Nachlesen: Wie HTTPS funktioniert →Let’s Encrypt meldet too many certificates already issued.
Rate-Limit gerissen, meist durch Experimentier-Schleifen gegen die Produktiv-CA. Auf die Staging-CA wechseln, bis das Setup steht – und
Nachlesen: Wie HTTPS funktioniert →acme.json ins Backup nehmen, statt Zertifikate neu auszustellen.unable to get local issuer certificate auf einem alten Client.
Dem System fehlt das Root-Zertifikat aus Schritt 3 – der Root Store ist veraltet. Auf Debian:
Nachlesen: Wie HTTPS funktioniert →apt update && apt install ca-certificates.Der Container startet nicht, Log sagt „listen udp :53: bind: address already in use".
systemd-resolved (oder ein anderer DNS-Dienst) belegt Port 53. Stub-Listener abschalten wie in
Schritt 1, danach docker compose up -d erneut.docker compose up scheitert mit „cannot assign requested address" für 10.8.0.1.
Das
WireGuard-Interface
Nachlesen: AdGuard Home einrichten →wg0 mit 10.8.0.1 existiert (noch) nicht – Docker kann den Port nicht an eine
nicht vorhandene Adresse binden. Zuerst das WireGuard-VPN
einrichten und wg0 hochfahren (ip -br addr show wg0 muss 10.8.0.1 zeigen), dann den Container
starten.Nach dem Setup ist die Weboberfläche nicht mehr erreichbar.
Im Assistenten wurde der Admin-Port
auf 80 (Vorschlag) statt auf 3000 gesetzt – Traefik leitet aber auf 3000. In
Nachlesen: AdGuard Home einrichten →./conf/AdGuardHome.yaml unter http: die address auf 0.0.0.0:3000 korrigieren und docker compose restart.DNS filtert nicht, obwohl das Gerät verbunden ist.
Der Browser nutzt DNS-over-HTTPS (DoH)
und umgeht damit deinen Server komplett – Firefox und Chrome haben das teils standardmäßig aktiv. In
den Browser-Einstellungen „Sicheres DNS" / „DNS über HTTPS" deaktivieren. Prüfen kannst du das mit
Nachlesen: AdGuard Home einrichten →dig @10.8.0.1 … (greift immer).Eine Website ist plötzlich kaputt (leere Seiten, fehlende Bilder, kein Login).
Overblocking –
eine Sperrliste blockt eine Domain, die die Seite wirklich braucht. Im Abfrageprotokoll die
gesperrte Domain suchen, per Rechtsklick/Menü freigeben (Ausnahme) oder die zu aggressive Liste
deaktivieren.
Nachlesen: AdGuard Home einrichten →Der Runner startet neu und meldet „cannot ping the docker daemon … certificate is valid for docker, …, not fjr-docker".
Der DinD-Dienst heißt anders als
Nachlesen: Forgejo Actions: eigener CI/CD-Runner mit Docker →docker, aber sein TLS-Zertifikat
ist auf docker ausgestellt. Nenne den DinD-Service exakt docker (wie oben) und sprich ihn
über DOCKER_HOST: tcp://docker:2376 an – dann passt der Name zum Zertifikat.Der Job startet, scheitert aber beim actions/checkout mit einem Verbindungsfehler.
Der Runner
wurde mit einer internen Instanz-URL (
Nachlesen: Forgejo Actions: eigener CI/CD-Runner mit Docker →http://forgejo:3000) registriert. Die Job-Container im
DinD können diesen Namen nicht auflösen. Neu registrieren mit der öffentlichen URL
https://DEINE_DOMAIN (.runner-Datei im Volume vorher löschen oder das Volume neu anlegen).Der Runner erscheint gar nicht in der Übersicht / die Registrierung schlägt fehl.
Falscher oder
bereits verbrauchter Token, oder der Runner erreicht Forgejo nicht. Frischen Token holen (Schritt 1)
und prüfen, dass der Runner-Container
Nachlesen: Forgejo Actions: eigener CI/CD-Runner mit Docker →https://DEINE_DOMAIN erreicht (docker compose run --rm runner wget -qO- https://DEINE_DOMAIN/api/healthz).Ein Job bleibt ewig „wartend" (pending).
Kein Runner hat ein passendes Label. Der Workflow
nutzt
Nachlesen: Forgejo Actions: eigener CI/CD-Runner mit Docker →runs-on: docker, der Runner muss also das Label docker tragen. Labels beim Registrieren
prüfen; in der Runner-Übersicht werden die Labels je Runner angezeigt.actions/checkout findet die Action nicht.
Forgejo lädt Actions aus einem konfigurierten
Register (standardmäßig
Nachlesen: Forgejo Actions: eigener CI/CD-Runner mit Docker →data.forgejo.org). Ist der Server komplett vom Internet abgeschnitten,
schlägt das fehl. Ausgehenden HTTPS-Zugriff erlauben oder Actions in einem internen Register
spiegeln.mail-tester zeigt „reverse DNS does not match".
Der PTR-Eintrag fehlt, ist noch nicht propagiert
oder passt nicht zum A-Record. PTR im Provider-Panel auf
Nachlesen: E-Mail-Zustellbarkeit einrichten →mail.DEINE_DOMAIN setzen und mit dig -x
prüfen; sicherstellen, dass mail.DEINE_DOMAIN vorwärts auf dieselbe IP zeigt.DKIM schlägt fehl (DKIM: FAIL oder „no signature").
Der DNS-Record ist falsch übernommen
(wirklich abgeschnittener Schlüssel, falscher Selector) oder noch nicht propagiert. Den Wert exakt
aus der Mailserver-UI kopieren, Selector im Record (
Nachlesen: E-Mail-Zustellbarkeit einrichten →SELECTOR._domainkey) mit dem im Server
konfigurierten abgleichen, dann dig gegenprüfen. Dass dig den Schlüssel als zwei Blöcke in
Anführungszeichen zeigt, ist dabei normal und kein Fehler – siehe Schritt 3.SPF „permerror" oder „too many DNS lookups".
Mehrere SPF-Records, oder zu viele
Nachlesen: E-Mail-Zustellbarkeit einrichten →include:-Verschachtelungen (Limit: 10 DNS-Lookups). Mit dig +short TXT DEINE_DOMAIN | grep spf1
prüfen, ob wirklich nur eine Zeile zurückkommt, auf einen SPF-Record konsolidieren und
unnötige include: entfernen.Mails an Outlook/Hotmail landen im Spam oder werden abgewiesen.
Kommt eine harte Abweisung mit
Nachlesen: E-Mail-Zustellbarkeit einrichten →550 5.7.515 Access denied, sending domain … does not meet the required authentication level, ist
es kein Reputationsproblem, sondern Microsofts Authentifizierungsregel ab 5.000 Mails pro Tag –
SPF und DKIM müssen bestehen und ein ausgerichteter DMARC-Record (mindestens p=none) vorhanden
sein; die Schwelle klebt an der Domain, auch wenn du später weniger sendest. Landen die Mails
dagegen nur im Junk-Ordner, ist Microsoft schlicht streng mit neuen IPs: Geduld, wenig aber
regelmäßig senden, ggf. Microsofts SNDS-/JMRP-Programm nutzen.Deine IP steht auf einer Blockliste.
Die IP war vor dir bei einem Spammer, oder ein Postfach von
dir versendet Spam. Auf den gängigen Blocklist-Checkern prüfen, bei berechtigtem Fund über das
jeweilige Delisting-Formular entfernen lassen – und die Ursache (kompromittiertes Konto) abstellen.
Nachlesen: E-Mail-Zustellbarkeit einrichten →Die Weboberfläche auf Port 8080 antwortet nicht.
Der Container ist noch am Hochfahren oder Port
8080 ist belegt/geblockt.
Nachlesen: Stalwart: der schlanke Mailserver in einem Container →docker compose ps prüfen, docker compose logs lesen und
sicherstellen, dass die Firewall Port 8080 (und später 443)
durchlässt. Bleibt die Log-Ausgabe nach dem Setup komplett leer, steht das Log-Ziel noch auf Log
file – in der Konsole unter Settings → Telemetry → Tracers auf Console umstellen und neu
starten.Ich habe das Bootstrap-Passwort verpasst.
Es wird nur einmal geloggt. Setze in der
Nachlesen: Stalwart: der schlanke Mailserver in einem Container →compose.yaml ein STALWART_RECOVERY_ADMIN=admin:DEIN_PASSWORT unter environment: und starte
mit docker compose up -d neu – damit hast du ein festes Recovery-Admin-Konto.Kein TLS-Zertifikat, die HTTPS-Adresse zeigt eine Warnung.
Entweder erreicht Let’s Encrypt
deinen Server nicht auf Port 443 (Stalwart nutzt die TLS-ALPN-01-Challenge über 443), oder einer
der fünf Hostnamen aus Schritt 1 fehlt im DNS. Das Log nennt den Schuldigen beim Namen:
Nachlesen: Stalwart: der schlanke Mailserver in einem Container →ACME authentication error … NXDOMAIN looking up A for autoconfig.DEINE_DOMAIN. Fehlende Records
nachtragen, Port 443 in der Firewall öffnen – Stalwart wiederholt die Zertifikatsanforderung
danach automatisch.Mails nach außen bleiben hängen, Logs zeigen Timeouts auf Port 25.
Dein Provider sperrt
ausgehenden SMTP-Verkehr. Bei netcup ist die Default-Policy „netcup Mail block" (Port 25/465/587)
schuld: Im SCP unter Firewall → Policys dem Server dieses netcup-Template abnehmen – kein
Ticket nötig, siehe netcup-Firewall einrichten. Ohne das
ist keine Zustellung an fremde Server möglich.
Nachlesen: Stalwart: der schlanke Mailserver in einem Container →Andere Server nehmen deine Mails nicht an oder sie landen im Spam.
Fehlender oder falscher
PTR-Eintrag, kein SPF/DKIM/DMARC. Das ist kein Fehler von Stalwart, sondern Sache der
DNS-/Reputations-Konfiguration – siehe das Tutorial zur
E-Mail-Zustellbarkeit.
Nachlesen: Stalwart: der schlanke Mailserver in einem Container →generate_config.sh bricht mit Cannot find command 'jq' ab.
Das Paket
Nachlesen: Eigener Mailserver mit Mailcow: Setup von Grund auf →jq fehlt. sudo apt install -y jq und den Generator erneut starten.Der Generator meldet „User declined to create daemon.json" und bricht ab.
Auf Hosts mit aktivem
IPv6 hast du die Frage nach der IPv6-fähigen Docker-Konfiguration mit
Nachlesen: Eigener Mailserver mit Mailcow: Setup von Grund auf →n beantwortet – ohne sie
läuft mailcow dort nicht, sonst droht ein offenes Relay. Lege /etc/docker/daemon.json mit
{"ipv6": true} an (Docker 28 und neuer), starte Docker mit sudo systemctl restart docker neu und
führe ./generate_config.sh erneut aus – oder bestätige die Frage beim zweiten Anlauf einfach mit
Enter, dann erledigt der Generator beides selbst.Die Webmail antwortet nur mit Unauthorized.
SOGo kennt deine Mail-Domain nicht: Es liest die
Domainliste ausschließlich beim Start und wurde nach dem Anlegen der Domain nicht neu gestartet – in
seinen Logs steht
Nachlesen: Eigener Mailserver mit Mailcow: Setup von Grund auf →No authentication sources defined - nobody will be able to login. Starte SOGo
über E-Mail → SOGo neustarten neu. Bleibt es dabei, hängt noch ein fehlgeschlagener Login im
Cache: docker compose restart memcached-mailcow sogo-mailcow.Kein Zertifikat, acme-mailcow startet immer wieder neu.
Let’s Encrypt erreicht deinen Server
nicht auf Port 80, oder der A-Record von
Nachlesen: Eigener Mailserver mit Mailcow: Setup von Grund auf →mail.DEINE_DOMAIN stimmt nicht. Prüfe mit docker compose logs acme-mailcow, ob der Hostname und die IP passen, und dass Port 80 durch UFW und die
netcup-Firewall offen ist.Mails nach außen werden nicht zugestellt, Logs zeigen Timeouts auf Port 25.
Dein Provider sperrt
ausgehenden SMTP-Verkehr (üblich als Spam-Schutz). Bei netcup ist es die Default-Policy „netcup Mail
block" (Port 25/465/587): Im SCP unter Firewall → Policys dem Server dieses netcup-Template
abnehmen – kein Support-Ticket nötig, Details in
netcup-Firewall einrichten. Ohne das kannst du keine Mails
an fremde Server senden – Empfang und lokale Zustellung funktionieren trotzdem.
Nachlesen: Eigener Mailserver mit Mailcow: Setup von Grund auf →Ports 80/443 lassen sich nicht binden (address already in use).
Auf dem Host läuft schon ein
Webserver oder Reverse Proxy (z. B. Traefik). Für dieses Rezept gehört mailcow auf einen eigenen
Server. Alternativ bindest du den nginx mit
Nachlesen: Eigener Mailserver mit Mailcow: Setup von Grund auf →HTTP_BIND/HTTPS_BIND und HTTP_PORT/HTTPS_PORT
auf einen lokalen Port um und stellst mailcow hinter den Proxy – das beschreibt
mailcows Traefik-Anleitung.
Die Mail-Ports liegen in beiden Fällen weiterhin direkt am Host.Container starten träge oder werden vom Kernel beendet (OOM).
Zu wenig RAM. Auf mindestens 6–8
GB gehen oder ClamAV in der
Nachlesen: Eigener Mailserver mit Mailcow: Setup von Grund auf →mailcow.conf (SKIP_CLAMD=y) deaktivieren – der Virenscanner ist der
größte Speicherfresser.Die App meldet „Cannot connect" oder der Web-Client bleibt leer.
Die
Nachlesen: ntfy einrichten →NTFY_BASE_URL passt nicht
zur aufgerufenen Adresse. Sie muss exakt deine öffentliche HTTPS-URL sein
(https://ntfy.DEINE_DOMAIN, ohne Slash am Ende). Nach einer Änderung docker compose up -d
erneut ausführen.curl liefert HTTP 401 oder 403.
Bei
Nachlesen: ntfy einrichten →deny-all sind fehlende oder falsche Zugangsdaten der
häufigste Fehler. Benutzer/Passwort prüfen (docker exec ntfy ntfy user list) und beim Senden -u BENUTZER:PASSWORT bzw. den Bearer-Token mitgeben. Ein 403 bedeutet, dass der Benutzer existiert,
aber keine Rechte auf dieses Thema hat – dann mit ntfy access Rechte vergeben.Nachrichten kommen im Browser an, aber nicht als Push aufs Handy, wenn der Tab zu ist.
Browser-Push braucht erteilte Benachrichtigungsrechte und einen aktiven Service Worker; das ist
unzuverlässig, sobald der Tab geschlossen ist. Für echtes „unterwegs"-Push die ntfy-App verwenden –
sie hält die Verbindung im Hintergrund.
Nachlesen: ntfy einrichten →502 Bad Gateway von Traefik.
Der Container ist noch nicht bereit oder hört auf dem falschen
Port. Prüfe
Nachlesen: ntfy einrichten →docker compose logs ntfy und dass das Label loadbalancer.server.port=80 gesetzt ist
– ntfy lauscht im Container auf Port 80 (NTFY_LISTEN_HTTP=":80").429 Too Many Requests bei vielen Nachrichten kurz hintereinander.
ntfy begrenzt standardmäßig
die Rate pro Absender, um Missbrauch zu verhindern. Bei einem privaten Server mit eigenen Skripten
stößt du selten daran – ein Schleifen-Skript ohne Pause aber schon. Nachrichten bündeln statt im
Sekundentakt zu feuern, oder die Limits gezielt über die
Nachlesen: ntfy einrichten →NTFY_VISITOR_*-Umgebungsvariablen anheben
(in der ntfy-Doku unter „Rate limiting" beschrieben). NTFY_BEHIND_PROXY: "true" ist Voraussetzung,
damit das Limit pro echter IP statt pro Traefik-Container greift.Der Container schreibt, aber der Bind-Mount-Ordner auf dem Host bleibt leer.
Du hast einen
relativen Pfad benutzt, der woanders zeigt als gedacht, oder Docker hat den Pfad neu als leeren
Ordner angelegt. Bei
Nachlesen: Docker-Volumes vs. Bind-Mounts →docker run Bind-Mounts immer mit absolutem Pfad angeben
(/opt/app/config, nicht config). Existiert dieser Host-Pfad noch nicht, legt Docker ihn
stillschweigend als leeren Ordner an – prüfe also mit ls, dass du wirklich den richtigen erwischt
hast. In der compose.yaml sind ./-Pfade dagegen völlig in Ordnung – sie sind relativ zur
compose.yaml und damit eindeutig. Achtung außerdem: docker run -v config:/data (ohne / oder
./ davor) ist kein Bind-Mount, sondern legt ein Named Volume namens config an.Permission denied, sobald der Container in den Mount schreiben will.
Der Prozess im Container
läuft unter einer anderen UID als der Besitzer des Host-Ordners – typisch bei Bind-Mounts. Bei Named
Volumes tritt das selten auf (Docker setzt die Rechte). Bei Bind-Mounts den Ordner dem passenden
Benutzer geben (
Nachlesen: Docker-Volumes vs. Bind-Mounts →chown -R 1000:1000 /opt/app/data) oder im Image die user:-Angabe der Compose
nutzen.Nach docker compose down sind alle Daten weg.
Du hast
Nachlesen: Docker-Volumes vs. Bind-Mounts →docker compose down -v benutzt – das
-v löscht die Named Volumes mit. Für einen normalen Neustart ohne -v arbeiten. -v bewusst
nur einsetzen, wenn du wirklich bei null anfangen willst.docker system prune hat Daten gelöscht.
docker volume prune bzw. docker system prune --volumes entfernt Volumes, an denen gerade kein Container hängt. Bei docker volume prune sind
benannte Volumes standardmäßig geschützt – gelöscht werden nur anonyme Volumes; benannte
fallen erst mit --all/-a weg. (Bei docker system prune steuert -a/--all dagegen die
Images, nicht die benannten Volumes.) Ein weiteres starkes Argument fürs Benennen – ein
sk-demo-vol übersteht ein versehentliches docker volume prune, ein anonymes Volume nicht.
Trotzdem prune mit Volumes nur laufen lassen, wenn alle wichtigen Stacks aktiv sind, oder gezielt
mit docker volume rm entfernen.Der Browser zeigt einen Zertifikatsfehler oder 404 page not found.
Traefik hat das
Let’s-Encrypt-Zertifikat noch nicht geholt, oder der DNS-Record zeigt nicht auf den Server. Prüfe
mit
Nachlesen: Matomo selbst hosten →dig statistik.DEINE_DOMAIN, dass die IP stimmt, und sieh in die Traefik-Logs. Den genauen
Container-Namen aus deinem Traefik-Setup findest du mit docker ps | grep traefik, dann docker logs <container-name> (bei uns z. B. docker logs traefik-traefik-1). Die HTTP-Challenge
scheitert, wenn Port 80 nicht von außen erreichbar ist – kontrolliere deine
Firewall und die
netcup-Firewall.Der Installer meldet SQLSTATE... Connection refused oder hängt bei der Datenbank.
MariaDB war
beim ersten Start noch nicht bereit. Gib der DB einen Moment und lade die Seite neu. Prüfe mit
Nachlesen: Matomo selbst hosten →docker compose logs db, ob dort ready for connections steht. Erscheint stattdessen ein
Zugangsfehler, passen DB_PASSWORD in der .env und die bereits angelegte DB nicht mehr zusammen –
dann hilft ein sauberer Neustart mit docker compose down -v (Achtung: löscht die Daten) und
docker compose up -d.Warnung „Es sieht so aus, als ob die trusted_hosts-Einstellung nicht korrekt ist".
Matomo
prüft aus Sicherheitsgründen, unter welchem Hostnamen es aufgerufen wird. Die Warnung erscheint,
wenn du die Domain wechselst. Bestätige den korrekten Hostnamen über den Button in der Meldung –
Matomo trägt ihn dann in
Nachlesen: Matomo selbst hosten →config/config.ini.php ein.Im Dashboard tauchen keine Besuche auf.
Der Tracking-Code fehlt, ist falsch eingebaut, oder du
besuchst deine Seite selbst (Matomo ignoriert dich, wenn deine IP ausgeschlossen ist). Öffne deine
Website in einem privaten Fenster und prüfe im Netzwerk-Tab, ob ein Request an
Nachlesen: Matomo selbst hosten →matomo.php
rausgeht. In Matomo hilft Verwaltung → Diagnose → Tracking Fehlschläge.Das Dashboard lädt sehr langsam.
Die On-the-fly-Archivierung rechnet bei jedem Aufruf. Richte
den Archivierungs-Cron aus Schritt 8 ein und stelle die Berichterstellung auf Cron um.
Nachlesen: Matomo selbst hosten →Der Container startet immer wieder neu (Restarting), im Log steht bind: address already in use.
Der eingebaute SSH-Server kollidiert mit sich selbst, weil
Nachlesen: Forgejo: der eigene Git-Server hinter Traefik →SSH_PORT und SSH_LISTEN_PORT nicht
zusammenpassen. Setze beide auf denselben Wert (hier 2222) – dann startet Forgejo sauber.Der Container braucht ewig, bis er healthy ist.
Docker führt den ersten Healthcheck standardmäßig
erst nach dem
Nachlesen: Forgejo: der eigene Git-Server hinter Traefik →interval (30 s) aus – der Container sieht also 30 s+ „ungesund" aus, obwohl Forgejo
längst in ~2 s bereit ist. Die Lösung steckt schon oben in der Compose: start_interval: 2s prüft
während der Startphase im 2-Sekunden-Takt und schaltet sofort auf healthy, sobald die App antwortet.
(Braucht Docker 25+ / Compose v2.20+ – auf Debian 13 gegeben.)Traefik liefert 502 Bad Gateway.
Fast immer der falsche Port: Forgejos Weboberfläche lauscht intern
auf 3000, deshalb muss
Nachlesen: Forgejo: der eigene Git-Server hinter Traefik →loadbalancer.server.port=3000 gesetzt sein und der Container im
proxy-Netz hängen.Klon-Links zeigen localhost oder den falschen Port.
Dann stimmen
Nachlesen: Forgejo: der eigene Git-Server hinter Traefik →ROOT_URL, SSH_DOMAIN oder
SSH_PORT nicht. Korrigiere die Werte in der Compose und starte mit docker compose up -d neu.SSH-Klon scheitert mit Permission denied (publickey).
Der SSH-Server läuft, aber dein
öffentlicher Schlüssel ist noch nicht im Konto hinterlegt (Schritt 6) – oder du hast den Port
Nachlesen: Forgejo: der eigene Git-Server hinter Traefik →2222
vergessen.Der Live-Verifier bleibt auf „Waiting" / keine Treffer im Dashboard.
Prüfe im Browser (Entwicklertools → Netzwerk), ob
Nachlesen: HitKeep selbst hosten →hk.js überhaupt geladen wird und der
Sende-Request danach mit Status 2xx zurückkommt. Häufigste Ursachen: Das Snippet steckt nicht
im HTML, die in HitKeep angelegte Site-Domain passt nicht zum Hostnamen der besuchten Seite,
oder ein Ad-/Tracking-Blocker filtert den Aufruf. Da du unter deiner eigenen Domain hostest
(First-Party), greifen die meisten Blocker nicht – manche Listen kennen aber den Pfad hk.js.Alle Besucher kommen scheinbar von einer einzigen IP, Land und Provider stehen auf „(Unknown)".
Dann greift
Nachlesen: HitKeep selbst hosten →HITKEEP_TRUSTED_PROXIES nicht: Der angegebene Bereich enthält die IP deines Proxys
nicht, und HitKeep wertet nur noch Traefiks Container-IP aus. Prüfe mit
docker network inspect proxy, in welchem Subnetz der Proxy liegt – 172.16.0.0/12 deckt die
üblichen Docker-Netze ab – und starte den Stack neu (docker compose up -d). Danach zählt wieder
die echte Client-IP aus dem X-Forwarded-For-Header.Traefik liefert 404 oder 502.
Ein
Nachlesen: HitKeep selbst hosten →404 heißt meist, dass die Router-Regel nicht greift – prüfe, dass Host(...) deine echte
Domain enthält und der Container im proxy-Netz hängt. Ein 502 deutet auf den falschen Port:
HitKeep lauscht intern auf 8080, deshalb muss loadbalancer.server.port=8080 gesetzt sein.Nach dem Login landest du wieder auf der Anmeldeseite (Login-Schleife).
Das ist fast immer eine Diskrepanz bei
Nachlesen: HitKeep selbst hosten →HITKEEP_PUBLIC_URL: Der Wert muss exakt der Adresse
entsprechen, über die du HitKeep aufrufst (inklusive https://, ohne abschließenden Slash).
Korrigiere die Variable und starte den Container neu.Der Container startet nicht bzw. ist nicht healthy.
Sieh in die Logs:
Nachlesen: HitKeep selbst hosten →docker compose logs -f hitkeep. Ein fehlendes oder leeres
HITKEEP_JWT_SECRET ist eine typische Startbremse – erzeuge eines wie in Schritt 1 und trage
es ein.In wg show erscheint nie ein latest handshake.
Der UDP-Port ist nicht erreichbar oder
die Schlüssel passen nicht. WireGuard ist bei falschen Schlüsseln stumm – es gibt keine
Fehlermeldung, nur keinen Handshake. Prüfe:
Nachlesen: WireGuard-VPN einrichten →sudo ufw status (Port 51820/udp offen?), die
netcup-Firewall (eingehend UDP 51820), den Endpoint im Client (richtige öffentliche IP?) und
dass privater und öffentlicher Schlüssel nicht vertauscht sind.Handshake ist da, aber im Full-Tunnel kommt kein Internet an.
Fast immer das Routing/NAT.
Ist
Nachlesen: WireGuard-VPN einrichten →net.ipv4.ip_forward=1 gesetzt (sysctl net.ipv4.ip_forward)? Läuft Docker mit – oder ist
UFW aktiv –, greift die FORWARD-DROP-Falle aus dem Warnkasten oben; beide setzen die
Forward-Policy auf DROP. Die Regeln müssen mit -I FORWARD 1 vor den bestehenden Ketten
stehen. Stimmt das externe Interface im MASQUERADE (eth0 vs. etwas anderes)?Full-Tunnel steht, aber DNS-Anfragen laufen weiter am Tunnel vorbei (DNS-Leak).
Ohne
Nachlesen: WireGuard-VPN einrichten →DNS =-Zeile fragt dein Gerät weiter die DNS-Server deines lokalen Netzes – im offenen WLAN sieht
der Betreiber also weiter, welche Domains du aufrufst. Prüfe unter Linux mit resolvectl status, welcher DNS-Server dem Interface wg0 zugeordnet ist, oder mach einen Leak-Test (z. B.
auf dnsleaktest.com): Tauchen dort fremde Resolver auf, trägst du in der Client-Konfig einen
echten Resolver ein (DNS = 1.1.1.1) – oder den Server selbst (10.8.0.1), falls dort ein
eigener DNS-Resolver läuft.Der Tunnel steht, aber große Übertragungen (SSH, HTTPS, Downloads) hängen oder brechen ab.
Ein MTU-Problem.
Nachlesen: WireGuard-VPN einrichten →wg-quick setzt die MTU auf 1420; in manchen Netzen (DS-Lite, bestimmte
Mobilfunknetze) ist das noch zu hoch. Setz testweise MTU = 1412 oder 1280 in der
[Interface]-Sektion des Clients.wg-quick up meldet resolvconf: command not found.
Die
Nachlesen: WireGuard-VPN einrichten →DNS =-Zeile braucht
resolvconf. Entweder sudo apt install openresolv installieren oder die DNS-Zeile
entfernen, wenn du den VPN-DNS nicht brauchst.Die Verbindung schläft ein, sobald das Handy kurz nichts sendet.
Der Client sitzt hinter
NAT/CGNAT.
Nachlesen: WireGuard-VPN einrichten →PersistentKeepalive = 25 in der Client-Konfig hält die Verbindung offen.Deine Werte liegen deutlich unter unseren, besonders bei der CPU.
Ein VPS teilt sich die
physische CPU. Prüfe die Steal Time (
Nachlesen: netcup VPS 1000 G12 im Benchmark →vmstat 1, Spalte st) und top (Zeile %st). Ist
sie dauerhaft hoch, rechnen gerade Nachbarn auf demselben Host. Miss zu einer anderen Tageszeit
erneut – oft ist der Unterschied dann weg.Die Disk-Werte sind absurd hoch (z. B. „10 GB/s random read").
Dir fehlt
Nachlesen: netcup VPS 1000 G12 im Benchmark →--direct=1 –
dann misst fio den RAM-Cache, nicht die NVMe. Immer mit direktem I/O testen, sonst sind die
Zahlen wertlos.lsblk zeigt für vda die Spalte ROTA=1 („rotierend") – ist das eine Festplatte statt
NVMe?
Nein. Das ist ein Virtualisierungs-Artefakt: Der virtio-Treiber meldet die
virtuelle Disk pauschal als rotierend. Die gemessenen 100k+ IOPS und 4 GB/s beweisen, dass
echter Flash-Speicher dahintersteht.
Nachlesen: netcup VPS 1000 G12 im Benchmark →Der Download ist viel langsamer als 2 Gbit/s.
Miss gegen einen nahen, schnellen Server
(z. B. Falkenstein). Ein weit entferntes Ziel oder eine langsame Gegenstelle begrenzt die
Messung, nicht dein VPS. Ein einzelner
Nachlesen: netcup VPS 1000 G12 im Benchmark →curl-Stream schöpft zudem nicht immer die volle
Bandbreite aus.Jeder Lauf liefert andere Zahlen.
Normal – Benchmarks schwanken. Miss mehrfach, verwirf den
ersten („warmen") Lauf und nimm den Median. Vergleiche außerdem nur gleiche Tool-Versionen
und Parameter miteinander.
Nachlesen: netcup VPS 1000 G12 im Benchmark →docker compose pull zieht kein neues Image, obwohl es eine neue Version gibt.
Dein Tag zeigt
auf eine feste Version (
Nachlesen: Den ganzen Docker-Stack sicher aktuell halten →:1.37.2) oder auf einen Major-Tag (:18), unter dem es nur ein neues
Major gäbe. pull holt nur, was derselbe Tag inzwischen zeigt. Für einen Versionssprung
musst du den Tag in der compose.yaml selbst anheben.Die App startet nach dem Update nicht mehr oder wirft Datenbank-Fehler.
Meist ein Breaking
Change oder eine fehlgeschlagene Migration. Prüfe
Nachlesen: Den ganzen Docker-Stack sicher aktuell halten →docker compose logs, gleiche mit den
Release-Notes ab. Tag auf die alte Version zurücksetzen und up -d; hat die neue Version die Daten
schon migriert, das Backup aus Schritt 3 einspielen.Diun meldet nichts, obwohl Updates existieren.
Prüfe, dass die Container das Label
Nachlesen: Den ganzen Docker-Stack sicher aktuell halten →diun.enable=true tragen und Diun den Socket lesen kann (DIUN_PROVIDERS_DOCKER=true, Socket
gemountet). Für neuere Versions-Tags braucht der Container zusätzlich diun.watch_repo=true –
ohne das sieht Diun nur Änderungen am exakt gepinnten Tag. Und: Was Diun beim ersten Mal
sieht, wird nur in die Datenbank geschrieben, nicht gemeldet (watch.firstCheckNotif ist
false) – zum Testen des Meldewegs einmalig DIUN_WATCH_FIRSTCHECKNOTIF=true setzen.Die Festplatte läuft voll, obwohl du regelmäßig docker image prune machst.
docker image prune räumt nur dangling Images ab, nicht die alten getaggten Versionen. Entferne sie gezielt
mit docker rmi <image>:<tag> oder – mit Bedacht – docker image prune -a. Auch der Build-Cache
(docker builder prune) kann wachsen.Beim Ziehen kommt toomanyrequests / ein Docker-Hub-Rate-Limit.
diun.watch_repo=true auf
vielen Images fragt viele Tags ab. Setz das Watch-Intervall seltener (z. B. einmal täglich) und
grenze mit diun.include_tags auf relevante Versionen ein, statt das ganze Repo abzuklopfen.Eine frisch gesetzte Sperre wirkt nicht, die IP bekommt weiter 200.
Der Bouncer cached
die Entscheidungen und zieht neue im stream-Modus erst nach dem Pull-Intervall (bis zu ~60
Sekunden). Kurz warten. Wer die Reaktionszeit drücken will, senkt
Nachlesen: CrowdSec: moderne, kollaborative Angriffsabwehr →updateIntervalSeconds in
der Middleware (Schritt 3).cscli metrics show acquisition zeigt keine Zeile für die Log-Datei.
CrowdSec liest die
Logs nicht – und weil
Nachlesen: CrowdSec: moderne, kollaborative Angriffsabwehr →cscli leere Tabellen weglässt, fehlt die Zeile komplett statt
Lines read: 0 zu zeigen. Häufigste Ursache: der Container startete, bevor die
access.log existierte; dann steht in docker logs crowdsec die Zeile
No matching files for pattern /var/log/traefik/access.log, und CrowdSec nimmt die Datei auch
später nicht von allein auf – cd ~/crowdsec && docker compose restart behebt das. Prüfe
sonst, dass Traefik wirklich nach /var/log/traefik/access.log schreibt (Schritt 1), dass
beide Container denselben Host-Pfad einbinden und dass die acquis.yaml genau diesen Pfad
nennt.Nach dem Neustart von Traefik bekommt jede App 403 – auch du selbst.
Der Bouncer konnte
die LAPI beim Start nicht erreichen und blockt dann im Zweifel, statt ungeschützt
durchzulassen. Im Traefik-Log steht dazu
Nachlesen: CrowdSec: moderne, kollaborative Angriffsabwehr →crowdsecQuery:unreachable mit der URL
http://crowdsec:8080/v1/decisions/stream. Prüfe mit docker ps, dass der crowdsec-Container
Up ist – sobald der nächste Pull klappt (bis zu ~60 Sekunden), gehen die Anfragen von allein
wieder durch. Das ist sicher, macht CrowdSec aber zu einer kritischen Komponente: Läuft der
Container nicht, ist deine Seite betroffen. restart: unless-stopped (oben gesetzt) holt ihn
nach einem Server-Neustart automatisch zurück.CrowdSec sperrt lauter harmlose oder gar keine echten Besucher – die erkannte IP ist immer die deines CDNs.
Sitzt ein CDN wie Cloudflare vor Traefik, sieht Traefik nur dessen IP.
Dann die echte Client-IP aus dem
Nachlesen: CrowdSec: moderne, kollaborative Angriffsabwehr →X-Forwarded-For-Header lesen lassen: In der Middleware
forwardedHeadersTrustedIPs mit den CDN-Netzen füllen – sonst sperrst du am Ende das CDN.
Direkt an netcup (ohne CDN) ist hier nichts zu tun.docker compose up -d bei Traefik meldet einen Plugin-Fehler.
Traefik lädt das Plugin
beim Start aus dem Netz. Prüfe, dass der Server raus darf (die
netcup-Firewall sperrt ausgehend nur SMTP, UFW
ebenso wenig) und dass
Nachlesen: CrowdSec: moderne, kollaborative Angriffsabwehr →modulename und version exakt stimmen.CrowdSec sperrt nichts, obwohl die Angriffe in der access.log stehen – oder es sperrt 172.18.0.1.
Dann sieht Traefik die echte Absenderadresse gar nicht. Das passiert bei IPv6-Besuchern, wenn das
Nachlesen: CrowdSec: moderne, kollaborative Angriffsabwehr →proxy-Netz ohne IPv6 angelegt wurde: Docker schiebt die Verbindung dann über einen Hilfsprozess und ersetzt die Quelladresse durch die des Bridge-Gateways. In der access.log steht dann bei allen IPv6-Zugriffen dieselbe 172.x.x.x, und eine Sperre darauf trifft entweder niemanden oder alle. Leg das Netz mit --ipv6 neu an; die Anleitung dafür steht im Reverse Proxy mit Traefik.dd hat die falsche Festplatte überschrieben – Daten weg.
dd fragt nicht nach und
heißt nicht umsonst spöttisch „disk destroyer". Prüfe das Ziel (of=) immer vorher mit
lsblk, und verwechsle nie sda mit sdb. Es gibt kein Rückgängig – im Zweifel lieber
dreimal lesen.kill -9 hat einen Dienst beendet, aber die Datenbank ist danach beschädigt.
-9 gibt
dem Prozess keine Chance, sauber zu schließen. Nutze immer zuerst kill ohne -9 und gib
dem Prozess ein paar Sekunden. Erst wenn er wirklich hängt, folgt die harte Variante.rsync hat viel mehr kopiert (oder gelöscht) als erwartet.
Der abschließende
Schrägstrich entscheidet:
Nachlesen: Die wichtigsten Terminal-Befehle für deinen Server →rsync -a /quelle/ kopiert den Inhalt von quelle, rsync -a /quelle kopiert den Ordner mit hinein. Und --delete löscht im Ziel alles, was in der
Quelle fehlt. Erst mit -n testen, immer.Ein Werkzeug meldet „command not found".
Das Paket ist nicht installiert. Installiere es
(siehe Tipp-Box oben) oder prüfe den Namen. Manche Tools wie
Nachlesen: Die wichtigsten Terminal-Befehle für deinen Server →iotop brauchen zudem sudo,
um überhaupt Daten zu sehen.Nach tmux ist bei erneutem Login „alles weg".
Du hast eine neue Sitzung gestartet
statt dich anzuhängen.
Nachlesen: Die wichtigsten Terminal-Befehle für deinen Server →tmux ls listet laufende Sitzungen, tmux attach -t 0 hängt dich an
die erste. Nur tmux allein erzeugt jedes Mal eine frische.502 Bad Gateway beim Aufruf, obwohl der Container läuft.
Traefik erreicht den
Container, trifft aber den falschen Port. Jellyfin lauscht auf 8096 – prüfe das Label
Nachlesen: Jellyfin selbst hosten →traefik.http.services.jellyfin.loadbalancer.server.port=8096 auf Tippfehler. Kommt
stattdessen nach ein paar Sekunden ein 504 Gateway Timeout, ist der Port nicht das
Problem, sondern das Netzwerk: Dann fehlt networks: [proxy], und Traefik läuft gegen eine
Adresse, die es gar nicht erreichen kann.Die Bibliotheken bleiben leer, obwohl Dateien da sind.
Fast immer ein Rechte-Problem.
Der Container läuft als
Nachlesen: Jellyfin selbst hosten →1000:1000 (Schritt 4), die Medien müssen also diesem Benutzer
gehören: sudo chown -R 1000:1000 /mnt/media. Und: In Jellyfin muss der Container-Pfad
stehen (/media/filme), nicht der Host-Pfad. Danach unter Dashboard → Geplante Aufgaben
„Alle Bibliotheken scannen" starten.Video ruckelt/puffert, docker stats zeigt Jellyfin bei ~100 % CPU.
Es wird
transcodiert. Unter Dashboard → Wiedergabe siehst du im Aktivitätsmonitor, ob
„Transcode" statt „Direct Play" steht. Stell die Client-Qualität auf Original, stell
exotische Codecs auf ein breit unterstütztes Format um, oder gib dem Server mehr (dedizierte)
Kerne.
Nachlesen: Jellyfin selbst hosten →Nach einem Reboot ist die Mediathek weg und Jellyfin zeigt leere Ordner.
Der Block
Storage wurde nicht eingehängt – meist ein fehlender oder falscher
Nachlesen: Jellyfin selbst hosten →fstab-Eintrag (Schritt
2). Prüfe mit df -h /mnt/media und sudo mount -a. Die Zeile muss die UUID verwenden,
nicht /dev/vdb1.Login-Seite lädt, aber die App findet den Server nicht / Links zeigen auf eine interne Adresse.
JELLYFIN_PublishedServerUrl fehlt oder ist falsch. Setz sie in der
compose.yaml auf https://jellyfin.DEINE_DOMAIN und starte mit docker compose up -d neu
(ein restart reicht nicht, damit die Environment-Änderung greift).Ein Target steht in Prometheus auf up = 0 bzw. „DOWN".
Prometheus erreicht den
Exporter nicht. Bei
Nachlesen: Monitoring mit Grafana & Prometheus →cadvisor prüfe, dass er im selben monitoring-Netz läuft und Name
und Port exakt stimmen (cadvisor:8080). Beim node-Job prüfe den extra_hosts-Eintrag
am Prometheus-Service und das Target host.docker.internal:9100 – ohne beides findet
Prometheus den node-exporter im Host-Netz nicht. Nach Änderungen an der prometheus.yml
den Prometheus-Container neu starten: docker compose restart prometheus.Das cAdvisor-Dashboard zeigt teils „No data" oder cAdvisor startet nicht.
Fehlen die
Mounts oder
Nachlesen: Monitoring mit Grafana & Prometheus →privileged: true, sieht cAdvisor die Container nicht. Kontrolliere den
cadvisor-Block (Mounts, devices: /dev/kmsg). Einzelne „No data"-Panels sind normal –
manche Metriken (etwa CPU-Drosselung) gibt es nur, wenn du den Containern CPU-Limits
gesetzt hast.Grafana lädt hinter Traefik nicht richtig – Login schlägt fehl oder das Layout ist kaputt.
Fast immer stimmt
Nachlesen: Monitoring mit Grafana & Prometheus →GF_SERVER_ROOT_URL nicht. Sie muss exakt die öffentliche
Adresse sein (https://grafana.DEINE_DOMAIN). Prüfe außerdem, dass die Traefik-Label
loadbalancer.server.port=3000 gesetzt ist – Grafana lauscht intern auf 3000.Grafana zeigt in den Panels „No data", obwohl die Targets up sind.
Meist der
Zeitbereich. Ein frischer Stack hat noch keine Historie – stell oben rechts „Last 15
minutes" ein und warte ein paar Minuten, bis Daten aufgelaufen sind. Prüfe zudem, dass
beim Dashboard-Import die Prometheus-Datenquelle gewählt war.
Nachlesen: Monitoring mit Grafana & Prometheus →Der Speicherplatz auf dem Server wächst stetig.
Das ist die Prometheus-TSDB. Reduziere
Nachlesen: Monitoring mit Grafana & Prometheus →--storage.tsdb.retention.time (z. B. auf 15d) oder überwache weniger Ziele. Das
prom_data-Volume wächst mit Anzahl der Metriken × Vorhaltezeit.Uploads großer Videos brechen nach etwa einer Minute ab (Fehler 502 oder 499).
Traefiks
Nachlesen: Immich selbst hosten →readTimeout (Standard 60 s) greift. Setz ihn wie in Schritt 4 auf 600s (oder höher) und
starte Traefik neu. Das ist mit Abstand der häufigste Immich-hinter-Proxy-Fehler.Der immich-machine-learning-Container stürzt ab bzw. beendet sich mit „exit 137", Suche
und Gesichtserkennung funktionieren nicht.
Zu wenig RAM – der Container wurde vom System
beendet (Out of Memory). Gib dem Server mehr Speicher, oder deaktiviere ML, indem du
den Service
Nachlesen: Immich selbst hosten →immich-machine-learning aus der compose.yaml entfernst. Immich läuft dann
ohne Gesichtserkennung und intelligente Suche, aber Upload und Zeitleiste funktionieren
normal.Nach einem Update starten die Container nicht mehr oder melden Migrationsfehler.
Server, Machine-Learning und Datenbank müssen auf derselben Version laufen. Setz in der
Nachlesen: Immich selbst hosten →.env die neue IMMICH_VERSION und aktualisiere alle Container gemeinsam (docker compose pull && docker compose up -d). Ein Downgrade nach einer Migration ist nicht
möglich – nur ein Rücksetzen aus dem Backup.Immich zeigt „Wartungsmodus" / „Vorübergehend nicht verfügbar".
Immich v3 startet bei
bestimmten Datenbank-Zuständen in einen Wartungsmodus. Im Log (
Nachlesen: Immich selbst hosten →docker compose logs immich-server) steht dann eine URL mit einem einmaligen Token
(…/maintenance?token=…) – darüber meldest du dich am Wartungsmodus an und wählst „neu
starten" bzw. beendest ihn. Danach ist die normale Oberfläche wieder da.Container startet nicht, „permission denied" beim Datenbank- oder Upload-Verzeichnis.
UPLOAD_LOCATION oder DB_DATA_LOCATION haben die falschen Zugriffsrechte oder liegen auf
einem Netzlaufwerk. Lege beide auf einer lokalen Platte an und stelle sicher, dass Docker
hineinschreiben darf.Beim Login erscheint „Forbidden (403)" oder „CSRF verification failed".
PAPERLESS_URL
ist nicht oder falsch gesetzt. Sie muss exakt deiner HTTPS-Adresse entsprechen
(https://paperless.DEINE_DOMAIN, ohne Schrägstrich am Ende). Nach der Korrektur docker compose up -d.Dateien im Consume-Ordner werden nicht verarbeitet, „permission denied".
Häufigste
Ursache: Die Ordner wurden nicht vorab angelegt (Schritt 3), sondern beim ersten Start vom
Docker-Daemon erzeugt – dann gehören sie
Nachlesen: Paperless-ngx selbst hosten: papierloses Büro mit OCR →root. Mit sudo chown -R $(id -u):$(id -g) ~/paperless/consume ~/paperless/export gehören sie wieder dir. Ansonsten:
USERMAP_UID/USERMAP_GID passen nicht zum Besitzer des Ordners – ermittle deine Kennung
mit id -u und id -g, trag die Werte ein und starte neu.Hochgeladene Dokumente bleiben „in Bearbeitung" hängen.
Die Hintergrundverarbeitung läuft
über Redis. Prüfe, dass der
Nachlesen: Paperless-ngx selbst hosten: papierloses Büro mit OCR →broker-Container läuft, und sieh unter Dateiaufgaben nach
der Fehlermeldung der fehlgeschlagenen Aufgabe.Die Texterkennung liefert Unsinn oder erkennt nichts.
Falsche OCR-Sprache. Setz
Nachlesen: Paperless-ngx selbst hosten: papierloses Büro mit OCR →PAPERLESS_OCR_LANGUAGE=deu (oder deu+eng für gemischte Dokumente). Nur installierte
Sprachen funktionieren.Office-Dokumente (Word, Excel) werden nicht angenommen oder enden im Timeout.
Dafür sind
Gotenberg und Tika zuständig. Prüfe, dass beide Container laufen und
Nachlesen: Paperless-ngx selbst hosten: papierloses Büro mit OCR →PAPERLESS_TIKA_ENABLED=1 samt der beiden Endpoint-Variablen gesetzt ist.Beim Massenimport wird der Server sehr langsam, die CPU ist dauerhaft am Anschlag.
OCR
ist rechenintensiv, und Paperless nutzt standardmäßig alle Kerne. Auf kleinen Servern kannst
du die Last drosseln, indem du die Zahl der Worker bzw. Threads begrenzt
(
Nachlesen: Paperless-ngx selbst hosten: papierloses Büro mit OCR →PAPERLESS_TASK_WORKERS, PAPERLESS_THREADS_PER_WORKER). Dann dauert der Import länger,
aber die Oberfläche bleibt bedienbar.Nach dem Traefik-Neustart erscheint der HSTS-Header nicht in der curl-Ausgabe.
Meist
ist die Middleware nicht am Router. Prüfe, dass die Zeile
Nachlesen: Nextcloud absichern (Teil 2) →traefik.http.routers.nc.middlewares beide Middlewares nennt (nc-dav,nc-secure) und
dass die zwei nc-secure-Header-Labels im nc-app-Block stehen. Danach docker compose up -d nc-app. Traefik übernimmt geänderte Labels erst beim Neu-Erstellen des Containers.Der E-Mail-Test schlägt fehl („Es gab ein Problem beim Senden der E-Mail").
Fast immer
Port/Verschlüsselung oder Authentifizierung. Kombiniere
Nachlesen: Nextcloud absichern (Teil 2) →SSL/TLS mit Port 465 oder
STARTTLS mit Port 587 – nicht kreuzweise. Nutzt dein Anbieter 2FA, brauchst du ein
App-Passwort (siehe Schritt 4). Details stehen im Nextcloud-Log: docker exec -u www-data nc-app php occ log:tail 20.Du kommst nach dem Erzwingen von 2FA selbst nicht mehr rein.
Du hattest noch keinen
zweiten Faktor eingerichtet. Hebe die Pflicht per Kommandozeile auf, richte deinen Faktor
in Ruhe ein und schalte sie danach wieder scharf:
Nachlesen: Nextcloud absichern (Teil 2) →docker exec -u www-data nc-app php occ twofactorauth:enforce --off.Im Brute-Force-Kasten steht eine 172.x.x.x-Adresse statt deiner echten IP.
TRUSTED_PROXIES passt nicht zum tatsächlichen proxy-Subnetz. Ermittle es mit docker network inspect proxy -f '{{(index .IPAM.Config 0).Subnet}}' und trag den Wert in der
nc-app-Umgebung ein (Teil 1, Schritt 2). Sonst sperrt der Brute-Force-Schutz im
Ernstfall den Proxy und damit alle Nutzer.Nach einem Reboot meldet Nextcloud „Redis went away" oder wird sehr langsam.
Der
App-Container ist vor Redis gestartet. Stelle sicher, dass
Nachlesen: Nextcloud absichern (Teil 2) →nc-redis in depends_on
steht (Teil 1) und mit restart: unless-stopped läuft – dann fängt Docker den
Startreihenfolge-Fall selbst ab.„Zugriff über eine nicht vertrauenswürdige Domäne" statt der Login-Seite.
Deine
Domain steht nicht in
Nachlesen: Nextcloud selbst hosten →trusted_domains. Prüfe NEXTCLOUD_TRUSTED_DOMAINS in der
Compose-Datei. Nachträglich setzen geht per occ: docker exec -u www-data nc-app php occ config:system:set trusted_domains 1 --value=cloud.DEINE_DOMAIN.Der Sicherheits-Check meldet „Your web server is not set up properly to resolve .well-known/caldav".
Der CalDAV/CardDAV-Redirect greift nicht. Kontrolliere die
Nachlesen: Nextcloud selbst hosten →nc-dav-Middleware-Labels (Schritt 3) und dass der Router sie über
...routers.nc.middlewares=nc-dav einbindet. Das Regex muss die volle https://…-URL
matchen – redirectregex prüft die komplette URL, nicht nur den Pfad.Warnung „The ‘Strict-Transport-Security’ HTTP header is not set".
Der HSTS-Header
fehlt. Setz ihn als Traefik-Middleware und häng sie an den Router:
Nachlesen: Nextcloud selbst hosten →traefik.http.middlewares.nc-secure.headers.stsSeconds=15552000. Häng sie zusätzlich zur
nc-dav-Middleware an den Router (...routers.nc.middlewares=nc-dav,nc-secure). Der
Header muss vom Proxy kommen, nicht von Nextcloud. In Teil
2 richten wir genau diese
nc-secure-Middleware vollständig ein (inklusive includeSubdomains).Große Uploads brechen ab oder enden mit einem Timeout / „413".
Das PHP-Limit ist zu
klein. Erhöhe
Nachlesen: Nextcloud selbst hosten →PHP_UPLOAD_LIMIT und PHP_MEMORY_LIMIT (Schritt 3) und starte den
Container neu. In seltenen Fällen greifen diese Variablen nicht – dann ein eigenes
php.ini-Snippet ins Image mounten.Beim ersten Start bricht die Installation mit „MySQL server has gone away" oder „Connection refused" ab.
Der App-Container war schneller als die Datenbank. Genau
dagegen ist der
Nachlesen: Nextcloud selbst hosten →healthcheck mit depends_on: condition: service_healthy da – prüfe,
dass beide in deiner Compose-Datei vorhanden sind, und starte mit docker compose up -d
neu.Bad Gateway (502) beim Aufruf von status.DEINE_DOMAIN.
Fast immer fehlt das
Port-Label
Nachlesen: Uptime Kuma installieren →traefik.http.services.kuma.loadbalancer.server.port=3001 oder es steht
ein falscher Port drin. Traefik erreicht den Container dann zwar, klopft aber am
falschen Port an. Label prüfen und docker compose up -d erneut ausführen.404 page not found statt Kuma.
Wie bei jeder App hinter Traefik:
Nachlesen: Uptime Kuma installieren →traefik.enable=true gesetzt? Container im proxy-Netzwerk? Stimmt die Domain in
der Host(...)-Regel und zeigt der DNS-Record status.DEINE_DOMAIN auf den Server?
Das Traefik-Dashboard zeigt unter „HTTP Routers", ob kuma registriert ist.Die Oberfläche lädt, aber die Live-Aktualisierung ruckelt / bricht ab.
Kuma nutzt
WebSockets. Traefik leitet die standardmäßig korrekt weiter – tritt das Problem
trotzdem auf, liegt es meist an einem davorgeschalteten CDN/Proxy (z. B. Cloudflare
im „Proxy"-Modus), der WebSockets blockt. Für den Direktbetrieb hinter Traefik ist
keine Zusatzkonfiguration nötig.
Nachlesen: Uptime Kuma installieren →Nach einem Neuaufsetzen sind alle Monitore weg.
Das
Nachlesen: Uptime Kuma installieren →kuma-data-Volume wurde
gelöscht (z. B. durch docker compose down -v). Alle Konfiguration und Historie
liegt allein in diesem Volume – deshalb steht es im nächsten Abschnitt ganz oben.Der Container beendet sich sofort wieder, das Log sagt No persistent volume!.
Es
fehlt das
Nachlesen: Vaultwarden: eigener Passwortmanager hinter Traefik →volumes:-Mapping. Vaultwarden bricht dann mit dem Kasten „It looks like you
did not configure a persistent volume!" ab und beendet sich mit Exit-Code 1, damit deine
Passwörter nicht in einem flüchtigen Container landen. Ergänze ./vw-data:/data wie in
Schritt 2 und starte neu.Die Web-Oberfläche zeigt „You need to enable HTTPS!" oder der Login scheitert mit Krypto-Fehlern.
Vaultwarden nutzt die Web-Crypto-API des Browsers, die nur in einem
sicheren Kontext (echtes HTTPS) verfügbar ist. Du hast die Seite über
Nachlesen: Vaultwarden: eigener Passwortmanager hinter Traefik →http:// oder
mit ungültigem Zertifikat aufgerufen. Stell sicher, dass Traefik ein gültiges
Let’s-Encrypt-Zertifikat geholt hat (Traefik-Log prüfen) und du die Seite über
https:// erreichst. Die DOMAIN-Variable muss ebenfalls mit https:// beginnen.Das Admin-Panel weist dein Passwort ab, obwohl es stimmt.
Vermutlich sind die
Dollarzeichen im
Nachlesen: Vaultwarden: eigener Passwortmanager hinter Traefik →ADMIN_TOKEN nicht verdoppelt. In der compose.yaml muss aus jedem
$ ein $$ werden. Prüfe mit docker compose exec vaultwarden printenv ADMIN_TOKEN,
wie der Token wirklich im Container ankommt – dort muss wieder ein einfaches $
stehen. (docker compose config hilft hier nicht: Es zeigt die Datei mit den doppelten
$$.) Denk auch daran: Beim Login gibst du das Passwort ein, nicht den Hash.Die Handy-App findet den Server nicht oder meldet „Server-URL ungültig".
Die
Server-URL muss die vollständige
Nachlesen: Vaultwarden: eigener Passwortmanager hinter Traefik →https://-Adresse ohne abschließenden Pfad sein
(https://vault.DEINE_DOMAIN). Prüfe außerdem, ob die Domain von außen per Browser
erreichbar ist und das Zertifikat gültig ist – Apps sind bei Zertifikatsfehlern strenger
als Browser.Trotz SIGNUPS_ALLOWED=false konnte sich jemand registrieren.
Wahrscheinlich wurde
die Einstellung im Admin-Panel gesetzt und überschreibt die Umgebungsvariable, oder der
Container wurde nach der Änderung nicht neu gestartet. Kontrolliere den Wert unter
Settings → General settings im Panel und starte mit
Nachlesen: Vaultwarden: eigener Passwortmanager hinter Traefik →docker compose up -d neu.Du hast dich selbst ausgesperrt.
ignoreip fehlte oder enthielt die falsche IP.
Verbinde dich über die Konsole im netcup SCP (unabhängig von SSH) und entsperre
dich mit sudo fail2ban-client set sshd unbanip DEINE_EIGENE_IP. Trage deine IP
anschließend in ignoreip ein und lade neu. Deshalb steht die Whitelist in Schritt 2
an erster Stelle.fail2ban.service startet nicht (systemctl status zeigt „failed").
Fast immer
ein Tippfehler in
Nachlesen: Fail2ban einrichten →jail.local. Prüfe die Syntax mit sudo fail2ban-client -t
(Testmodus) – der Befehl nennt die fehlerhafte Zeile.Deine Werte aus jail.local greifen nicht.
Es wird nur 10 Minuten gesperrt, oder die
eigene IP fliegt trotz
Nachlesen: Fail2ban einrichten →ignoreip raus. Fast immer fehlt der Reload – der Dienst lief
schon, bevor du die erste eigene Zeile geschrieben hast, und start/enable --now tut
bei einem laufenden Dienst nichts. Was wirklich gilt, zeigen
sudo fail2ban-client get sshd bantime (600 = Debian-Standard, 3600 = deine Stunde)
und sudo fail2ban-client get sshd ignoreip; übernommen wird es mit
sudo systemctl reload fail2ban.Es wird nie jemand gesperrt, obwohl das Log voller Fehlversuche ist.
Prüfe mit
Nachlesen: Fail2ban einrichten →sudo fail2ban-client status sshd, ob Total failed überhaupt steigt. Bleibt es bei
0, findet der Filter die Einträge nicht – meist, weil eine veraltete Anleitung einen
logpath auf eine nicht existierende Datei gesetzt hat. Auf Debian 13 den logpath
aus jail.local entfernen und das Journal nutzen (Schritt 2).Sperren „wirken" nicht – die IP verbindet sich weiter.
Auf Debian 13 sperrt Fail2ban
per nftables (
Nachlesen: Fail2ban einrichten →banaction = nftables aus defaults-debian.conf). Sichtbar wird das
mit sudo nft list table inet f2b-table: Dort steht die Kette f2b-chain und darin ein
Adress-Set addr-set-sshd mit den gesperrten IPs. sudo iptables -L -n | grep f2b
liefert dagegen nichts – das ist kein Fehler, sondern die falsche Werkzeugebene, an
der ältere Anleitungen hängen bleiben. Fehlt die Tabelle ganz, hakt das Zusammenspiel mit
der Firewall – Dienst neu starten und /var/log/fail2ban.log ansehen.subprocess ssh: Host key verification failed beim SFTP-Ziel.
Restic kann den
SSH-Hostkey des Backup-Servers nicht bestätigen, weil er noch nicht bekannt ist.
Verbinde dich einmal manuell (
Nachlesen: Restic-Backups einrichten: verschlüsselt und off-site →ssh BACKUP_BENUTZER@DEIN_BACKUP_HOST) und bestätige
den Fingerprint – oder hinterlege ihn mit ssh-keyscan DEIN_BACKUP_HOST >> ~/.ssh/known_hosts. Danach läuft Restic durch.wrong password oder repository does not exist.
RESTIC_REPOSITORY oder
RESTIC_PASSWORD_FILE ist nicht gesetzt oder zeigt ins Leere – im systemd-Dienst also
die EnvironmentFile prüfen. Ein per Hand gesetztes export gilt nur in der aktuellen
Shell.repository is already locked.
Ein abgebrochener Lauf hat eine Sperre
hinterlassen. Prüfe, dass wirklich kein Backup mehr läuft, dann
Nachlesen: Restic-Backups einrichten: verschlüsselt und off-site →restic unlock.
Niemals blind entsperren, während parallel ein Lauf aktiv ist.Das Backup wird riesig / sichert Unsinn.
Grenze mit
Nachlesen: Restic-Backups einrichten: verschlüsselt und off-site →--exclude/--exclude-file
ein (Caches, Logs, temporäre Dateien) und nutze --one-file-system, damit Restic nicht
in gemountete Fremd-Dateisysteme abtaucht.prune dauert ewig oder wurde abgebrochen.
Kein Grund zur Panik –
Nachlesen: Restic-Backups einrichten: verschlüsselt und off-site →prune ist
wiederaufnehmbar und das Repository bleibt gültig. Starte es erneut und lass
anschließend einmal restic check laufen. Trenne --prune bei großen Repos vom
täglichen Backup (siehe Schritt 6).Der Timer läuft, aber in Uptime Kuma kommt nie eine Erfolgsmeldung.
Sieh dir den
letzten Lauf mit
Nachlesen: Restic-Backups einrichten: verschlüsselt und off-site →journalctl -u restic-backup.service an. Meist bricht das Skript
vor dem curl-Aufruf ab (z. B. der DB-Dump schlug fehl) – dank set -euo pipefail
stoppt es dann sauber, statt ein kaputtes Backup als Erfolg zu melden. Der ausbleibende
Push ist also kein Bug, sondern genau das Alarmsignal, das du haben willst.Im Browser „Zertifikat ungültig" oder Traefik-Log zeigt ACME-Fehler.
Die drei
üblichen Gründe: (1) Der DNS-Record zeigt noch nicht auf den Server –
Nachlesen: Traefik einrichten →dig +short DEINE_DOMAIN prüfen. (2) Port 80 ist von außen nicht erreichbar
(Firewall/netcup-Firewall) – die HTTP-Challenge braucht ihn. (3) Du hast das
Rate-Limit der Produktiv-CA gerissen – auf den Staging-Server wechseln (Tipp in
Schritt 3), testen, dann zurück.404 page not found beim Aufruf der App-Domain.
Traefik kennt die Route nicht.
Prüfe: Hat der Container
Nachlesen: Traefik einrichten →traefik.enable=true? Hängt er im proxy-Netzwerk?
Stimmt die Domain in der Host(...)-Regel exakt (inkl. Subdomain)? Das Dashboard
(Schritt 7) zeigt unter „HTTP Routers", ob der Router registriert wurde.Der Browser zeigt Traefiks selbstsigniertes Notfall-Zertifikat; im Log steht
permissions 644 for /acme.json are too open, please use 600.
Traefik läuft, hat
aber den ACME-Resolver übersprungen – daher kein echtes Zertifikat.
Nachlesen: Traefik einrichten →chmod 600 acme.json nachholen (Schritt 2) und Container neu starten.Keine App wird geroutet; im Traefik-Log wiederholt sich client version 1.24 is too old. Minimum supported API version is 1.40.
Deine Traefik-Version ist zu alt für
deine Docker-Engine – der Docker-Provider kann den Socket nicht mehr abfragen.
Aktuelles Docker (Engine 29, API-Level ≥ 1.40) braucht Traefik ≥ v3.6; deshalb
nutzt dieses Tutorial
Nachlesen: Traefik einrichten →traefik:v3.7. Gegen Docker 29 nachgestellt: v3.5.6 läuft in
genau diesen Fehler, v3.6.25 spricht wieder sauber mit dem Socket. Ältere Tags wie
v3.3 oder v3.5 funktionieren mit neuem Docker also nicht mehr – Image-Tag
hochziehen und docker compose up -d erneut ausführen.Basic-Auth am Dashboard wird sofort wieder abgewiesen / Router fehlt.
In der
Nachlesen: Traefik einrichten →compose.yaml müssen die $-Zeichen des Hashes verdoppelt sein ($$). Prüfe
den Hash außerhalb noch einmal mit htpasswd -nbB.Gateway Timeout oder Traefik erreicht den Container nicht.
Meist hängt die App
im falschen Netzwerk oder Traefik weiß nicht, welches gemeint ist.
Nachlesen: Traefik einrichten →providers.docker.network=proxy in Traefik und networks: [proxy] an der App
müssen zusammenpassen.502 Bad Gateway, obwohl der Container läuft.
Traefik erreicht den Container,
trifft aber den falschen Port. Lauscht die App nicht auf 80, braucht sie das Label
Nachlesen: Traefik einrichten →traefik.http.services.<name>.loadbalancer.server.port=<echter-port>. Genau dieser
Fall begegnet dir bei der ersten App im nächsten Tutorial (Uptime Kuma auf 3001).Der Probelauf meldet No packages found that can be upgraded unattended.
Meist
völlig normal – aktuell steht kein Sicherheitsupdate an. Prüfe die Konfiguration
trotzdem über die
Nachlesen: unattended-upgrades einrichten →Allowed origins are:-Zeile im --debug-Lauf. Erscheinen dort
keine Security-Origins, stimmt das Origins-Pattern aus Schritt 3 nicht.Updates kommen, aber der Server startet trotz Kernel-Update nie neu.
Meist steht
Nachlesen: unattended-upgrades einrichten →Automatic-Reboot auf "false" (Standard) – dann auf "true" setzen und eine
Automatic-Reboot-Time vergeben (Schritt 3). Steht die Option richtig, prüfe die
Markierungsdatei: Ohne /var/run/reboot-required löst der Neustart nie aus. Dafür
zuständig ist der Kernel-Hook des Pakets – dpkg -S /etc/kernel/postinst.d/unattended-upgrades muss ihn melden (Schritt 3)./boot läuft voll, Updates schlagen fehl.
Alte Kernel häufen sich an.
Nachlesen: unattended-upgrades einrichten →Remove-Unused-Kernel-Packages "true" setzen (Schritt 3); einmalig aufräumen mit
sudo apt autoremove --purge.Ein Paket wird hartnäckig zurückgehalten (kept back).
unattended-upgrades
installiert keine Updates, die andere Pakete entfernen würden. Solche Fälle löst du
bewusst von Hand mit
Nachlesen: unattended-upgrades einrichten →sudo apt upgrade und prüfst, was passiert.yaml: line 7: did not find expected key (oder ähnliche YAML-Fehler).
YAML ist
einrückungssensibel – ausschließlich Leerzeichen, niemals Tabs, und pro Ebene
konsistent (üblich: 2 Leerzeichen). Prüfe die Datei ohne sie zu starten:
Nachlesen: Docker Compose verstehen: Services, Volumes, Netzwerke →docker compose config löst alles auf und meckert genau die falsche Zeile an.Error ... address already in use beim up.
Der Host-Port (links in
Nachlesen: Docker Compose verstehen: Services, Volumes, Netzwerke →8080:80)
ist schon belegt. Finde den Beleger mit sudo ss -tlnp | grep 8080 oder wähle einen
anderen Host-Port. Zwei Container dürfen sich denselben Host-Port nicht teilen.Eine App findet ihre Datenbank nicht (could not translate host name).
Als
Hostname muss der Service-Name stehen (z. B.
Nachlesen: Docker Compose verstehen: Services, Volumes, Netzwerke →db), nicht localhost. Innerhalb
eines Containers ist localhost der Container selbst, nicht der Nachbar-Service. Und:
Beide Services müssen im selben Compose-Projekt (derselben Datei) liegen.Nach docker compose down sind alle Daten weg.
Entweder lag das Volume nicht als
Named Volume unter
Nachlesen: Docker Compose verstehen: Services, Volumes, Netzwerke →volumes: vor (dann war es nur der vergängliche
Container-Speicher), oder es wurde down -v verwendet. Persistente Dienste immer mit
deklariertem Named Volume fahren.docker-compose: command not found.
Das ist das alte Compose v1 (mit Bindestrich).
Aktuell ist
Nachlesen: Docker Compose verstehen: Services, Volumes, Netzwerke →docker compose (mit Leerzeichen, Plugin). Falls es fehlt: sudo apt install docker-compose-plugin (siehe
Docker-Tutorial).dig liefert keine oder eine falsche (alte) IP.
Meist noch Propagation. Frage
gezielt einen öffentlichen Resolver, der deinen lokalen Cache umgeht:
Nachlesen: Eine Domain mit dem Server verbinden (DNS-Grundlagen) →dig +short DEINE_DOMAIN @1.1.1.1. Zeigt der schon den richtigen Wert, ist nur dein
lokaler/Provider-Cache noch nicht abgelaufen – abwarten.Die Domain zeigt zwar, aber die falsche IP – z. B. eine Parking-Seite des Registrars.
Oft existiert noch ein alter A-Record oder eine
Weiterleitung/Parking-Einstellung. Entferne widersprüchliche Einträge; pro Name und
Typ sollte genau ein Wert stehen (bewusste Ausnahmen ausgenommen).
Nachlesen: Eine Domain mit dem Server verbinden (DNS-Grundlagen) →IPv4 klappt, IPv6 (AAAA) führt zu Timeouts.
Du hast einen AAAA-Record
eingetragen, obwohl der Server keine funktionierende IPv6-Adresse hat. Browser
bevorzugen dann IPv6 und laufen in einen Timeout. AAAA-Record entfernen, bis der
Server wirklich IPv6 kann.
Nachlesen: Eine Domain mit dem Server verbinden (DNS-Grundlagen) →In manchen Oberflächen wird der Wert mit angehängtem Punkt gespeichert
(DEINE_DOMAIN.) und du bist unsicher.
Der abschließende Punkt (Root der
DNS-Hierarchie) ist normal und korrekt – viele DNS-Verwaltungen ergänzen ihn
automatisch. Kein Grund zur Sorge.
Nachlesen: Eine Domain mit dem Server verbinden (DNS-Grundlagen) →Vom Server verschickte E-Mails landen im Spam oder werden abgelehnt (im Mail-Log
steht z. B. does not resolve to address oder no PTR record).
Der
Reverse-DNS-Eintrag (PTR) fehlt oder passt nicht zum Absender-Hostnamen. Setze den
PTR wie in Schritt 5 beschrieben beim VPS-Anbieter und achte darauf, dass er auf
denselben Namen zeigt, der auch per A-/AAAA-Record auflöst.
Nachlesen: Eine Domain mit dem Server verbinden (DNS-Grundlagen) →Nach ufw enable kommst du per SSH nicht mehr rein.
Die SSH-Regel fehlte oder
betraf den falschen Port. Verbinde dich über die Konsole im netcup SCP (VNC,
unabhängig von SSH), erlaube dort deinen SSH-Port (
Nachlesen: Firewall mit UFW einrichten →sudo ufw allow …) und teste
erneut. Genau davor warnt Schritt 3.ERROR: Could not find a profile matching 'OpenSSH'.
Das OpenSSH-Profil
existiert nur, wenn
Nachlesen: Firewall mit UFW einrichten →openssh-server installiert ist. Nutze stattdessen die
Portnummer: sudo ufw allow 22/tcp (bzw. deinen Port). sudo ufw app list zeigt die
verfügbaren Profile.Ein Docker-Container ist von außen erreichbar, obwohl UFW den Port nicht freigibt.
Kein Fehler von dir – Docker umgeht UFW. Docker schreibt seine Regeln
direkt in
Nachlesen: Firewall mit UFW einrichten →iptables und hängt sie vor die UFW-Ketten. Ein veröffentlichter
Container-Port (ports: in der compose.yaml) ist damit offen, egal was UFW sagt. Die
saubere Lösung ist eine zweite Firewall-Ebene vor dem Server – bei netcup die
Firewall im SCP als vorgelagerter
Perimeter. Auf dem Host hilft außerdem, Container-Ports nur an 127.0.0.1 zu binden
statt an 0.0.0.0.„Erstellen" legt keinen Snapshot an, solange eine DVD eingelegt ist.
Hängt unter
Medien → DVD-Laufwerk ein .iso-Image im virtuellen Laufwerk, verweigert das SCP neue
Snapshots. Wirf das Image dort aus – in der Server-Übersicht muss die Zeile ISO wieder
Nachlesen: netcup Server Control Panel: Snapshots, Konsole & Rettung →- zeigen – und starte den Snapshot erneut.Der Snapshot lässt sich nicht anlegen, weil der Speicherplatz nicht reicht.
Ein
Snapshot braucht Platz neben deinen Live-Daten. Räume auf dem Server auf, gib die
freigewordenen Blöcke mit
Nachlesen: netcup Server Control Panel: Snapshots, Konsole & Rettung →fstrim -av an den Host zurück, lösche nicht mehr benötigte
Snapshots und stoße im SCP unter Medien → Festplatten die Speicheroptimierung an.Nach einem Online-Snapshot-Restore ist die Datenbank beschädigt.
Ein
Online-Snapshot fängt einen laufenden Schreibvorgang womöglich mittendrin ein. Für
Server mit Datenbank nimm einen Offline-Snapshot oder erstelle vorher einen
Datenbank-Dump.
Nachlesen: netcup Server Control Panel: Snapshots, Konsole & Rettung →Du kommst nicht ins SCP.
Das SCP nutzt eigene Zugangsdaten (nicht SSH). Sie
stehen in der Willkommensmail; ein vergessenes SCP-Passwort setzt du im
netcup-Kundenkonto (CCP) zurück.
Nachlesen: netcup Server Control Panel: Snapshots, Konsole & Rettung →Nach dem Aktivieren geht keine Namensauflösung mehr (apt update hängt, ping domain.de
scheitert, aber ping 1.1.1.1 geht).
Die DNS-Antworten werden geblockt. Prüfe im
Basis-Template die Regel EINGEHEND UDP ACCEPT, Src-Port 53. Wichtig: Quell-Port, nicht
Ziel-Port.
Nachlesen: netcup-Firewall einrichten →Die Uhr driftet, oder TLS-Zertifikate werden wegen falscher Zeit abgelehnt.
Die
NTP-Antworten fehlen. Ergänze EINGEHEND UDP ACCEPT, Src-Port 123.
Nachlesen: netcup-Firewall einrichten →IPv6 funktioniert nicht mehr (v4 schon).
Es fehlt die ICMPv6-Regel. Ohne Neighbor
Discovery kann der Server über IPv6 nicht einmal seinen Nachbarn (Router) finden.
Nachlesen: netcup-Firewall einrichten →Du kommst nach dem Aktivieren nicht mehr per SSH rein.
Die SSH-Regel fehlt oder nennt
den falschen Port. Über die VNC-Konsole (SCP → Bildschirm) kommst du trotzdem auf den
Server; korrigiere die Policy und speichere neu. Genau dagegen hilft die „zweite Sitzung
offen lassen"-Regel oben.
Nachlesen: netcup-Firewall einrichten →Der Server kann keine E-Mails versenden (Port 25 raus geht nicht).
Das ist kein
Fehler deiner Policy, sondern netcups Default-Policy „netcup Mail block" – sie sperrt
ausgehendes SMTP (Port 25/465/587) als Spam-Schutz. Für einen echten Mailversand musst du
dieses netcup-Template am Server deaktivieren.
Nachlesen: netcup-Firewall einrichten →Der Server läuft zunächst normal und ist nach ein bis zwei Wochen plötzlich offline.
Nutzt der Server DHCP, wird die Lease-Erneuerung von der Whitelist geblockt – die
DHCP-Antwort kommt von UDP-Quell-Port 67, den keine Regel erlaubt, und UDP ist
zustandslos. Ergänze
Nachlesen: netcup-Firewall einrichten →EINGEHEND · UDP · ACCEPT · Src 67 im Basis-Template. Statisch
konfigurierte netcup-VPS (der Standard) sind davon nicht betroffen.E: Package 'docker-ce' has no installation candidate.
Die Paketquelle aus
Schritt 2 fehlt oder ist fehlerhaft – apt kennt den Namen nur aus den Abhängigkeiten
der Debian-Pakete, findet aber kein Paket dazu. Prüfe den Inhalt von
Nachlesen: Docker auf Debian installieren →/etc/apt/sources.list.d/docker.list – dort muss deine Debian-Version (z. B.
trixie) stehen – und führe danach erneut sudo apt update aus.permission denied while trying to connect to the docker API at unix:///var/run/docker.sock.
Die
Nachlesen: Docker auf Debian installieren →docker-Gruppenmitgliedschaft greift noch nicht. SSH-Sitzung beenden und neu
verbinden; groups muss danach docker enthalten. Falls nicht, Schritt 4
wiederholen.Konflikte bei der Installation mit bereits vorhandenen Paketen.
Auf dem System
ist schon eine andere Docker-Variante installiert (
Nachlesen: Docker auf Debian installieren →docker.io, podman-docker, …).
Alte Pakete zuerst entfernen: sudo apt remove docker.io docker-doc docker-compose podman-docker containerd runc – bestehende Container/Images bleiben dabei erhalten.docker compose meldet docker: unknown command: docker compose.
Das
Compose-Plugin fehlt – wahrscheinlich wurde Docker früher anders installiert.
Nachlesen: Docker auf Debian installieren →sudo apt install docker-compose-plugin nachholen. Achtung: Das alte
docker-compose (mit Bindestrich) ist ein anderes, veraltetes Werkzeug.SSH fragt trotz ssh-copy-id weiter nach dem Passwort.
Meist stimmen die
Dateirechte auf dem Server nicht: SSH ignoriert
Nachlesen: SSH-Zugang absichern →authorized_keys, wenn Gruppe
oder andere in ~/.ssh schreiben dürfen. Im Log auf dem Server (sudo journalctl -u ssh --since -5min) steht dann Authentication refused: bad ownership or modes for directory /home/koch/.ssh. Repariere mit chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys und prüfe außerdem, dass du dich mit dem richtigen
Benutzer verbindest (koch@…, nicht root@…).Permission denied (publickey) – und du kommst gar nicht mehr rein.
Passwort-Login wurde deaktiviert, bevor der Schlüssel funktionierte. Kein Drama:
Öffne die VNC-Konsole im netcup SCP, melde dich dort lokal an, setze
Nachlesen: SSH-Zugang absichern →PasswordAuthentication yes, starte SSH neu und beginne wieder bei Schritt 2.Nach dem Neustart startet der SSH-Dienst nicht mehr.
Syntaxfehler in der
Nachlesen: SSH-Zugang absichern →sshd_config – ein verschriebenes PasswordAuthentification genügt (deshalb immer
sshd -t vor dem Neustart). Über die VNC-Konsole einloggen, dann nennt
sudo sshd -t Datei, Zeile und Option: /etc/ssh/sshd_config: line 125: Bad configuration option: PasswordAuthentification gefolgt von
/etc/ssh/sshd_config: terminating, 1 bad configuration options.Einstellungen scheinen zu greifen, Passwort-Login geht aber weiterhin.
Eine
Datei unter
Nachlesen: SSH-Zugang absichern →/etc/ssh/sshd_config.d/ (häufig 50-cloud-init.conf) überschreibt
deine Werte. sudo sshd -T | grep -i passwordauthentication zeigt die tatsächlich
wirksame Einstellung – Treffer in den Zusatzdateien anpassen und SSH neu starten.ssh: connect to host … port 22: Connection timed out.
Meist ist die IP falsch
abgetippt oder der Server noch nicht fertig provisioniert. Prüfe die IP in deinem
Kundenkonto und ob der Server dort als „online" angezeigt wird. Warte nach der
Bestellung ein paar Minuten.
Nachlesen: Erste Schritte mit einem netcup VPS →Permission denied, please try again beim root-Login.
Falsches Passwort – oft
ein Copy-Paste-Problem mit unsichtbaren Leerzeichen am Ende oder ein abweichendes
Tastaturlayout. Kopiere das Passwort ohne umgebende Leerzeichen direkt aus den
Zugangsdaten.
Nachlesen: Erste Schritte mit einem netcup VPS →WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!.
Der Server wurde neu
installiert und hat einen neuen Host-Key – SSH schlägt zu Recht Alarm. Wenn du
selbst neu installiert hast, entferne den alten Eintrag mit
Nachlesen: Erste Schritte mit einem netcup VPS →ssh-keygen -R DEINE_SERVER_IP und verbinde neu. Hast du nicht neu installiert, geh der Sache nach,
bevor du dich verbindest.sudo: command not found als neuer Benutzer.
Auf Minimal-Images fehlt das Paket
manchmal. Als
Nachlesen: Erste Schritte mit einem netcup VPS →root nachinstallieren: apt install sudo. Danach prüfen, dass der
Benutzer in der Gruppe ist: groups koch muss sudo enthalten – sonst Schritt 3
wiederholen und einmal ab- und wieder anmelden.Nichts gefunden. Versuch es mit weniger Wörtern oder der wörtlichen Fehlermeldung.