SilverBullet 2.12.0 mit Docker Compose: private Markdown-Wissensbasis ohne Datenbank
SilverBullet speichert Notizen als Markdown-Dateien ohne Datenbank. Die getestete Anleitung zeigt Version 2.12.0 mit Docker Compose: festes Image, Healthcheck, Datei-API, Backup und Wiederherstellung sowie typische Fehler.
Geprüft am 11.10.2026 · für silverbullet 2.12.0
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

SilverBullet ist eine selbst gehostete Notiz- und Wissensplattform. Die Inhalte liegen als Markdown-Dateien in einem Ordner („Space“) statt in einer Datenbank; Backup und Migration gelingen mit Dateiwerkzeugen.
Beschrieben ist SilverBullet 2.12.0 mit Docker Compose, getestet am 20.09.2026 (Ubuntu, Docker 29.1.3, Compose 2.40.3, Hostport 3999). Logzeilen, Statuscodes und Messwerte stammen aus diesem Lauf; Ungeprüftes ist gekennzeichnet.
Wofür SilverBullet gut ist und wo die Grenzen liegen
SilverBullet ist quelloffen und per Lua („Space Lua“) erweiterbar. Der Rust-Server liefert den Client aus, stellt die Datei-API bereit, übernimmt die Anmeldung und enthält Headless-Chromium für serverseitiges Lua.
- Backup: Ein Archiv des Datenordners genügt, kein Datenbank-Dump.
- Migration: Ordner auf einen anderen Host kopieren und mounten.
- Kein Vendor-Lock-in: Jeder Texteditor liest die Dateien.
- Versionierung: Git über dem Datenordner ist möglich.
Grenzen: SB_USER definiert genau einen Zugang (Bootmodus „single-space“), ohne Rollen, Gruppen, Freigaben oder seitenbezogene Rechte.
Abgrenzung zu anderen Notiz- und Wiki-Werkzeugen
SilverBullet passt, wenn der Systemzustand ein Markdown-Ordner sein soll, Sie eigene Kommandos und Vorlagen per Space Lua nutzen und wenig Ressourcen haben (Raspberry Pi, kleiner vServer). Mehrere Personen mit unterschiedlichen Rechten brauchen ein Werkzeug mit Rollenmodell.
Voraussetzungen und Ressourcenbedarf
Sie benötigen einen Linux-Host mit Docker Engine, Compose-Plugin und freiem Port. Das Image basiert auf Alpine.
| Eigenschaft | Wert | Herkunft der Angabe |
|---|---|---|
| Architekturen | x86-64, ARM64, ARMv7 | offizielle Dokumentation |
| Getestete Version | 2.12.0, Release vom 17.09.2026 | eigener Testlauf |
| Container-Port | 3000 | Dokumentation, im Test bestätigt |
| Datenordner im Container | /data | Dokumentation, im Test bestätigt |
| Arbeitsspeicher im Leerlauf | 5,469 MiB | eigene Messung mit docker stats |
| Zusätzliche Dienste | keine, ein einzelner Container ohne Datenbank | eigener Testlauf |
| Lizenz | MIT | GitHub-API, Abruf 20.09.2026 |
Unter Last, besonders mit Chromium-Laufzeit, steigt der RAM-Bedarf über den gemessenen Leerlaufwert.
Laut Dokumentation spart die Variante ohne Chromium (-slim, etwa :2.12.0-slim) Speicher, ohne serverseitiges Lua. Nicht getestet.
Die compose.yml Schritt für Schritt
Die Dokumentation verwendet :latest. Mit fester Version aktualisiert docker compose pull nicht unangekündigt.
services:
silverbullet:
# Feste Version statt :latest, damit Updates reproduzierbar bleiben
image: ghcr.io/silverbulletmd/silverbullet:2.12.0
# Container startet nach Hostneustart und nach Absturz wieder
restart: unless-stopped
environment:
# Format benutzer:passwort, Platzhalter unbedingt ersetzen
- SB_USER=admin:BitteHierEinStarkesPasswort
volumes:
# Bind-Mount: der Space liegt als normaler Ordner auf dem Host
- ./data:/data
ports:
# Nur lokal erreichbar; von außen über Reverse Proxy mit TLS
- 127.0.0.1:3999:3000
restart: unless-stoppedstartet den Container nach Hostneustart oder Absturz neu, nicht nach bewusstem Stoppen.SB_USER(benutzer:passwort) aktiviert die Anmeldung; ohne die Variable gibt es keinen Anmeldeschutz../data:/dataist ein Bind-Mount: Die Markdown-Dateien liegen sichtbar auf dem Host.127.0.0.1:3999:3000veröffentlicht den Port nur auf Loopback (im Test ohne Adressbindung); nach außen über einen Reverse Proxy.
Das Passwort lässt sich in eine .env-Datei neben der compose.yml auslagern:
# Datei .env neben der compose.yml, nicht ins Git-Repository aufnehmen
SB_USER=admin:BitteHierEinStarkesPasswort
In der compose.yml steht dann - SB_USER=${SB_USER}. Nicht getestet.
Installation und erster Start
Im Test in dieser Reihenfolge ausgeführt:
# Projektordner anlegen und hineinwechseln
mkdir -p ~/silverbullet
cd ~/silverbullet
# Datenordner vorab anlegen, damit die UID-Erkennung greift
mkdir -p data
# compose.yml aus dem vorherigen Abschnitt in diesem Ordner speichern,
# danach den Stack im Hintergrund starten
docker compose up -d
# Status der Container anzeigen
docker compose ps
# Startausgaben des Dienstes ansehen
docker compose logs
Den Datenordner vor dem ersten Start als späterer Verwaltungsbenutzer anlegen (siehe nächster Abschnitt).
Verifizieren: docker compose ps zeigt den Container als running, zunächst mit health: starting, kurz darauf healthy.
Was beim ersten Start passiert
Ausgabe von docker compose logs im Test:
Will run SilverBullet with UID 1000, inferred from the owner of /data (set PUID environment variable to override)
Creating 'silverbullet' group (with GID 1000) and 'silverbullet' user (with UID 1000) inside container
Running SilverBullet as user configured with PUID 1000 and PGID 1000
INFO silverbullet::server: SilverBullet 2.12.0-0-g3b669b81-2026-09-17T13-06-11Z
INFO silverbullet::server: Data folder: /data
INFO silverbullet::boot: boot mode: single-space (SB_USER is set)
INFO silverbullet_server_runtime_chrome::config: runtime Chrome detected: /usr/bin/chromium-headless-shell
INFO silverbullet::server: SilverBullet is now running: http://0.0.0.0:3000
- UID-Erkennung: Der Container übernimmt Besitzer und Gruppe von
/data(im Test UID 1000),chownentfällt.PUIDundPGIDübersteuern das laut Dokumentation. - Versionszeile:
SilverBullet 2.12.0-0-g3b669b81nennt Version und Commit, verlässlicher als der Tag. - Bootmodus:
single-space (SB_USER is set)bestätigt die Anmeldung; fehlt die Zeile, ist kein Schutz aktiv. - Chromium-Laufzeit:
runtime Chrome detected: Das Standard-Image unterstützt serverseitiges Lua. - Startmeldung:
0.0.0.0:3000gilt im Container; nach außen gilt die Portbindung.
Funktionsprüfung und Healthcheck
Das Image bringt einen Healthcheck mit (curl ist enthalten). Definition auslesen:
# Healthcheck-Definition des laufenden Containers anzeigen
docker inspect --format '{{json .Config.Healthcheck}}' silverbullet-silverbullet-1
Ergebnis im Test:
CMD-SHELL curl --fail "http://localhost:$SB_PORT/.instance" || exit 1
Skripte, die auf den Start warten, fragen healthy ab.
Im Test ausgeführte HTTP-Aufrufe:
# Startseite ohne Anmeldung, liefert die Anmeldeseite
curl -s -o /dev/null -w "%{http_code}\n" http://localhost:3999/
# Eine Inhaltsseite ohne Anmeldung
curl -s -o /dev/null -w "%{http_code}\n" http://localhost:3999/index
# Einfacher Erreichbarkeitsendpunkt
curl -s -o /dev/null -w "%{http_code}\n" http://localhost:3999/.ping
| Aufruf | Beobachtete Antwort | Bedeutung |
|---|---|---|
| GET / ohne Anmeldung | HTTP 200, 2578 Byte, text/html | Anmeldeseite wird ausgeliefert |
| GET /index ohne Anmeldung | HTTP 302 | Weiterleitung zur Anmeldung |
| GET /.ping | HTTP 200 | Erreichbarkeitsprüfung |
| docker compose ps nach Start | health: starting, danach healthy | eingebauter Healthcheck greift |
HTTP 200 auf / zeigt nur, dass der Webserver antwortet; Monitoring nutzt /.ping oder den Healthcheck.
Verifizieren: /.ping liefert 200, /index ohne Anmeldung 302.
Anmeldung und Zugangsschutz
Anmeldung per POST auf /.auth mit den Feldern username und password:
# Anmelden und Sitzungscookie in eine Datei schreiben
curl -s -c cookies.txt -o /dev/null -w "%{http_code}\n" \
-X POST \
-d "username=admin" \
-d "password=BitteHierEinStarkesPasswort" \
http://localhost:3999/.auth
# Mit dem Cookie eine geschuetzte Seite abrufen
curl -s -b cookies.txt -o /dev/null -w "%{http_code}\n" http://localhost:3999/index
Verifizieren: Mit korrektem Passwort setzt der POST ein Sitzungscookie, /index liefert danach HTTP 200.
Hinweis aus dem Test: Auch ein falsches Passwort liefert HTTP 200 (mit Invalid, ohne Sitzung). Skripte prüfen daher auf ein Sitzungscookie.
Das Passwort ist der einzige Schutz: lang, zufällig, nur hier verwendet.
Die Datei-API für Automatisierung und Backup
Skripte und Importe nutzen die Datei-API unter /.fs/; Schreiben auf den Seitenpfad scheitert:
# Falscher Pfad: direkt auf den Seitennamen schreiben
curl -s -o /dev/null -w "%{http_code}\n" \
-X PUT --data-binary "Inhalt" \
http://localhost:3999/Testseite.md
# Richtiger Pfad: ueber das Praefix /.fs/ mit Sitzungscookie
curl -s -b cookies.txt -o /dev/null -w "%{http_code}\n" \
-X PUT --data-binary "Inhalt" \
http://localhost:3999/.fs/Test.md
# Dateiliste des Space als JSON abrufen
curl -s -b cookies.txt http://localhost:3999/.fs/
| Aufruf | Beobachtete Antwort | Einordnung |
|---|---|---|
| PUT /Testseite.md | HTTP 405 | kein API-Pfad, Methode nicht erlaubt |
| PUT /.fs/Test.md mit Sitzungscookie | HTTP 200 | Datei erschien sofort als data/Test.md auf dem Host |
| GET /.fs/ mit Sitzungscookie | HTTP 200, JSON-Liste | Felder name, created, lastModified, contentType, size und perm |
| PUT /.fs/Hack.md ohne Anmeldung | HTTP 401 | Schreibzugriff korrekt abgewiesen |
| GET /.fs/index.md ohne Anmeldung | HTTP 401 | Lesezugriff korrekt abgewiesen |
Für Backups ist der direkte Dateizugriff auf dem Host einfacher.
Persistente Daten und Rechte
Nach dem ersten Start enthielt ./data zwei Einträge, beide UID 1000, ohne erhöhte Rechte bearbeitbar:
# Inhalt des Datenordners samt Rechten und Besitzer anzeigen
ls -la data
| Datei | Rechte | Zweck |
|---|---|---|
| .silverbullet.auth.json | 600 | Authentifizierungszustand |
| index.md | 644 | Startseite des Space |
.silverbullet.auth.json (nur mit ls -a sichtbar) per .gitignore aus Git und Dateisync ausschließen, aber mitsichern.
Sichere Netzwerkfreigabe und Reverse Proxy mit TLS
Nicht getestet (Test lokal ohne Domain, Zertifikat und Proxy); Grundlage sind Dokumentation und Betriebspraxis.
Außerhalb von localhost ist laut Dokumentation TLS nötig, sonst laufen Zugangsdaten und Notizen im Klartext.
- Containerport nie direkt ins Internet veröffentlichen; der Reverse Proxy terminiert das Zertifikat.
- Proxy auf demselben Host: Bindung
127.0.0.1:3999:3000beibehalten. - Alternativ Container und Proxy in ein gemeinsames Docker-Netzwerk hängen und
portsweglassen. - Am Proxy HTTP auf HTTPS umleiten, optional zusätzliche Authentifizierung vorschalten.
Backup und Wiederherstellung
Beide Schritte liefen im Test.
# In den Projektordner wechseln
cd ~/silverbullet
# Backup des kompletten Datenordners erstellen
tar czf sb-backup.tgz -C ~/silverbullet data
# Inhalt des Archivs kontrollieren, die versteckte Auth-Datei muss dabei sein
tar tzf sb-backup.tgz
Wiederherstellungstest mit einer gezielt gelöschten Datei:
# Eine Datei absichtlich entfernen
rm ~/silverbullet/data/Test.md
# Aus dem Archiv wiederherstellen
tar xzf sb-backup.tgz -C ~/silverbullet
# Ergebnis pruefen, die Datei muss wieder vorhanden sein
ls -la ~/silverbullet/data
Verifizieren: tar tzf listet data/.silverbullet.auth.json und data/index.md; nach dem Entpacken ist Test.md wieder vorhanden. Im Test war das Archiv der frischen Instanz 1,1 KB groß.
tarauf den ganzen Ordner erfasst die Auth-Datei, eigene Dateilisten oft nicht.- Während des Archivierens geschriebene Seiten können unvollständig sein; für ein sicheres Backup vorher
docker compose stop.
Umstieg auf SilverBullet Server 2.12.0: Sichern Sie den Space-Ordner und die Compose-Konfiguration, ändern Sie dann den Image-Tag und erstellen Sie den Container neu. Für bestehende 2.11-Installationen beschreibt der Hersteller den normalen Docker-Updateweg. Eigene Space-Lua-Erweiterungen benötigen dennoch eine Prüfung: view.new entfällt; verwenden Sie widget.new und übergeben Sie das Widget an view.define als widget statt view. Die bisherigen Top-/Bottom-Widget-Hooks sind abgekündigt. Die Dokumentation liegt jetzt unter docs.silverbullet.md. Die Desktop-Anwendung wechselt separat von Tauri auf Electron; nach deren Umstieg müssen Space-Synchronisierungen erneut aktiviert werden. Das ist kein zusätzlicher Schritt für den Docker-Server.
Updates und Rollback-Grenzen
Laut Dokumentation Version in der compose.yml anpassen, dann:
# Vor jedem Update: Backup des Datenordners erstellen
tar czf sb-backup-vor-update.tgz -C ~/silverbullet data
# Danach die Versionsnummer in der compose.yml anpassen
# und das neue Image herunterladen
docker compose pull
# Laufenden Container stoppen
docker compose stop
# Mit dem neuen Image wieder starten
docker compose up -d
# Laufende Version in den Logs gegenpruefen
docker compose logs | grep "SilverBullet 2."
:latest zeigt auf das letzte Release, :v2 ebenso, :edge auf den letzten Commit im Hauptzweig und ist für den Betrieb ungeeignet. Aktuell ist 2.11.1 (Patch-Release vom 22.09.2026, Releases).
Rollback ist unkritisch (keine Datenbankmigration). Ein Backup vor dem Update bleibt Pflicht, da ein neuer Stand Hilfsdateien im Space ändern kann. Upgrade und Downgrade wurden nicht getestet.
Verifizieren: Die Logzeile SilverBullet 2. nennt die neue Version, docker compose ps zeigt healthy.
Typische Fehler mit Diagnose und Lösung
| Symptom | Ursache | Lösung |
|---|---|---|
| Schreibzugriffe scheitern mit Rechtefehlern | Datenordner gehört einem anderen Benutzer, die UID-Erkennung übernimmt ihn | Besitzer korrigieren oder PUID/PGID setzen, Container neu starten |
| Jeder kann ohne Anmeldung auf die Notizen zugreifen | SB_USER fehlt | SB_USER ergänzen, im Log auf single-space (SB_USER is set) prüfen |
| Skript bekommt beim Schreiben einer Seite HTTP 405 | Schreibzugriff auf den Seitennamen statt über die Datei-API | Pfadpräfix /.fs/ verwenden, also PUT auf /.fs/Seite.md |
| Monitoring meldet Anmeldung trotz falschem Passwort als erfolgreich | /.auth liefert auch bei falschem Passwort HTTP 200 mit Invalid | Auf Sitzungscookie oder Abruf einer geschützten Seite prüfen |
| Container startet nicht, Fehlermeldung zum Port | Hostport belegt | Mit ss -tlnp prüfen, freien Hostport eintragen; Containerport 3000 bleibt |
| Anmeldung funktioniert lokal, aber nicht über die Domain | Zugriff ohne TLS oder fehlerhafte Proxy-Konfiguration | Reverse Proxy mit gültigem Zertifikat vorschalten |
Einstieg in die Diagnose:
# Laufzustand und Healthcheck-Status aller Container des Stacks
docker compose ps
# Startausgaben und laufende Meldungen des Dienstes
docker compose logs --tail 50
Laut Dokumentation führt der Container beim Start die Seite CONTAINER_BOOT als Bash-Skript aus, etwa für apk add. Nicht getestet. Schreibzugriff auf den Space heißt also Befehlsausführung im Container.
Saubere Deinstallation
Im Projektordner:
# In den Projektordner wechseln
cd ~/silverbullet
# Container stoppen und entfernen
docker compose down
# Optional: das heruntergeladene Image entfernen
docker image rm ghcr.io/silverbulletmd/silverbullet:2.12.0
docker volume prune oder down -v erfassen den Bind-Mount ./data nicht.
Warnung vor Datenverlust: ./data enthält den gesamten Space. Vor dem Löschen ein Archiv wie oben erstellen und auf einem anderen Datenträger ablegen.
Was in dieser Umgebung nicht geprüft wurde
Nur aus der Dokumentation: Reverse Proxy mit TLS, slim-Variante, CONTAINER_BOOT, Upgrade, Downgrade, Mehrbenutzerbetrieb, OIDC, serverseitiges Lua, .env-Auslagerung. Alles Übrige lief im Test.
Einordnung und Projektlage
Laut GitHub-API (Abruf 20.09.2026) wird silverbulletmd/silverbullet aktiv gepflegt, Lizenz MIT; nach 2.12.0 (17.09.2026) folgte am 22.09.2026 das Patch-Release 2.11.1.
Für kleine Unternehmen eignet sich SilverBullet als persönliche oder abteilungsinterne Wissensablage.
Passende Anleitungen auf S-EDV
- TriliumNext mit Docker für das Wissensmanagement: Alternative mit verschachtelten Notizbäumen.
- Memos mit Docker für Schnellnotizen: schlanker Ansatz für kurze Notizen.
- Traefik als Reverse Proxy mit HTTPS einrichten: Zugriff über eine Domain mit TLS.
Quellen
- GitHub: silverbulletmd/silverbullet: Repository, Lizenz, Sterne und Aktivität, Abruf 20.09.2026.
- SilverBullet-Dokumentation: Install/Docker: Image, Architekturen, Release-Kanäle, UID-Verhalten, TLS-Hinweis und Upgrade-Weg, Abruf 20.09.2026.
- SilverBullet: Projektseite und Dokumentation: Funktionsumfang, Space-Konzept und Space Lua, Abruf 20.09.2026.
- GitHub: SilverBullet Releases: Release 2.12.0 vom 17.09.2026, Abruf 20.09.2026.


