Keyboard-first, Vim-friendly Markdown notes โ self-hosted web app backed by a Go server.
50K+
Keyboard-first, Vim-friendly Markdown notes. Your notes stay as ordinary
.md files on disk โ no database, no lock-in. This image runs the
self-hosted web app + Go server: open it in a browser and edit a vault
mounted from your host.
linux/amd64, linux/arm64The server binds to 0.0.0.0 inside the container, so it requires an auth
token โ it refuses to start without one. Generate a token and pass it in:
TOKEN=$(openssl rand -hex 32)
docker run -d --name zennotes \
-p 127.0.0.1:7878:7878 \
-e ZENNOTES_AUTH_TOKEN="$TOKEN" \
-v "$HOME/Notes/ZenNotesVault:/workspace" \
-v "$HOME/zennotes-data:/data" \
--read-only --tmpfs /tmp \
--cap-drop ALL --security-opt no-new-privileges \
adibhanna/zennotes:latest
echo "Open http://localhost:7878 and log in with: $TOKEN"
Paste the token into the browser when prompted. After login the browser uses a session cookie, so you won't need to re-enter it on refresh.
Prefer a persisted token? Write one to a file and point the server at it with
-e ZENNOTES_AUTH_TOKEN_FILE=/data/auth-tokenplusopenssl rand -hex 32 > ./zennotes-data/auth-token.
services:
zennotes:
image: adibhanna/zennotes:latest
container_name: zennotes
restart: unless-stopped
ports:
- "127.0.0.1:7878:7878"
environment:
ZENNOTES_AUTH_TOKEN: "change-me-to-a-long-random-string"
volumes:
- ./vault:/workspace # your notes (plain Markdown)
- ./data:/data # server config
read_only: true
tmpfs:
- /tmp
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
| Path | Purpose |
|---|---|
/workspace | Your vault โ plain Markdown files on the host |
/data | Server config (server.json) |
| Variable | Purpose | Default |
|---|---|---|
ZENNOTES_AUTH_TOKEN | Login token. Required for this image (non-loopback bind). | โ |
ZENNOTES_AUTH_TOKEN_FILE | Read the token from a file instead (Docker/K8s secrets). | โ |
ZENNOTES_BEHIND_TLS | Set 1 behind a TLS proxy (Secure cookies + HSTS). | 0 |
ZENNOTES_TRUSTED_PROXIES | CIDR list of trusted reverse proxies. | โ |
ZENNOTES_ALLOWED_ORIGINS | Extra cross-origin clients (same-origin always works). | same-origin |
ZENNOTES_BROWSE_ROOTS | Directories allowed as vault candidates. | /workspace |
ZENNOTES_BASE_PATH | Serve under a subpath behind a reverse proxy. | โ |
ZENNOTES_MAX_NOTE_BYTES / ZENNOTES_MAX_ASSET_BYTES | Per-request size caps. | 10 MiB / 50 MiB |
latest โ most recent releaseX.Y.Z / X.Y โ pinned versions (e.g. 2.0.1, 2.0)Plain-file Markdown vault ยท Vim mode & leader-key flows ยท command palette ยท edit / split / preview modes ยท tasks, tags, search, archive, trash ยท daily notes ยท KaTeX math, Mermaid, TikZ, JSXGraph diagrams ยท wiki links & callouts ยท first-party MCP server for AI tools.
The image runs as a non-root user (uid 65532) by default. The quick-start
and compose examples above also run it read-only, with /tmp on tmpfs and all
Linux capabilities dropped โ recommended.
It requires an auth token and warns periodically if exposed on a non-loopback
bind over plain HTTP. If you expose it beyond your LAN, put it behind a reverse
proxy, terminate TLS there, and set ZENNOTES_BEHIND_TLS=1 plus
ZENNOTES_TRUSTED_PROXIES.
Full guide: Self-Host with Dockerโ
Content type
Image
Digest
sha256:9f90fd2d9โฆ
Size
41.4 MB
Last updated
2 days ago
docker pull adibhanna/zennotes