Repository navigation
Multi Instance Setup
Flatnotes-Enhanced supports running two or more instances on the same server — for example, one for work notes and one for personal notes — and accessing both from the same browser without interference.
This page explains why isolation works, what each instance needs, and how to configure Docker Compose and a reverse proxy for a clean multi-instance deployment.
Flatnotes-Enhanced namespaces the browser session by origin. Each domain gets its own isolated authentication token, stored under a unique key derived from the origin.
This avoids the session bleed, stale cache hits, and "note not found" errors that can occur when running multiple instances of the original Flatnotes from the same browser.
You do not need to configure anything extra for isolation to work — it is a property of the application. What you must get right is the per-instance configuration described below.
Each instance must have its own:
| Requirement | Why |
|---|---|
Data volume (/data) |
Never share notes between instances |
Database volume (.flatnotes/) |
Never share the SQLite database or backups |
FLATNOTES_SECRET_KEY |
Mandatory — see below |
FLATNOTES_TOTP_KEY |
Mandatory when using TOTP authentication |
| Domain or subdomain | Isolation is based on origin (domain + port); paths on the same domain are not isolated |
| Port (if not using a reverse proxy) | Each instance needs a distinct host port |
Every instance must have its own FLATNOTES_SECRET_KEY. This is the single most important configuration requirement for a multi-instance setup.
If two instances share the same secret key, their JWT tokens are cryptographically interchangeable. A token issued by one instance will be accepted by the other. This causes subtle authentication failures when the browser presents a cookie or stored token from one instance to the other.
Generate a unique key for each instance:
openssl rand -hex 32Run the command once per instance and use a different value for each.
If you use TOTP authentication, also generate a unique FLATNOTES_TOTP_KEY for each instance:
openssl rand -base64 32Using separate TOTP keys gives you true isolation — a compromised key only affects one instance.
The example below runs two instances — flatnotes-personal on host port 8091, and flatnotes-work on host port 8092.
services:
flatnotes-personal:
container_name: flatnotes-personal
image: dockerbobw/flatnotes-enhanced:latest
hostname: flatnotes-personal
restart: unless-stopped
ports:
- "8091:8080"
volumes:
- /your/path/personal-notes:/data
- /your/path/personal-db/.flatnotes:/data/.flatnotes
environment:
FLATNOTES_AUTH_TYPE: "totp"
FLATNOTES_USERNAME: "your_username"
FLATNOTES_PASSWORD: "your_password"
FLATNOTES_TOTP_KEY: "unique_totp_key_for_personal"
FLATNOTES_SECRET_KEY: "unique_secret_key_for_personal"
FLATNOTES_SESSION_EXPIRY_DAYS: 30
ENABLE_DATABASE: true
DATABASE_PATH: /data/.flatnotes/flatnotes.db
flatnotes-work:
container_name: flatnotes-work
image: dockerbobw/flatnotes-enhanced:latest
hostname: flatnotes-work
restart: unless-stopped
ports:
- "8092:8080"
volumes:
- /your/path/work-notes:/data
- /your/path/work-db/.flatnotes:/data/.flatnotes
environment:
FLATNOTES_AUTH_TYPE: "totp"
FLATNOTES_USERNAME: "your_username"
FLATNOTES_PASSWORD: "your_password"
FLATNOTES_TOTP_KEY: "a_different_totp_key_for_work"
FLATNOTES_SECRET_KEY: "a_different_secret_key_for_work"
FLATNOTES_SESSION_EXPIRY_DAYS: 30
ENABLE_DATABASE: true
DATABASE_PATH: /data/.flatnotes/flatnotes.dbTip
Give each service a unique hostname. Using the same hostname on both services causes confusing log entries and can cause network conflicts.
Both instances must be served on their own domain or subdomain. Path-based routing (e.g. /personal and /work on the same domain) is not supported, because session isolation is based on origin, and two paths on the same domain share the same origin.
Create two separate proxy hosts:
| Proxy Host | Forward Hostname/IP | Forward Port |
|---|---|---|
notes.example.com |
192.168.1.100 |
8091 |
wnotes.example.com |
192.168.1.100 |
8092 |
Do not add a password-protected Access List to these proxy hosts. NPM's password-protected Access Lists use the Authorization header for their own basic auth, which conflicts with Flatnotes-Enhanced's Bearer token authentication.
IP-based allow/deny rules without a password work fine and do not interfere.
No custom Nginx configuration is needed. NPM forwards the Authorization header by default for proxy hosts without a password-protected Access List.
notes.example.com {
reverse_proxy localhost:8091
}
wnotes.example.com {
reverse_proxy localhost:8092
}server {
server_name notes.example.com;
location / {
proxy_pass http://localhost:8091;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Authorization $http_authorization;
}
}
server {
server_name wnotes.example.com;
location / {
proxy_pass http://localhost:8092;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Authorization $http_authorization;
}
}After upgrading from a pre-multi-instance build, the first login on each instance will ask you to log in again. This is expected — the session key format changed. It only happens once.
Your notes and settings are intact. No data migration is required.
You will see 401 responses in the container logs on startup, before any user logs in. These are normal.
The app attempts to load settings and tags immediately on load. Those requests are rejected because no session exists yet. They stop as soon as the user logs in.
If the 401s persist after login, check that FLATNOTES_SECRET_KEY is set uniquely for that instance and that the reverse proxy forwards the Authorization header.
To confirm both instances are correctly isolated:
- Log in to
notes.example.com. - Open DevTools → Application → Local Storage. You should see a key starting with
token_followed by a base64 string unique to that origin. - Open
wnotes.example.comin the same browser and log in. - Its Local Storage key will be a different
token_string. - Both instances can now be used simultaneously in the same browser without interference.
If both instances show the same token_ key, either they share an origin (for example, they are being served from the same domain and port via the reverse proxy), or they share a FLATNOTES_SECRET_KEY. Fix whichever of these applies.
Can both instances use the same username and password? Yes. Each instance authenticates against its own configuration independently.
Can both instances use the same TOTP key? Technically yes, but it means one authenticator entry unlocks both instances. Using separate TOTP keys gives you true isolation — a compromised key only affects one instance.
What if I forget to use unique secret keys?
Tokens from one instance will be accepted by the other. You may see unexpected authentication behaviour, cross-instance session sharing, or intermittent 401 errors. The fix is to add unique keys and restart both containers.
Does this work with TOTP (two-factor authentication)? Yes, fully supported. Each instance has its own TOTP secret and its own session storage namespace.
Can I run more than two instances? Yes. Repeat the pattern for as many instances as you need. Each needs its own port, domain, data volume, secret key, and (if used) TOTP key.
What if both instances are on the same domain under different paths? Not supported. Session isolation is based on origin (domain + port). Two paths on the same domain share the same origin and cannot be isolated this way. Use separate subdomains instead.
Can I share a /data volume between two instances?
No. Each instance must have its own /data volume and its own .flatnotes/ folder. Sharing these will cause data corruption or silent data loss.
- Getting Started & Installation — Single-instance setup and environment variables
- Docker Compose Examples — Reverse proxy, secrets, and NAS deployments
- README: Multi-Instance Setup — Feature summary