Self-host FUTO Notes sync
Run the FUTO Notes sync server on your own box and your devices keep each other up to date without anyone else in the middle. Sync is end-to-end encrypted: every note is encrypted on your device before upload, and the server stores sealed blobs it cannot open. See how the encryption works below.
There is no hosted service today, so self-hosting is how you get sync. It is a single-user server with one sync password.
Install
Install the sync server with one command, on a Linux box with Docker and Docker Compose v2 (amd64 or arm64):
curl -fsSL https://notes.futo.tech/install-server.sh | shThe installer asks for an install directory, a port (3005 by default), and a sync password, then starts one container and checks /health before it finishes. SQLite runs inside the container; the database and your encrypted blobs both live in a data directory under the install directory.
Connect the app
In the app, open Settings → Sync and find Server URL. On iPhone and Android, tap Self-hosted sync inside the Sync section first. On your own network, enter:
http://<your-server-ip>:3005Use the same sync password on every device. That password does two jobs: it signs the app in to your server, and it unlocks the encryption key for your notes. If you lose it, nothing on the server can be decrypted, and there is no reset. The sync password covers where each app keeps it, and how to change it without locking your devices out.
Reach it from outside your network
To reach the sync server from anywhere, put a TLS reverse proxy in front of it. The server speaks plain HTTP, which is fine on a LAN.
Tailscale Funnel is the least work: it gives the machine an HTTPS name without opening a port on your router. If you already run a public server, Caddy handles the certificate for you:
notes.example.com { reverse_proxy localhost:3005}Then point the app at the HTTPS URL instead. Reverse proxy setup has tested nginx and Traefik configs as well, and the settings live sync needs.
Upgrade and back up
From the install directory:
docker compose pull && docker compose up -dTo back up, stop the container, copy the whole data directory somewhere safe, and start it again. That directory is everything the server has. Back up, restore, and move a server has the details, including restoring onto a new machine. Every setting the server reads is listed in server configuration.
How the encryption works
The app does all of the cryptography, and the server stores bytes it cannot read. That protects your notes from anyone who gets a copy of the server’s data directory. It does not protect them from whoever runs the server: the server receives your sync password when a device signs in, and the app would not notice a server that withheld, rolled back, or deleted data. How the encryption works has the full detail, and what the server can see goes through each case.
- When you first connect, the app generates a random 256-bit vault key on your device.
- Every note is packed together with its filename and folder path, then encrypted with AES-256-GCM under the vault key. Each blob gets a fresh random nonce, and the authentication tag means a tampered or truncated blob is rejected rather than decrypted wrong.
- The vault key is wrapped with a key derived from your sync password using PBKDF2-SHA-256 with 100,000 iterations and a random salt. Only this wrapped copy, the salt, and the KDF name are stored on the server. A new device downloads the wrapped key and unwraps it locally with your password.
- The server never receives the vault key or a decryption key, and it never decrypts anything.
What the server can see is the sync coordination data: how many objects there are, the size of each encrypted blob, when each one changed, and opaque IDs. It cannot see note text, titles, filenames, folder names, tags, or links. That means a copy of the data directory or a backup of it is worthless without your password.
Three honest caveats. The sync password is also the login password, so whoever runs the server is handed it when a device signs in; in a self-hosted setup that person is you. The installer writes that password into the server’s .env file, so protect that file: it is created mode 600, it should not sit in the same backup as the data directory, and you can store a scrypt hash in FUTO_NOTES_PASSWORD_HASH instead of the password itself (how to make one). And the app speaks plain HTTP unless you put TLS in front of it; TLS protects the password and session token in transit, while the notes are already encrypted either way.
Without Docker
Release binaries are published for Linux, macOS, and Windows if you would rather run the server directly, with a systemd unit example. The server README covers that path.
The full README and the source are at gitlab.futo.org/futo-notes/futo-notes-server. To compile the server yourself, see build the sync server.
Next steps
- Get the app for each device you want to sync.
- Reverse proxy setup: HTTPS so devices can sync from outside your network.
- Server configuration: every setting the server reads.
- Back up, restore, and move a server: what to copy, and what to keep separate.