LinkWarden mit Docker installieren: Self-hosted kollaborativer Bookmark-Manager mit Webarchivierung
LinkWarden kombiniert Lesezeichenverwaltung mit automatischer Webarchivierung als Screenshot, PDF und HTML, damit gespeicherte Links auch nach dem Verschwinden der Seite lesbar bleiben. Diese Anleitung zeigt die getestete Docker-Compose-Installation.
Geprüft am 29.09.2026 · für linkwarden 2.16.3
WerbelinksMit * markierte Links sind Werbelinks: Bei einem Kauf erhalten wir eine Provision, der Preis bleibt gleich. Als Amazon-Partner verdiene ich an qualifizierten Verkäufen. Mehr dazu

Gespeicherte Links führen oft Monate später ins Leere. LinkWarden archiviert jeden Bookmark automatisch als Screenshot, PDF und Single-File-HTML, sodass der Inhalt auch nach dem Abschalten der Originalseite erhalten bleibt. Dazu kommen Mobile-Apps für iOS und Android, Browser-Erweiterungen, eine Leseansicht mit Anmerkungen, optionales KI-Tagging und Anmeldung über zahlreiche SSO-Anbieter. Diese Anleitung zeigt den Betrieb mit Docker Compose auf einem Linux-Host, ob VPS, Heimserver oder NAS.
Voraussetzungen
- Docker Engine >= 24.x und Docker Compose v2 (Befehl:
docker compose, ohne Bindestrich) auf dem Host installiert – siehe Docker und Docker Compose auf Linux installieren - Linux-Host (x86_64 oder arm64) – Ubuntu 22.04/24.04 oder Debian 12 empfohlen; läuft identisch auf einem NAS mit Docker-Unterstützung
- 2 CPU-Kerne und 4 GB RAM empfohlen, da drei Services parallel laufen (Next.js, PostgreSQL 16, MeiliSearch) und die Archivierung einen Chromium-Browser startet. Im Test belegte der Stack nach dem Start rund 600 MB RAM; mindestens 20 GB freier Speicherplatz für Archivdaten
- Ausgehender HTTP/HTTPS-Zugriff vom Container zum Internet (LinkWarden lädt externe Seiten zur Archivierung herunter)
openssloderpython3zur Generierung sicherer Zufalls-Secrets- Optional: eigene Domain + Reverse Proxy (Nginx Proxy Manager, Traefik oder Caddy) für HTTPS-Betrieb – wie das funktioniert, erklärt Traefik als Docker-Reverse-Proxy mit automatischem HTTPS einrichten
Schritt 1: Projektordner anlegen
Legen Sie einen eigenen Ordner an; Datenbank, Archive und Suchindex liegen als Unterverzeichnisse darin:
mkdir -p /opt/linkwarden
cd /opt/linkwardenOhne Root-Zugriff geht auch ~/linkwarden, sofern der Benutzer Schreibrechte hat. ./pgdata, ./data und ./meili_data entstehen beim ersten Start automatisch und gehören danach root bzw. dem Postgres-Benutzer (relevant für das Backup in Schritt 8).
Verifizieren: ls -la /opt/linkwarden zeigt das leere Verzeichnis. Der aktuell angemeldete Benutzer ist Eigentümer (drwxr-xr-x ... ihrbenutzer).
Schritt 2: Sichere Secrets generieren
LinkWarden benötigt drei kryptografisch starke Zufalls-Strings. Erzeugen Sie sie mit openssl:
# NEXTAUTH_SECRET (mindestens 32 Zeichen, signiert alle Auth-Sessions)
openssl rand -base64 36
# POSTGRES_PASSWORD (Datenbankpasswort)
openssl rand -base64 24
# MEILI_MASTER_KEY (mindestens 16 Zeichen für MeiliSearch-Produktion)
openssl rand -base64 36Notieren Sie alle drei Ausgaben für die .env. Alternativ: python3 -c 'import secrets; print(secrets.token_urlsafe(36))'.
Verifizieren: Jeder generierte String ist mindestens 32 Zeichen lang und enthält Groß- und Kleinbuchstaben sowie Sonderzeichen. Alle drei Werte sind voneinander verschieden.
Schritt 3: .env-Datei anlegen und konfigurieren
Die .env-Datei enthält alle sensitiven Konfigurationswerte. Legen Sie sie im Projektordner an:
# /opt/linkwarden/.env
# --- Pflichtfelder (alle drei MÜSSEN geändert werden!) ---
# Signiert Auth-Sessions; mindestens 32 Zeichen; generiert mit: openssl rand -base64 36
NEXTAUTH_SECRET=HIER_IHREN_GENERIERTEN_STRING_EINTRAGEN
# Muss exakt das Suffix /api/v1/auth enthalten – sonst schlägt der Login fehl!
# Lokal: http://localhost:3000/api/v1/auth
# Mit Reverse Proxy: https://links.meinedomain.tld/api/v1/auth
NEXTAUTH_URL=http://localhost:3000/api/v1/auth
# PostgreSQL-Datenbankpasswort; generiert mit: openssl rand -base64 24
POSTGRES_PASSWORD=HIER_IHR_DB_PASSWORT
# MeiliSearch Master-Key; mindestens 16 Zeichen; generiert mit: openssl rand -base64 36
MEILI_MASTER_KEY=HIER_IHREN_MEILI_KEY_EINTRAGEN
# --- Optionale Felder ---
# Nach der Erstregistrierung auf true setzen, um offene Registrierung zu sperren
NEXT_PUBLIC_DISABLE_REGISTRATION=false
# Sekunden Wartezeit vor Screenshot/PDF-Capture (Standard: 30)
# AUTOSCROLL_TIMEOUT=30
# Maximale Links pro Benutzer (Standard: 30000)
# MAX_LINKS_PER_USER=30000
# Browser-Archivierung deaktivieren (spart Ressourcen, aber kein Link-Rot-Schutz mehr)
# Frueher DISABLE_PRESERVATION
# DISABLE_BROWSER=falseSchützen Sie die Datei vor unbefugtem Zugriff:
chmod 600 /opt/linkwarden/.envVerifizieren: cat /opt/linkwarden/.env zeigt alle drei Pflichtfelder mit echten Werten (keine Platzhalter mehr). ls -la /opt/linkwarden/.env zeigt die Berechtigung -rw-------.
Schritt 4: compose.yaml erstellen
Erstellen Sie die compose.yaml im Projektordner mit drei Services: LinkWarden-App (Next.js), PostgreSQL 16 und MeiliSearch für die Volltextsuche. Nur Port 3000 wird freigegeben:
# /opt/linkwarden/compose.yaml
services:
postgres:
image: postgres:16-alpine
env_file: .env
restart: always
volumes:
- ./pgdata:/var/lib/postgresql/data
environment:
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
meilisearch:
image: getmeili/meilisearch:v1.12.8
restart: always
env_file:
- .env
volumes:
- ./meili_data:/meili_data
linkwarden:
image: ghcr.io/linkwarden/linkwarden:latest
env_file: .env
environment:
- DATABASE_URL=postgresql://postgres:${POSTGRES_PASSWORD}@postgres:5432/postgres
restart: always
ports:
- "3000:3000"
volumes:
- ./data:/data/data
depends_on:
- postgres
- meilisearchDetails: Das offizielle Image liegt auf der GitHub Container Registry (ghcr.io), nicht auf Docker Hub. MeiliSearch ist bewusst auf v1.12.8 festgeschrieben, um Breaking Changes zu vermeiden; die offizielle Vorlage verwendet inzwischen v1.13.3 (Stand September 2026). DATABASE_URL wird im environment-Block aus ${POSTGRES_PASSWORD} zusammengebaut und gehört nicht in die .env.
Die folgende Tabelle fasst alle wichtigen Eckdaten des Stacks zusammen:
| Eigenschaft | Wert |
|---|---|
| Haupt-Image | ghcr.io/linkwarden/linkwarden:latest (Stand September 2026: v2.16.3) |
| Datenbank-Image | postgres:16-alpine |
| Suche-Image | getmeili/meilisearch:v1.12.8 |
| Exponierter Port | 3000 (Web-UI und API) |
| Volume: Archivdaten | ./data → /data/data |
| Volume: Datenbank | ./pgdata → /var/lib/postgresql/data |
| Volume: Suchindex | ./meili_data → /meili_data |
| RAM | 4 GB empfohlen |
| Mindest-Speicher | 20 GB für Archivdaten |
Verifizieren: cat /opt/linkwarden/compose.yaml zeigt alle drei Services ohne Syntaxfehler. docker compose config (im Projektordner) validiert die Datei und interpoliert die Umgebungsvariablen aus .env – die Ausgabe darf keine Fehler und keine Platzhalter-Werte enthalten.
Schritt 5: Stack starten
Starten Sie alle drei Services mit einem Befehl:
cd /opt/linkwarden
docker compose up -dDocker lädt beim ersten Start die Images (im Test rund 3 GB, davon 2,5 GB für LinkWarden); PostgreSQL initialisiert die Datenbank in einigen Sekunden. Da depends_on ohne Healthcheck arbeitet, startet LinkWarden eventuell vor der Datenbank. Dann genügt ein Neustart:
docker compose restart linkwardenPrüfen Sie den Status aller Services:
docker compose psErwartete Ausgabe (alle Services Up):
NAME IMAGE STATUS PORTS
linkwarden-linkwarden-1 ghcr.io/linkwarden/linkwarden:latest Up 0.0.0.0:3000->3000/tcp
linkwarden-postgres-1 postgres:16-alpine Up 5432/tcp
linkwarden-meilisearch-1 getmeili/meilisearch:v1.12.8 Up 7700/tcpBei Problemen helfen die Logs:
# Alle Services gleichzeitig
docker compose logs -f
# Nur LinkWarden
docker compose logs -f linkwardenVerifizieren: docker compose ps zeigt alle drei Container im Status Up. Ein HTTP-Check bestätigt die Erreichbarkeit:
curl -I http://localhost:3000
# Erwartete Antwort: HTTP/1.1 200 OK oder HTTP/1.1 302 FoundSchritt 6: Admin-Account anlegen und Ersteinrichtung
Öffnen Sie http://localhost:3000 (bzw. IP/Domain des Servers) und klicken Sie auf „Registrieren“. Der erste registrierte Benutzer wird automatisch zum Admin; wählen Sie ein starkes Passwort.
Danach stehen alle Funktionen bereit: Links speichern (manuell oder per Browser-Extension), Collections, Tagging, Reader-View und Volltextsuche via MeiliSearch. Die Archivierung läuft im Hintergrund; je nach Seite und Einstellung (Standard: 30 Sekunden Wartezeit) dauert es einige Momente, bis Screenshot, PDF und HTML-Snapshot verfügbar sind.
Sperren Sie danach die offene Registrierung, damit sich keine unbefugten Benutzer anmelden können:
# In .env den Wert ändern:
# NEXT_PUBLIC_DISABLE_REGISTRATION=true
# Dann den Container neu starten:
docker compose up -d --force-recreate linkwardenVerifizieren: Melden Sie sich mit dem neuen Admin-Account an und speichern Sie einen Test-Link. Nach etwa einer Minute stehen Screenshot, PDF und HTML-Kopie bereit. Versuchen Sie in einem privaten Browser-Fenster, einen zweiten Account zu registrieren: Nach dem Setzen von NEXT_PUBLIC_DISABLE_REGISTRATION=true lehnt LinkWarden das mit „Registration is disabled.“ ab.
Schritt 7: Reverse Proxy und HTTPS (Produktion)
Für den Produktionsbetrieb mit einer eigenen Domain und HTTPS-Zertifikat passen Sie zwei Dinge an:
1. NEXTAUTH_URL in der .env anpassen: Der Wert muss die externe HTTPS-Domain samt dem Pflicht-Suffix /api/v1/auth enthalten:
NEXTAUTH_URL=https://links.meinedomain.tld/api/v1/auth2. Reverse Proxy konfigurieren: Leiten Sie Port 443 auf den Container-Port 3000 weiter. Binden Sie Port 3000 dann nur lokal ("127.0.0.1:3000:3000"), damit LinkWarden nicht am Proxy vorbei erreichbar ist. Nginx Proxy Manager, Traefik oder Caddy eignen sich gut dafür. Wie das auf einem Docker-Host mit Nginx Proxy Manager klappt, erklärt die Anleitung Nginx Proxy Manager einrichten: Reverse Proxy und SSL Schritt für Schritt.
Nach der Änderung der .env den LinkWarden-Container neu starten:
docker compose up -d --force-recreate linkwardenVerifizieren: Öffnen Sie https://links.meinedomain.tld im Browser. Das Schloss-Symbol zeigt ein gültiges TLS-Zertifikat. Login und OAuth-Callbacks funktionieren korrekt. Einen Test-Link speichern und nach einigen Sekunden prüfen, ob der Screenshot erscheint.
Schritt 8: Updates und Backups
Aktuell ist v2.16.3 (Stand September 2026). Mit dem :latest-Tag zieht ein Pull-Update die aktuelle Version:
cd /opt/linkwarden
docker compose pull
docker compose up -dLegen Sie vor jedem Update ein Backup der drei Datenordner an. Da ./pgdata und ./meili_data nach dem ersten Start root bzw. dem Postgres-Benutzer gehören, braucht tar Root-Rechte:
# Kurz stoppen, Backup erstellen, wieder starten
docker compose down
sudo tar czf ~/backup-linkwarden-$(date +%Y%m%d).tar.gz \
/opt/linkwarden/pgdata \
/opt/linkwarden/data \
/opt/linkwarden/meili_data
docker compose up -dFür eine automatisierte Backup-Strategie – etwa mit Restic auf eine externe Quelle – empfiehlt sich Restic Backup auf Linux und Windows einrichten und automatisieren.
Verifizieren: Nach dem Update zeigt docker compose ps alle Container im Status Up. docker compose logs linkwarden | head -20 enthält keine Fehlermeldungen zu Datenbankmigrationen oder fehlenden Umgebungsvariablen. Das Backup-Archiv ist vorhanden und lesbar: sudo tar tzf ~/backup-linkwarden-*.tar.gz | head.
Troubleshooting / Typische Fehler
- Login schlägt fehl: „Invalid URL“ oder Redirect-Fehler: NEXTAUTH_URL fehlt das Suffix
/api/v1/auth. Korrektes Format:http://HOST:3000/api/v1/auth. Nach Änderung:docker compose up -d --force-recreate linkwarden. - „Can't reach database server at postgres:5432“: LinkWarden startete vor PostgreSQL. Fix:
docker compose restart linkwarden; dauerhaft per Healthcheck independs_on. - POSTGRES_PASSWORD-Mismatch nach Passwortänderung –
pgdatawurde mit dem alten Passwort initialisiert. Passwort in PostgreSQL ändern:docker compose exec postgres psql -U postgres -c "ALTER USER postgres PASSWORD 'neues_passwort';"– oder Volume löschen (Datenverlust!) und neu initialisieren. - MeiliSearch startet im unsicheren Modus – MEILI_MASTER_KEY fehlt oder ist kürzer als 16 Zeichen. Neuen Key generieren (
openssl rand -base64 36), in.enveintragen unddocker compose up -d --force-recreate meilisearchausführen. - Archivierung schlägt lautlos fehl (Screenshots leer) – Playwright/Chromium braucht System-Libraries, die das offizielle
ghcr.io-Image enthält. Bei ARM64 prüfen:docker inspect ghcr.io/linkwarden/linkwarden:latest | grep -i architecture. - ./data-Volume falsch gemountet – Archive liegen im Container unter
/data/data; der Mount muss./data:/data/datalauten (nicht./data:/data), sonst gehen Archive beim Neustart verloren. - NEXTAUTH_URL nach Reverse-Proxy-Umstieg falsch – Hinter Nginx/Traefik muss
NEXTAUTH_URLdie externe HTTPS-URL sein, sonst schlagen OAuth-Callbacks und Session-Cookies fehl. - Backup mit tar meldet „Permission denied“: Die Datenordner gehören
root(./data,./meili_data) bzw. dem Postgres-Benutzer mit UID 70 (./pgdata).tarmitsudoausführen; Eigentümer nicht perchownändern.
Häufige Fragen
Kann ich LinkWarden ohne MeiliSearch betreiben?
Ja. Ohne meilisearch-Service und MEILI_MASTER_KEY nutzt LinkWarden die einfache PostgreSQL-Suche, ohne unscharfe Suche und Relevanzbewertung; für den Einstieg oder schwache Hosts genügt das.
Wie sperre ich die Registrierung nach der Ersteinrichtung?
NEXT_PUBLIC_DISABLE_REGISTRATION=true in der .env setzen und docker compose up -d --force-recreate linkwarden ausführen. Neue Benutzer lädt dann nur noch der Admin ein.
Wie viel Speicherplatz brauche ich für Archive?
Pro archiviertem Link (Screenshot, PDF, HTML-Snapshot via Monolith) 1–10 MB je nach Seite; 1.000 Links mit 3 MB ergeben 3 GB. Für Teams mit Tausenden Links eignet sich ein großes Volume oder S3-kompatibles Object Storage (AWS S3, MinIO, Hetzner Object Storage) über die SPACES_*-Variablen.
Wie konfiguriere ich KI-Tagging?
LinkWarden unterstützt mehrere KI-Provider für automatisches Tagging: lokal via Ollama (NEXT_PUBLIC_OLLAMA_ENDPOINT_URL), OpenAI (OPENAI_API_KEY) oder Anthropic (ANTHROPIC_API_KEY). Für datenschutzbewusste Teams ist Ollama mit einem lokalen Modell naheliegend. Wie Sie Ollama als Docker-Container betreiben, erklärt Ollama und Open WebUI mit Docker: eigenes lokales KI-Sprachmodell ohne Cloud.
Wie aktiviere ich E-Mail und Passwort-Reset?
In der .env setzen und Container neu starten: NEXT_PUBLIC_EMAIL_PROVIDER=true, EMAIL_FROM=noreply@meinedomain.tld, EMAIL_SERVER=smtp://user:pass@smtp.meinedomain.tld:587 und BASE_URL=https://links.meinedomain.tld. Ohne diese Werte funktioniert der Passwort-Reset nicht.
Wie stelle ich auf SSO (Google, GitHub, Authentik) um?
LinkWarden unterstützt über 60 SSO-Provider via NextAuth.js. Fügen Sie die entsprechenden Provider-Variablen in die .env ein, z. B. für Google: GOOGLE_CLIENT_ID und GOOGLE_CLIENT_SECRET. Die vollständige Liste der unterstützten Provider findet sich in der offiziellen LinkWarden Environment Variables Referenz.
Fazit
Die Installation ist dank des offiziellen Images unkompliziert, verlangt aber sorgfältig gesetzte Pflicht-Secrets; häufigster Stolperstein ist das NEXTAUTH_URL-Suffix. MeiliSearch liefert vollwertige Volltextsuche, lässt sich aber weglassen.
Weiterführende Anleitungen und Quellen
- Docker und Docker Compose auf Linux installieren – die Self-Hosting-Grundlage
- Traefik als Docker-Reverse-Proxy mit automatischem HTTPS einrichten
- Ollama und Open WebUI mit Docker: eigenes lokales KI-Sprachmodell ohne Cloud
- Restic Backup auf Linux und Windows einrichten und automatisieren
- Paperless-ngx mit Docker einrichten: papierlose Dokumentenverwaltung mit OCR
- Firefly III mit Docker installieren: Self-hosted Finanzverwaltung
Offizielle Quellen: LinkWarden Installationsdokumentation | LinkWarden auf GitHub | Environment Variables Referenz


