Open Free and open source — read the code
Self-hosting

Run it yourself.

Postgres and one application container. No account with us, nothing that phones home.

# three secrets, generated separately
cp .env.example .env
openssl rand -base64 36

docker compose up --build

The one thing that will bite you

The application must not connect to Postgres as a superuser. Superusers bypass row-level security entirely, and so does any role granted BYPASSRLS. If you point the app at the postgres user, every level check silently stops applying — and nothing looks wrong. Queries return rows, the app is fast, and everyone sees everything.

The shipped compose file uses two roles for this reason: one owns the schema and runs migrations, and the application connects as a plain per-tenant role. The server checks its own role at startup and refuses to serve traffic if it could bypass the checks. Please do not remove that.

Two volumes, and you need both

enclave-pgdata holds the database and enclave-blobs holds the encrypted files themselves. A backup of one without the other restores nothing usable. Both are named volumes on purpose: an anonymous volume shows up as "dangling" and a routine docker volume prune will delete it.

A database dump contains all ciphertext and all levels. It contains no key that opens any of it — those exist only wrapped to each person's passphrase. That is a good property for a leaked backup and an unforgiving one for a lost passphrase.

Put TLS in front of it

The app binds to loopback as shipped. Terminate TLS in a reverse proxy in front of it. Serving this over plain HTTP defeats the encryption completely: anyone who can rewrite the page can replace the code that does the encrypting.

Your own domains

Set ENCLAVE_SITE_URL and ENCLAVE_APP_URL to your own hostnames so links and canonical URLs point at your deployment rather than ours.