Memos mit Docker installieren: Leichtgewichtiger Self-Hosted Memo-Hub für Schnellnotizen
Memos ist mit ~22 MB Image-Größe und einem einzigen Container der ressourcensparendste Self-Hosted-Notiz-Hub überhaupt. Markdown-Support, REST-API und SQLite ohne Begleitdatenbank – in 10 Minuten läuft deine eigene Cloud-freie Notizlösung.

Schnelle Gedanken festhalten, Code-Snippets speichern, tägliche Reflexionen schreiben – und das alles ohne Google Keep, Notion oder andere Cloud-Dienste. Memos ist ein schlanker, selbst gehosteter Memo-Hub aus der Go-Welt: Das gesamte Image wiegt nur rund 22 MB, läuft als einzelner Container ohne Begleitdienst und speichert alles in einer lokalen SQLite-Datei. Mit über 60.000 GitHub-Stars und mehr als fünf Millionen Docker-Hub-Pulls ist Memos kein Geheimtipp mehr – sondern das meistgenutzte ressourcensparende Self-Hosted-Notiz-Tool überhaupt. Diese Anleitung richtet sich an Linux-Admins, KMU-Selfhoster und alle, die eine Notizlösung wollen, die wirklich keine externe Abhängigkeit hat.
Voraussetzungen
- Docker Engine 20.10+ und das Docker Compose Plugin v2 (
docker compose, nicht das altedocker-compose) müssen installiert sein. Wie du Docker und Compose auf einem frischen Ubuntu/Debian-Server einrichtest, erklärt die Anleitung Docker und Docker Compose auf Linux installieren. - Linux-Host, VM oder NAS mit Docker-Unterstützung (x86-64, ARM64 oder ARMv7 – Raspberry Pi 4/5 funktioniert problemlos).
- Mindestens 256 MB freier RAM und 1 GB Speicherplatz für Daten; das Image selbst beansprucht nur ~22 MB.
- Einen Texteditor (nano, vim oder VS Code via SSH) für
compose.yamlund.env. - Optional: Reverse Proxy (Caddy, Traefik oder Nginx Proxy Manager) für HTTPS – mehr dazu in Schritt 5.
Schritt 1: Projektordner anlegen
Alle Dateien für den Memos-Stack landen in einem dedizierten Verzeichnis. Wähle einen Pfad, der zu deinem Setup passt – /opt/memos ist für produktive Server sinnvoll, ~/memos reicht für den Heimserver:
mkdir -p /opt/memos
cd /opt/memosDocker legt das Volume-Unterverzeichnis memos-data beim ersten Start automatisch an. Da der Container als UID/GID 10001 läuft, musst du die Rechte vorab setzen, sonst schlägt der erste Schreibzugriff fehl:
mkdir -p /opt/memos/memos-data
sudo chown -R 10001:10001 /opt/memos/memos-dataVerifizieren: ls -la /opt/memos/ sollte das Verzeichnis memos-data mit Eigentümer 10001 anzeigen.
ls -la /opt/memos/
# Erwartete Ausgabe (gekürzt):
# drwxr-xr-x 2 10001 10001 ... memos-dataSchritt 2: .env-Datei anlegen
Für den SQLite-Basisbetrieb sind keine Pflicht-Umgebungsvariablen nötig. Trotzdem lohnt sich eine .env für die Produktionskonfiguration – besonders für MEMOS_INSTANCE_URL, ohne die Share-Links und Webhooks falsche URLs generieren:
# /opt/memos/.env
# Oeffentliche URL der Instanz (in Produktion setzen!)
MEMOS_INSTANCE_URL=https://memos.example.com
# Log-Level: debug, info, warn, error (Standard: info)
MEMOS_LOG_LEVEL=info
# Datenbanktyp: sqlite (Standard), mysql, postgres
MEMOS_DRIVER=sqlite
# Interner Port (Standard: 5230 - nur aendern, wenn noetig)
# MEMOS_PORT=5230Passe MEMOS_INSTANCE_URL auf deine tatsächliche Domain an oder kommentiere die Zeile aus, wenn du Memos nur lokal ohne Reverse Proxy betreibst.
Verifizieren: Die Datei ist vorhanden und enthält keine Syntaxfehler:
cat /opt/memos/.env
# Ausgabe: die key=value-Zeilen ohne FehlermeldungenSchritt 3: compose.yaml erstellen
Die folgende compose.yaml startet Memos mit SQLite, Healthcheck und env_file-Verweis. Kein version:-Feld – das ist der aktuelle Compose-Spec-Standard:
services:
memos:
image: neosmemo/memos:stable
container_name: memos
restart: unless-stopped
ports:
- "5230:5230"
volumes:
- ./memos-data:/var/opt/memos
env_file:
- .env
environment:
MEMOS_PORT: "5230"
MEMOS_DRIVER: sqlite
healthcheck:
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:5230/healthz"]
interval: 30s
timeout: 10s
retries: 3
start_period: 20sEin paar Hinweise zum Image-Tag: neosmemo/memos:stable ist die offizielle Empfehlung für den Produktionseinsatz. Der Tag latest entspricht dem Canary-Build und kann Breaking Changes enthalten – verwende ihn nur zum Testen. Für reproduzierbare Deployments kannst du stattdessen den versionierten Tag neosmemo/memos:0.29.1 verwenden.
Als Alternative zum Docker-Hub-Image ist ghcr.io/usememos/memos:stable (GitHub Container Registry) funktional identisch und von denselben Entwicklern gepflegt.
Verifizieren: YAML-Syntax prüfen:
docker compose -f /opt/memos/compose.yaml config
# Keine Fehlermeldungen; gibt die geparste Konfiguration ausSchritt 4: Memos starten und Ersteinrichtung
Starte den Stack aus dem Projektverzeichnis heraus:
cd /opt/memos
docker compose up -dDocker lädt das ~22 MB große Image herunter (einmalig) und startet den Container im Hintergrund. Nach etwa 20 Sekunden (start_period des Healthchecks) sollte der Container als healthy erscheinen:
docker compose ps
# Erwartete Ausgabe:
# NAME IMAGE COMMAND SERVICE STATUS PORTS
# memos neosmemo/memos:stable ... memos Up X min (healthy) 0.0.0.0:5230->5230/tcpLogs auf Fehler prüfen:
docker compose logs memos
# Erwartete Ausgabe (Auszug):
# memos | ... INFO Server is running on :5230Erreichbarkeit per curl testen:
curl -I http://localhost:5230
# HTTP/1.1 200 OK (oder 302 Found bei Weiterleitung auf /auth)Ersteinrichtung im Browser: Öffne http://<server-ip>:5230 im Browser. Beim ersten Aufruf erscheint die Registrierungsseite – der erste angelegte Account erhält automatisch Administratorrechte. Danach kannst du sofort Memos schreiben, Markdown nutzen und Tags vergeben.
Verifizieren: docker compose ps zeigt STATUS: Up ... (healthy); im Browser öffnet sich die Memos-Oberfläche ohne Fehler.
Schritt 5: HTTPS und Reverse Proxy (optional, empfohlen)
Memos hat keinen eingebauten TLS-Terminator. Für eine öffentlich erreichbare Instanz musst du einen Reverse Proxy vorschalten. Eine bewährte Kombination auf Linux-Servern ist Caddy mit automatischem Let's-Encrypt-Zertifikat – die Anleitung dazu findest du unter Caddy als Reverse Proxy einrichten.
Alternativ bietet sich Traefik an, wenn du mehrere Dienste per Label-Routing verwaltest: Traefik als Docker-Reverse-Proxy mit automatischem HTTPS.
Minimales Caddy-Beispiel (Caddyfile-Auszug):
memos.example.com {
reverse_proxy localhost:5230
}Vergiss nicht, in der .env die Variable MEMOS_INSTANCE_URL=https://memos.example.com zu setzen und den Stack neu zu starten:
cd /opt/memos
docker compose up -d --force-recreateVerifizieren: curl -I https://memos.example.com liefert HTTP/2 200 oder 302; das Browser-Schloss ist grün.
Schritt 6: Updates und Backup
Ein Memos-Update besteht aus zwei Befehlen – alle Daten liegen sicher im Volume:
cd /opt/memos
docker compose pull
docker compose up -dDocker ersetzt nur den Container-Layer; ./memos-data bleibt unangetastet. Vor jedem Update empfiehlt sich ein kurzes Backup:
# Backup: gesamtes Datenverzeichnis kopieren
cp -a /opt/memos/memos-data /opt/memos/memos-data.bak-$(date +%Y%m%d)Das Verzeichnis ./memos-data enthält die SQLite-Datenbank (memos_prod.db) und alle hochgeladenen Dateien. Es ist der einzige zu sichernde Pfad. Für eine automatisierte Offsite-Strategie eignet sich Restic mit automatischer Cron-Sicherung.
Um den alten Image-Layer zu bereinigen:
docker image prune -fVerifizieren: docker compose ps zeigt die neue Image-ID; alle bisherigen Memos sind nach dem Update noch vorhanden.
Eckdaten auf einen Blick
| Eigenschaft | Wert |
|---|---|
| Offizielles Image | neosmemo/memos:stable (Docker Hub) / ghcr.io/usememos/memos:stable (GHCR) |
| Aktuelle stabile Version | 0.29.1 (5. Juni 2026) |
| Image-Größe | ~22 MB (einzelnes Go-Binary) |
| Architekturen | linux/amd64, linux/arm64, linux/arm/v7 |
| Web-UI / API-Port | 5230 |
| Daten-Volume im Container | /var/opt/memos |
| Standard-Datenbank | SQLite (memos_prod.db) – kein Begleitcontainer nötig |
| Alternativen DBs | MySQL 8+, PostgreSQL |
| Container-User (UID/GID) | 10001 / 10001 (Non-Root) |
| Lizenz | MIT |
| GitHub-Stars | 60.600+ (Juni 2026) |
Wichtige Umgebungsvariablen
| Variable | Standard | Beschreibung |
|---|---|---|
| MEMOS_PORT | 5230 | Interner Listener-Port |
| MEMOS_ADDR | (leer = alle) | Bind-Adresse, z. B. 127.0.0.1 |
| MEMOS_DATA | /var/opt/memos | Datenpfad im Container |
| MEMOS_DRIVER | sqlite | Datenbanktyp: sqlite, mysql, postgres |
| MEMOS_DSN | (leer) | Verbindungsstring (Pflicht bei MySQL/PG) |
| MEMOS_INSTANCE_URL | (leer) | Öffentliche URL; Pflicht für Share-Links |
| MEMOS_LOG_LEVEL | info | debug, info, warn, error |
| MEMOS_UID / MEMOS_GID | 10001 | Container-User-IDs |
Troubleshooting / Typische Fehler
- „permission denied" beim Start: Der Container läuft als UID 10001. Wurde
./memos-dataals root angelegt, schlägt der Schreibzugriff fehl. Fix:sudo chown -R 10001:10001 /opt/memos/memos-data, danachdocker compose restart memos. - „bind: address already in use" auf Port 5230: Ein anderer Dienst belegt diesen Port. Fix: Host-Port in der
compose.yamländern, z. B."5231:5230", danachdocker compose up -d. - Share-Links und Webhooks zeigen falsche URLs:
MEMOS_INSTANCE_URList nicht gesetzt. In der.envdie öffentliche HTTPS-URL eintragen und den Container neu starten. - Tag
lateststattstableverwendet:latestentspricht dem Canary-Build und kann Breaking Changes enthalten. Image in dercompose.yamlaufneosmemo/memos:stableoder einen versionierten Tag (0.29.1) setzen. - Daten nach Neustart weg: Das Volume-Mapping fehlt in der
compose.yaml. Ohne./memos-data:/var/opt/memosschreibt Memos in den ephemeralen Container-Layer. Stack stoppen, Volume-Zeile ergänzen, neu starten. - MySQL-Verbindungsfehler beim Start: Bei
MEMOS_DRIVER=mysqlmussMEMOS_DSNexakt im Formatuser:pass@tcp(host:3306)/dbnamegesetzt sein. Fehlendestcp()-Wrapper führt zu „invalid DSN". Außerdemdepends_onmitcondition: service_healthyergänzen. - Browser zeigt veraltetes Layout nach Update: Browser-Cache ist veraltet. Harter Reload mit Strg+Umschalt+R (Windows/Linux) oder Cmd+Umschalt+R (macOS) erzwingt das Nachladen aller Assets.
Häufige Fragen
Brauche ich eine externe Datenbank?
Nein. Memos läuft standardmäßig mit SQLite ohne jeden Begleitcontainer – ideal für Einzelpersonen und kleine Teams. MySQL 8+ und PostgreSQL sind optionale Alternativen, wenn du einen bestehenden DB-Stack nutzen oder bei sehr hohem Schreibvolumen auf mehr Parallelität setzen möchtest. Für die meisten Anwendungsfälle ist SQLite mehr als ausreichend.
Welches Image-Tag soll ich verwenden?
Für den Produktionsbetrieb: neosmemo/memos:stable. Für reproduzierbare Deployments: ein versionierter Tag wie neosmemo/memos:0.29.1. Den Tag canary oder latest solltest du nur auf einem Testsystem verwenden – er entspricht dem aktuellen Entwicklungsstand und kann instabile Features oder API-Änderungen enthalten.
Wie sichere ich meine Memos-Daten?
Das Verzeichnis ./memos-data enthält alles: die SQLite-Datenbank memos_prod.db und alle hochgeladenen Dateien. Eine vollständige Sicherung besteht aus einer einfachen Kopie dieses Ordners. Für eine automatisierte Lösung mit Versionierung und optionalem Offsite-Upload empfiehlt sich Restic – die Einrichtung beschreibt die Anleitung Restic Backup auf Linux automatisieren.
Wie aktiviere ich HTTPS?
Memos selbst hat keinen integrierten TLS-Terminator. Schalte einen Reverse Proxy vor, der SSL terminiert und Anfragen an localhost:5230 weiterleitet. Setze anschließend MEMOS_INSTANCE_URL in der .env auf deine HTTPS-Domain und starte den Container neu.
Läuft Memos auf einem Raspberry Pi?
Ja. Das offizielle Image unterstützt linux/arm64 und linux/arm/v7. Auf einem Raspberry Pi 4 oder 5 mit 64-Bit-Betriebssystem verwendest du dieselbe compose.yaml ohne Änderungen – Docker zieht automatisch die passende Architektur-Variante.
Wie aktualisiere ich Memos auf eine neue Version?
Mit zwei Befehlen: docker compose pull && docker compose up -d. Docker ersetzt nur den Container; das Volume ./memos-data bleibt unangetastet. Sichere das Datenverzeichnis vorher kurz als Schnappschuss.
Kann ich Memos mit MySQL oder PostgreSQL betreiben?
Ja. Setze MEMOS_DRIVER=mysql (oder postgres) und trage den Verbindungsstring in MEMOS_DSN ein – für MySQL im Format user:pass@tcp(host:3306)/dbname. Du benötigst dann einen Datenbank-Begleitcontainer und ein depends_on mit condition: service_healthy, damit Memos erst startet, wenn die Datenbank bereit ist.
Fazit
Memos ist das Paradebeispiel für „weniger ist mehr" im Self-Hosting: 22 MB Image, ein einziger Container, SQLite ohne Overhead, und trotzdem Markdown-Rendering, REST-API, Telegram-Bot-Integration und WebDAV an Bord. Der Aufwand für Installation und Betrieb ist minimal – der erste Start dauert keine zehn Minuten. Wer schnelle Gedanken, Daily-Notes, Code-Snippets oder Team-interne Kurznachrichten ohne Cloud-Abhängigkeit festhalten möchte, bekommt mit Memos ein ausgesprochen solides Werkzeug. Einzige Einschränkung: Für sehr umfangreiche kollaborative Dokumentation oder ein vollständiges Team-Wiki ist ein schwergewichtigeres Tool wie BookStack oder AFFiNE die bessere Wahl.
Weiterführende Anleitungen und Quellen
- Docker und Docker Compose auf Linux installieren – die Self-Hosting-Grundlage
- Traefik als Docker-Reverse-Proxy mit automatischem HTTPS
- Restic Backup auf Linux und Windows einrichten und automatisieren
- Docker Compose absichern: Secrets, Healthchecks, Non-Root und Read-Only
- AFFiNE mit Docker installieren: All-in-One-Notion-Alternative
Offizielle Quellen: Memos Docker-Dokumentation (usememos.com) · Memos GitHub Repository · neosmemo/memos auf Docker Hub