Skip to content

Multi Instance Setup

BobWs edited this page Nov 1, 2026 · 3 revisions

🖥️ 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.


Why Multi-Instance Works

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.


Requirements

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

Critical: Unique Secret Keys

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 32

Run 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 32

Using separate TOTP keys gives you true isolation — a compromised key only affects one instance.


Docker Compose Example

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.db

Tip

Give each service a unique hostname. Using the same hostname on both services causes confusing log entries and can cause network conflicts.


Reverse Proxy Configuration

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.

Nginx Proxy Manager

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.

Caddy

notes.example.com {
    reverse_proxy localhost:8091
}

wnotes.example.com {
    reverse_proxy localhost:8092
}

Nginx

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 First Login

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.


Pre-Login 401s in Logs

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.


Verifying Isolation

To confirm both instances are correctly isolated:

  1. Log in to notes.example.com.
  2. Open DevTools → Application → Local Storage. You should see a key starting with token_ followed by a base64 string unique to that origin.
  3. Open wnotes.example.com in the same browser and log in.
  4. Its Local Storage key will be a different token_ string.
  5. 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.


Frequently Asked Questions

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.


See Also

Clone this wiki locally