Self-hosting
Run Aquamarine on your own server from one Docker image and a Postgres database.
Requirements
- Docker
- Postgres 16 or 17
- A domain with HTTPS in front of the container. Passkeys and OAuth sign-in need it.
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:
- GitHub: create an OAuth app with callback URL
https://<host>/session/githuband Device Flow on, then setAQUAMARINE_GITHUB_CLIENT_IDandAQUAMARINE_GITHUB_CLIENT_SECRET. - Emailed codes: set
AQUAMARINE_SMTP_ADDRESS,AQUAMARINE_SMTP_PORT,AQUAMARINE_SMTP_USERandAQUAMARINE_SMTP_PASSWORD. Used when GitHub is not set up.
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.