Repository navigation
Docker Compose Examples
Complete Docker Compose examples for common Flatnotes-Enhanced deployment scenarios. If you're brand new, start with the Getting Started & Installation page — this page assumes you already know you want Compose.
Note
Notes that apply to every example below:
Security note: Version 1.18.2 hardens attachment and branding responses, and enforces read-only mode at the API level. No compose file changes are needed. If you use FLATNOTES_AUTH_TYPE=read_only, state-changing requests now return 403.
- All examples use
dockerbobw/flatnotes-enhanced:latest. Pin to a specific version (e.g.:v1.18.2) if you prefer controlled upgrades. - The
/datavolume holds your notes and the.flatnotesfolder (database, branding, backups). Back this up. - Multi-arch image: works on
linux/amd64andlinux/arm64(Synology, Raspberry Pi, Apple Silicon). - The
version:key is no longer needed incompose.yml— it's deprecated in Compose v2. -
restart: unless-stoppedsurvives reboots and crashes, but still respects a deliberatedocker compose stop.
The most common setup. Create a compose.yml next to a data/ folder:
services:
flatnotes-enhanced:
container_name: flatnotes-enhanced
image: dockerbobw/flatnotes-enhanced:latest
restart: unless-stopped
ports:
- "8080:8080"
volumes:
- ./data:/data
environment:
TZ: "Europe/Berlin"
FLATNOTES_AUTH_TYPE: "password"
FLATNOTES_USERNAME: "user"
FLATNOTES_PASSWORD: "changeMe!"
FLATNOTES_SECRET_KEY: "changeMeToo-a-long-random-string"Start it:
docker compose up -dThen open http://localhost:8080.
Note
FLATNOTES_SECRET_KEY should be a long random string. It signs login tokens — if it changes, existing sessions are invalidated. Generate one with openssl rand -hex 32.
Keeps passwords and keys out of your compose file and out of docker inspect output.
mkdir -p secrets
echo "changeMe!" > secrets/flatnotes_password.txt
openssl rand -hex 32 > secrets/flatnotes_secret_key.txt
chmod 600 secrets/*.txtservices:
flatnotes-enhanced:
container_name: flatnotes-enhanced
image: dockerbobw/flatnotes-enhanced:latest
restart: unless-stopped
ports:
- "8080:8080"
volumes:
- ./data:/data
secrets:
- flatnotes_password
- flatnotes_secret_key
environment:
TZ: "Europe/Berlin"
FLATNOTES_AUTH_TYPE: "password"
FLATNOTES_USERNAME: "user"
FLATNOTES_PASSWORD: /run/secrets/flatnotes_password
FLATNOTES_SECRET_KEY: /run/secrets/flatnotes_secret_key
secrets:
flatnotes_password:
file: ./secrets/flatnotes_password.txt
flatnotes_secret_key:
file: ./secrets/flatnotes_secret_key.txtdocker compose up -d| Secret | Environment variable |
|---|---|
flatnotes_secret_key |
FLATNOTES_SECRET_KEY |
flatnotes_password |
FLATNOTES_PASSWORD |
flatnotes_totp_key |
FLATNOTES_TOTP_KEY |
oidc_client_secret |
OIDC_CLIENT_SECRET |
oauth_client_secret |
OAUTH_CLIENT_SECRET |
Note
Secret files are read at container startup. If you rotate a secret, recreate the container (docker compose up -d --force-recreate) for the new value to take effect.
For Google, PocketID, Authelia, Authentik, Keycloak, and other OIDC providers.
services:
flatnotes-enhanced:
container_name: flatnotes-enhanced
image: dockerbobw/flatnotes-enhanced:latest
restart: unless-stopped
ports:
- "8080:8080"
volumes:
- ./data:/data
secrets:
- flatnotes_secret_key
- oidc_client_secret
environment:
TZ: "Europe/Berlin"
FLATNOTES_AUTH_TYPE: "oidc"
FLATNOTES_SECRET_KEY: /run/secrets/flatnotes_secret_key
AUTH_PROVIDER: "oidc"
OIDC_DISCOVERY_URL: "https://your-provider/.well-known/openid-configuration"
OIDC_CLIENT_ID: "your-client-id"
OIDC_CLIENT_SECRET: /run/secrets/oidc_client_secret
OIDC_REDIRECT_URI: "https://notes.example.com/api/auth/oidc/callback"
secrets:
flatnotes_secret_key:
file: ./secrets/flatnotes_secret_key.txt
oidc_client_secret:
file: ./secrets/oidc_client_secret.txtThings to get right:
-
OIDC_REDIRECT_URImust be reachable from the browser and match exactly what is registered with your identity provider — scheme, host, path, no trailing slash. - When
FLATNOTES_AUTH_TYPE=oidc, the login page shows a "Continue with OIDC" button instead of the password form. - If you don't need secrets, you can put
OIDC_CLIENT_SECRETdirectly inenvironment:— the Docker secrets pattern is optional.
Note
For GitHub OAuth instead of OIDC, use AUTH_PROVIDER=github with OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET, and OAUTH_REDIRECT_URI. See the README's SSO section.
If you already run Nginx, Caddy, or Nginx Proxy Manager in Docker, put Flatnotes-Enhanced on the same network instead of publishing a port to the host. The reverse proxy then reaches it by container name.
services:
flatnotes-enhanced:
container_name: flatnotes-enhanced
image: dockerbobw/flatnotes-enhanced:latest
restart: unless-stopped
# no "ports:" section — the reverse proxy reaches it by container name
volumes:
- ./data:/data
secrets:
- flatnotes_password
- flatnotes_secret_key
environment:
TZ: "Europe/Berlin"
FLATNOTES_AUTH_TYPE: "password"
FLATNOTES_USERNAME: "user"
FLATNOTES_PASSWORD: /run/secrets/flatnotes_password
FLATNOTES_SECRET_KEY: /run/secrets/flatnotes_secret_key
networks:
- proxy
networks:
proxy:
external: true
secrets:
flatnotes_password:
file: ./secrets/flatnotes_password.txt
flatnotes_secret_key:
file: ./secrets/flatnotes_secret_key.txtdocker network create proxyThen point your reverse proxy at http://flatnotes-enhanced:8080.
When both services are on the same Docker network, the reverse proxy can reach flatnotes-enhanced by name. Publishing the port to the host is unnecessary and widens the attack surface — traffic that arrives on localhost:8080 bypasses the proxy (and its HTTPS and auth).
Point the reverse proxy at HTTPS. This isn't just confidentiality:
- SSO callback URLs are often restricted to HTTPS
- The clipboard API (
navigator.clipboard) requires a secure context - Browser features like PWA install are restricted to HTTPS or localhost
On a NAS you often want notes and app data on separate volumes, and you may need to pass the host timezone files through. This is the pattern used by the maintainer's own Synology deployment.
services:
flatnotes-enhanced:
container_name: flatnotes-enhanced
image: dockerbobw/flatnotes-enhanced:latest
restart: unless-stopped
security_opt:
- no-new-privileges:true
mem_limit: 512m
mem_reservation: 512m
ports:
- "8080:8080"
volumes:
- /volume1/notes:/data
- /volume1/docker/flatnotes/.flatnotes:/data/.flatnotes
- /etc/localtime:/etc/localtime:ro
- /etc/TZ:/etc/timezone:ro
secrets:
- flatnotes_password
- flatnotes_secret_key
environment:
TZ: "Europe/Berlin"
FLATNOTES_AUTH_TYPE: "password"
FLATNOTES_USERNAME: "user"
FLATNOTES_PASSWORD: /run/secrets/flatnotes_password
FLATNOTES_SECRET_KEY: /run/secrets/flatnotes_secret_key
ENABLE_DATABASE: "true"
DATABASE_PATH: "/data/.flatnotes/flatnotes.db"
secrets:
flatnotes_password:
file: /volume1/docker/secrets/flatnotes_password.txt
flatnotes_secret_key:
file: /volume1/docker/secrets/flatnotes_secret_key.txtThe /data/.flatnotes subfolder is mounted from a separate host path. This keeps the database, branding, and backups outside the notes folder — useful if you sync notes elsewhere (e.g. Synology Drive, Dropbox) and don't want database or backup files syncing with them.
Note
If you sync /volume1/notes to another machine, don't also sync .flatnotes — database files don't tolerate two instances writing at once. Point the second mount at a location that's excluded from sync.
-
/volume1/notes— where your markdown notes live -
/volume1/docker/flatnotes/.flatnotes— where the database, backups, and branding live -
/volume1/docker/secrets/— where your secret files live
Change these to match your NAS layout. On Synology, /volume1 is the first storage volume; /volume2 is the second.
/etc/localtime and /etc/TZ are bind-mounted read-only from the host. Some NAS Docker setups don't propagate the timezone properly through the TZ environment variable alone — mounting the host files ensures log timestamps and dates line up with the host.
docker compose pull
docker compose up -dTo pin a version instead of following latest, change the image tag (e.g. :v1.18.2). See the README's Tags list for version history.
- Getting Started & Installation — Prerequisites and first run
- Multi-Instance Setup — Running multiple instances on one server
- README — Full environment variable reference and feature list