Postiz unter Windows installieren: Docker-Setup + Troubleshooting

Inhaltsverzeichnis

Postiz ist der enorm beliebte Open-Source-Scheduler für Social Media, eine selbst gehostete Alternative zu Buffer oder Hootsuite mit über 33.000 GitHub-Stars. Dieser Guide führt dich durch die Installation unter Windows mit Docker Desktop.

Wenn es dir geht wie mir und du die offizielle Postiz-Dokumentation zu vage findest, dann ist diese Schritt-für-Schritt-Anleitung genau das Richtige für dich.

Lies das zuerst: der Haken am lokalen Hosting

Eine Sache solltest du wissen, bevor du loslegst:

Postiz veröffentlicht Posts nur, solange dein Rechner läuft.

Das Scheduling übernimmt ein Background-Worker innerhalb des Docker-Stacks. Wenn du einen Post für Dienstag 9:00 Uhr planst und dein PC im Ruhezustand ist, heruntergefahren wurde oder Docker nicht läuft, geht der Post nicht raus. Er wird verspätet abgefeuert, sobald der Stack das nächste Mal startet.

Die Windows-Energieeinstellungen sind meistens der Übeltäter. Ein Rechner, der über Nacht in den Standby geht, verpasst alles, was für die Nacht geplant ist. Prüfe also deinen Energiesparplan, wenn Posts Stunden zu spät landen.

Damit eignet sich eine lokale Installation super für:

  • Postiz ausprobieren, bevor du dich für einen Server entscheidest
  • Content entwerfen und organisieren
  • Entwicklung und Tests

…und schlecht dafür, einen Posting-Zeitplan zuverlässig einzuhalten. Wenn deine Posts pünktlich rausgehen müssen, pack das Ganze auf einen VPS oder nutze die gehostete Version. Alles Folgende gilt auch für einen Server - nur das Problem mit dem “Rechner muss anbleiben” fällt dann weg.

Wenn Scheduling für dich ein K.-o.-Kriterium ist, kannst du entweder für Postiz bezahlen oder es auf einem VPS hosten. Ein günstiger VPS reicht völlig; ich habe aufgeschrieben, welche Hoster wirklich etwas taugen.

Was du brauchst

  • Windows 10 oder 11
  • Docker Desktop - https://docker.com/products/docker-desktop
  • Git (für Git Bash) - https://git-scm.com/download/win
  • ~15 GB freier Speicherplatz. Der Stack lädt rund 9,5 GB an Images herunter, dazu kommt Platz für Volumes und Overhead. (Bei einer Installation gemessen - Image-Größen ändern sich, nimm es also als groben Richtwert.)
  • Mindestens 8 GB RAM; der Stack braucht im Leerlauf etwa 3-4 GB. Beachte, dass das WSL2-Backend von Docker Desktop obendrauf noch ein eigenes Speicherlimit hat, 8 GB insgesamt lassen also sehr wenig Luft. Mit 16 GB ist es deutlich angenehmer.

Die Zeitangaben unten gehen von einer halbwegs schnellen Verbindung aus. Der Image-Download dominiert.

Schritt 1 - Docker Desktop installieren und starten

Installiere es, dann starte es und warte, bis das Wal-Symbol im System-Tray aufhört, sich zu bewegen. Die Docker-Engine läuft in einer Linux-VM, die 30-60 Sekunden zum Booten braucht. Jeder docker-Befehl schlägt fehl, bis sie oben ist.

Aktiviere Settings → General → Start Docker Desktop when you log in. Postiz kann nichts veröffentlichen, wenn Docker nicht läuft, bei einer lokalen Installation leistet diese Einstellung also echte Arbeit für dich.

In Git Bash prüfen:

docker --version

Irgendeine Versionsnummer bedeutet, dass die CLI erreichbar und die Engine oben ist. Wenn du bash: docker: command not found bekommst, siehe Stolperfalle 1 weiter unten.

Schritt 2 - Compose-Datei holen

Such dir aus, wo du deine Projekte ablegst. In Git Bash ist dein Windows-Benutzerordner ~, das hier landet also in C:\Users\<du>\projects\postiz:

mkdir -p ~/projects && cd ~/projects
git clone https://github.com/gitroomhq/postiz-docker-compose postiz
cd postiz

Das ist nur die Docker-Compose-Konfiguration - die Anwendung selbst kommt als vorgebaute Images.

Der Ordnername spielt eine kleine Rolle: Compose stellt ihn seinen Volumes und Netzwerken voran. Klonst du nach postiz, bekommst du postiz_postgres-volume; klonst du nach my-postiz, heißt es my-postiz_postgres-volume. Die Befehle unten gehen von postiz aus.

Schritt 3 - Ein echtes JWT-Secret setzen

docker-compose.yaml kommt mit einem Platzhalter:

JWT_SECRET: 'random string that is unique to every install - just type random characters here!'

Dieser String signiert deine Login-Tokens, und er ist in jeder Kopie des Repos identisch. Erzeuge dein eigenes:

openssl rand -base64 32

Füge das Ergebnis anstelle des Platzhalters ein. Mach das vor dem ersten Start - eine spätere Änderung macht bestehende Sessions ungültig.

Zwei weitere Einstellungen, die du kennen solltest, beide weit oben in der Datei:

EinstellungStandardBedeutung
DISABLE_REGISTRATION'false'Registrierung ist offen. Für deinen ersten Account nötig - danach schließen (Schritt 6).
MAIN_URLhttp://localhost:4007Nur ändern, wenn du nicht auf localhost bist.

Schritt 4 - Starten

docker compose up -d

Der erste Durchlauf lädt rund 9,5 GB über 8 Images - rechne mit 5-15 Minuten. Spätere Starts dauern deutlich unter einer Minute.

-d startet das Ganze detached, also im Hintergrund.

Schritt 5 - Warten, bis es wirklich bereit ist

docker compose ps

Alle Services sollen (healthy) anzeigen:

postiz                   Up (healthy)
postiz-postgres          Up (healthy)
postiz-redis             Up (healthy)
temporal                 Up (healthy)
temporal-postgresql      Up (healthy)
temporal-elasticsearch   Up (healthy)
temporal-ui              Up (healthy)
temporal-admin-tools     Up

Die Services starten in Abhängigkeitsreihenfolge - Elasticsearch, dann Temporal, dann Postiz - und Postiz führt beim ersten Boot Datenbank-Migrationen aus. Zwei bis drei Minuten (health: starting) zu sehen, ist völlig normal.

Dann öffne:

http://localhost:4007

Nutze http://, nicht https://. Hier terminiert nichts TLS, die https-URL schlägt also schlicht fehl.

Registriere dich - der erste Account ist der Admin.

Schritt 6 - Registrierung schließen

Sobald dein Account existiert, hindere alle anderen daran, einen anzulegen. In docker-compose.yaml:

DISABLE_REGISTRATION: 'true'

Übernehmen:

docker compose up -d

Das baut nur den geänderten Container neu. Dein Account und deine Daten liegen in benannten Volumes und bleiben unangetastet - du bleibst eingeloggt.

Schritt 7 - Secrets aus der Versionskontrolle heraushalten

Optional, aber sinnvoll, falls du diese Config jemals committest oder auf einen Server kopierst.

Docker Compose liest automatisch eine .env-Datei, die neben docker-compose.yaml liegt. Verschiebe die Secrets dorthin:

.env

JWT_SECRET=your-generated-secret
POSTGRES_USER=postiz-user
POSTGRES_PASSWORD=postiz-password
POSTGRES_DB=postiz-db-local

docker-compose.yaml

JWT_SECRET: ${JWT_SECRET:?set JWT_SECRET in .env}
DATABASE_URL: 'postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postiz-postgres:5432/${POSTGRES_DB}'

.gitignore

.env

Die :?-Syntax sorgt dafür, dass Compose mit einer klaren Meldung abbricht, wenn die Variable fehlt, statt stillschweigend mit einem leeren Secret zu starten.

Prüfe die Ersetzung, bevor du neu startest:

docker compose config | grep JWT_SECRET

Wenn .env korrekt eingerichtet ist, gibt das den aufgelösten Wert aus. Fehlt die Variable, bricht docker compose config mit einem Fehler ab, statt irgendetwas auszugeben - das grep läuft dann gar nicht erst. Beide Ausgänge sagen dir, was du wissen musst:

error while interpolating services.postiz.environment.JWT_SECRET:
required variable JWT_SECRET is missing a value: set JWT_SECRET in .env

Sichere .env irgendwo außerhalb des Repos. Die Datei ist per Design git-ignored, was eben auch heißt, dass sie nicht mitgesichert wird. Verlierst du das JWT_SECRET, ist jede Session kaputt.

Schritt 8 - Social-Kanäle verbinden

Postiz liest die Zugangsdaten der Plattformen aus der Umgebung des Containers, nicht aus irgendetwas im Web-UI. Es gibt dafür keine Felder im Dashboard - du setzt sie in der Config und startest neu.

Nach dem .env-Muster aus Schritt 7, hier am Beispiel X:

.env

X_API_KEY=your-key-here
X_API_SECRET=your-secret-here

docker-compose.yaml

X_API_KEY: ${X_API_KEY:-}
X_API_SECRET: ${X_API_SECRET:-}

Der :--Standardwert hält leere Werte gültig, sodass Plattformen, die du nicht eingerichtet hast, einfach nicht verfügbar sind, statt den Start zu zerschießen.

Dann docker compose up -d und den Kanal im UI verbinden.

Die vollständige Liste der unterstützten Plattformen

Das sind die Variablennamen, die die Compose-Datei mitbringt. Richte nur die ein, die du brauchst - das Muster ist bei allen identisch: Variablen in .env eintragen, in der Compose-Datei auf ${VAR:-} umstellen, neu starten.

PlattformVariablen
X (Twitter)X_API_KEY, X_API_SECRET
FacebookFACEBOOK_APP_ID, FACEBOOK_APP_SECRET
Instagram / ThreadsTHREADS_APP_ID, THREADS_APP_SECRET
LinkedInLINKEDIN_CLIENT_ID, LINKEDIN_CLIENT_SECRET
TikTokTIKTOK_CLIENT_ID, TIKTOK_CLIENT_SECRET
YouTubeYOUTUBE_CLIENT_ID, YOUTUBE_CLIENT_SECRET
PinterestPINTEREST_CLIENT_ID, PINTEREST_CLIENT_SECRET
RedditREDDIT_CLIENT_ID, REDDIT_CLIENT_SECRET
MastodonMASTODON_CLIENT_ID, MASTODON_CLIENT_SECRET, MASTODON_URL
DiscordDISCORD_CLIENT_ID, DISCORD_CLIENT_SECRET, DISCORD_BOT_TOKEN_ID
SlackSLACK_ID, SLACK_SECRET, SLACK_SIGNING_SECRET
DribbbleDRIBBBLE_CLIENT_ID, DRIBBBLE_CLIENT_SECRET
GitHubGITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET
BeehiivBEEHIIVE_API_KEY, BEEHIIVE_PUBLICATION_ID

MASTODON_URL steht standardmäßig auf https://mastodon.social - ändere es, wenn du auf einer anderen Instanz bist. Beachte, dass BEEHIIVE_* in der Compose-Datei mit dem zusätzlichen “E” geschrieben wird; übernimm es genau so.

Postiz unterstützt in seinem UI mehr Plattformen als diese. Wenn eine, die du willst, nicht aufgeführt ist, schau in der Konfigurationsreferenz nach den Variablennamen und ergänze sie auf die gleiche Weise.

Jede Plattform braucht eine im jeweiligen Developer-Portal registrierte App, und für jede muss eine Callback-URL freigeschaltet sein - typischerweise http://localhost:4007/integrations/social/<platform>. Prüfe docker compose logs postiz für die exakte URL, die Postiz erwartet, falls eine Verbindung fehlschlägt.

Fang mit einer einfachen an

Die Plattformen unterscheiden sich enorm darin, wie viel Arbeit sie machen, und das solltest du wissen, bevor du einen Nachmittag in die falsche steckst:

  • Einfach - Mastodon, Discord, Reddit, GitHub. Zugangsdaten sofort verfügbar, keine Prüfung.
  • Mittel - LinkedIn (braucht eine Unternehmensseite), Pinterest, Slack.
  • Schwer - Facebook, Instagram/Threads, TikTok, YouTube. App-Review, Sandbox-Einschränkungen oder Unternehmensverifizierung.
  • Kostenpflichtig - X verlangt für Schreibzugriff ein kostenpflichtiges API-Tier. Das kostenlose Tier ist nur lesend, Posten funktioniert damit also nicht.

Wenn du einfach nur zeigen willst, dass die Pipeline von Anfang bis Ende funktioniert, dauert Mastodon rund zwei Minuten: Einstellungen → Entwicklung → Neue Anwendung in einer beliebigen Mastodon-Instanz.

Diese Anforderungen ändern sich häufig - nimm die Einteilung oben als Ausgangspunkt und prüfe die aktuellen Bedingungen im jeweiligen Portal.

Befehle für den Alltag

docker compose ps             # status
docker compose logs -f postiz # follow logs, Ctrl+C to quit
docker compose stop           # stop, keeps all data
docker compose up -d          # start
docker compose restart postiz # restart just the app

Die Daten liegen in benannten Docker-Volumes und überleben stop, up -d, restart und down.

docker compose down -v löscht die Volumes - das vernichtet deinen Account, deine Posts und deine Uploads. Das ist der eine Befehl, bei dem du vorsichtig sein solltest.


Troubleshooting und typische Stolperfallen

Stolperfalle 1: bash: docker: command not found

Docker Desktop ist installiert, aber deine Shell findet es nicht.

Prüfe als Erstes, ob Docker Desktop tatsächlich läuft. Kein PATH-Fix der Welt hilft, wenn die Engine unten ist.

Falls es läuft, prüfe, ob die CLI in deinem PATH steht:

echo "$PATH" | tr ':' '\n' | grep -i docker

Keine Ausgabe heißt, das Verzeichnis fehlt. Finde die Binary:

ls "/c/Program Files/Docker/Docker/resources/bin/docker.exe"
ls "$LOCALAPPDATA/Programs/DockerDesktop/resources/bin/docker.exe"

Neuere Docker-Desktop-Versionen installieren möglicherweise pro Benutzer nach %LOCALAPPDATA%\Programs\DockerDesktop statt nach C:\Program Files\Docker. Guides, die von Program Files ausgehen, passen dann nicht.

Trage den Pfad, der bei dir existiert, in ~/.bashrc ein. $HOME hält deinen Benutzernamen aus der Zeile heraus und bleibt im Unix-Pfadformat, und genau das will PATH:

echo 'export PATH="$PATH:$HOME/AppData/Local/Programs/DockerDesktop/resources/bin"' >> ~/.bashrc
source ~/.bashrc

(Wenn es bei dir die Program-Files-Installation ist, nimm stattdessen /c/Program Files/Docker/Docker/resources/bin.)

Verwende hier nicht $LOCALAPPDATA. Das expandiert zu einem Windows-Pfad mit Backslashes und Laufwerksbuchstaben (C:\Users\you\AppData\Local), und ein C: in einem durch Doppelpunkte getrennten PATH ist geradezu eine Einladung für Ärger. $HOME ist in Git Bash ohnehin schon /c/Users/you.

Eine Feinheit, die man kennen sollte: Selbst wenn das Verzeichnis korrekt in deinem Windows-PATH registriert ist, erben Terminals ihre Umgebung von explorer.exe, das womöglich noch eine veraltete Kopie von vor der Installation hält. Ein neues Terminal zu öffnen hilft nicht immer - ein Neustart schon. Wenn du ~/.bashrc bearbeitest, umgehst du das ganze Problem.

Und noch etwas: Wo dein Projekt auf der Platte liegt, spielt hier keine Rolle. PATH ist eine Liste absoluter Verzeichnisse; von wo aus du den Befehl ausführst, ist egal.

Stolperfalle 2: 502 Bad Gateway beim Login oder bei der Registrierung

Die Seite lädt, aber das Absenden des Formulars liefert den 502 von nginx.

Das heißt: Das Frontend ist in Ordnung und das Backend ist tot.

Der postiz-Container ist kein einzelner Prozess - er betreibt mehrere hinter einer einzigen nginx-Instanz:

ProzessPortRolle
nginx5000Eingangstür; routet alles
frontend (Next.js)4200das UI, das du siehst
backend (NestJS)3000die API - /api/* wird hierher geproxyt
workers / cron-Veröffentlichung und geplante Jobs

nginx liefert das UI fröhlich aus, egal ob das Backend lebt oder nicht. Also rendert die Seite, und dann liefert jeder API-Aufruf - Login, Registrierung - einen 502.

Prüfe, ob das Backend lauscht:

docker exec postiz ss -tln | grep 3000

Falls ss nicht im Image ist, nimm Node, das immer vorhanden ist:

docker exec postiz node -e "require('net').connect(3000,'127.0.0.1').on('connect',()=>{console.log('backend UP');process.exit(0)}).on('error',()=>{console.log('backend DOWN');process.exit(1)})"
  • Eine LISTEN-Zeile (oder backend UP) → Backend ist in Ordnung; such woanders.
  • Keine Ausgabe (oder backend DOWN) → Backend ist unten. Finde heraus, warum:
docker compose logs postiz | grep -i "backend failed" -A 5

Stolperfalle 3: “Alle Services healthy”, aber die App ist kaputt

Das ist die Falle, die Stolperfalle 2 so verwirrend macht.

docker compose ps kann jeden Service als (healthy) melden, während Postiz grundlegend kaputt ist. Schau dir an, was der Health-Check der Compose-Datei tatsächlich testet - er ruft http://localhost:5000/ ab, und das ist nginx. Und nginx bleibt völlig gesund und liefert das Frontend aus, selbst wenn das Backend dahinter abgestürzt ist.

In diesem Stack heißt (healthy) also “der Webserver läuft”, nicht “die Anwendung funktioniert”. Wenn sich etwas seltsam verhält, ist der Port-3000-Check von oben ein weit besseres Signal als die Status-Spalte.

Stolperfalle 4: Entferne keine Services, um RAM zu sparen

Der Stack betreibt 8 Container, und der Temporal-Teil sieht für eine private Installation nach Overkill aus. Widerstehe dem Drang, ihn auszudünnen.

Besonders temporal-elasticsearch sieht optional aus, ist es aber nicht. Elasticsearch ist für Temporal generell tatsächlich optional - es liefert die “Advanced Visibility”, und Temporal fällt ohne es auf PostgreSQL zurück. Aber Postiz registriert beim Start eigene Temporal-Search-Attributes, und der PostgreSQL-Visibility-Store deckelt Attribute vom Typ Text bei drei. Postiz braucht mehr.

Entfernst du Elasticsearch, stirbt das Backend während der Initialisierung mit:

Unable to create search attributes: cannot have more than 3 search attribute of type Text.

…was bei dir als 502 beim Login ankommt, während alle Services healthy melden. Die Compose-Datei bringt diese Services aus gutem Grund mit.

Wenn du es bereits entfernt hast, stelle den ursprünglichen Elasticsearch-Service wieder her und lösche danach den State von Temporal, damit es sich konsistent neu initialisiert:

docker compose down
docker volume rm postiz_temporal-postgres-data
docker compose up -d

Das entfernt nur die Datenbank von Temporal. Dein Postiz-Account und deine Posts liegen in postiz_postgres-volume und bleiben unberührt.

Prüfe zuerst deine Volume-Namen - Compose stellt ihnen den Verzeichnisnamen voran, sie heißen also nur dann postiz_*, wenn du in einen Ordner namens postiz geklont hast:

docker volume ls | grep temporal

Stolperfalle 5: /api/copilot/chat-Timeouts in den Logs

Harmlos. Das ist die KI-Assistenten-Funktion, die fehlschlägt, weil OPENAI_API_KEY leer ist. Ignoriere es, außer du willst KI-generierte Post-Inhalte, dann hinterlege einen Key.


Solltest du überhaupt lokal selbst hosten?

Postiz ist die beste selbst gehostete Buffer-Alternative, die es gibt. Lokal zu hosten ist ein wirklich guter Weg, um Postiz zu evaluieren, den Stack kennenzulernen und Content zu entwerfen, ohne für irgendetwas zu bezahlen. ABER: Es ist kein guter Weg, um einen Posting-Zeitplan einzuhalten.

Wenn dir die Zuverlässigkeit des Schedulings wichtig ist: Dieselbe Compose-Datei läuft auf einem kleinen VPS - du würdest MAIN_URL, FRONTEND_URL und NEXT_PUBLIC_BACKEND_URL auf deine Domain umstellen und einen Reverse Proxy mit TLS davorsetzen. Alles andere lässt sich unverändert übernehmen.

Ein günstiger VPS reicht völlig; ich habe separat aufgeschrieben, bei welchen Hostern sich eine Anmeldung wirklich lohnt, inklusive der Verlängerungspreis-Fallen, die du vermeiden solltest.

Matt

Vertrauen Sie KEINER Review-Seite. Affiliate-Provisionen bestimmen deren Rankings. Dies ist auch eine Affiliate-Seite, aber ich bin ehrlich darüber, was ich verdiene, und ich bewerte nach Qualität statt nach Auszahlung. Selbst wenn das bedeutet, dass ich 0 $ bezahlt werde. Lesen Sie über meinen Ansatz und warum ich aufgehört habe zu lügen. Hier sind die Rohdaten, damit Sie alles selbst überprüfen können.

VPNs | Hosting | Cloud | Tools


Verwandte Beiträge