Self-hosting

Run Aquamarine on your own server from one Docker image and a Postgres database.

Requirements

Build the image

git clone <repository> aquamarine
cd aquamarine
docker build -t aquamarine .

Generate secrets

Production won't start without these. Generate them once and keep them. Changing the encryption keys makes stored API keys and connected accounts unreadable.

openssl rand -hex 64   # SECRET_KEY_BASE
openssl rand -hex 32   # AQUAMARINE_ENCRYPTION_PRIMARY_KEY
openssl rand -hex 32   # AQUAMARINE_ENCRYPTION_DETERMINISTIC_KEY
openssl rand -hex 32   # AQUAMARINE_ENCRYPTION_KEY_DERIVATION_SALT

Configure

Put these settings in an env file. Per-user choices such as themes, routines and connected accounts are set in the app.

AQUAMARINE_HOST=notes.example.org
AQUAMARINE_PORT=443
AQUAMARINE_SCHEME=https
AQUAMARINE_MAIL_FROM="Aquamarine <no-reply@notes.example.org>"

AQUAMARINE_DATABASE_HOST=db.internal
AQUAMARINE_DATABASE_PORT=5432
AQUAMARINE_DATABASE_USER=aquamarine
AQUAMARINE_DATABASE_PASSWORD=...

SECRET_KEY_BASE=...
AQUAMARINE_ENCRYPTION_PRIMARY_KEY=...
AQUAMARINE_ENCRYPTION_DETERMINISTIC_KEY=...
AQUAMARINE_ENCRYPTION_KEY_DERIVATION_SALT=...

The database user needs to create databases. The app uses three: aquamarine_production, aquamarine_production_cache and aquamarine_production_queue.

Sign-in

Set up at least one way to create an account:

Passkeys can be added after the first sign-in.

Run

docker run -d --name aquamarine --env-file aquamarine.env -p 8080:80 aquamarine

The container creates and migrates the databases on start, and runs background jobs in the same process. Point your reverse proxy at port 8080.

Integrations

Slack, Google Calendar and Todoist each need an OAuth app with redirect URI https://<host>/integrations/<provider>/callback. Set the client ID and secret as listed in .env.example. A provider without credentials shows as not set up.

Updating

Pull, rebuild the image and restart the container. Migrations run on start.