Self-hosting reference
The full surface for running Nottario on your own host. The Getting started guide covers the happy path; this page documents every knob.
Environment variables
| Variable | Required | Default | What it does |
|---|---|---|---|
PUBLIC_URL |
yes | http://localhost:8080 |
The base URL users reach. Must match the OAuth callback host and use https:// in production for Secure cookies. |
DATABASE_URL |
yes | — | pgx connection string. Migrations run automatically on startup. |
GITHUB_OAUTH_CLIENT_ID |
yes | — | From the GitHub OAuth App. |
GITHUB_OAUTH_CLIENT_SECRET |
yes | — | From the GitHub OAuth App. |
SESSION_KEY |
yes | — | 32 random bytes, base64-encoded. Generate once with openssl rand -base64 32 and keep. Rotating logs everyone out. |
GITHUB_OAUTH_ORG |
no | (disabled) | Org slug; when set, only active members can sign in via OAuth. API tokens are unaffected. |
HTTP_ADDR |
no | :8080 |
Listen address. Change only if you run multiple instances on one host. |
NOTTARIO_BACKUP_DIR |
no | (disabled) | Mount-friendly path where periodic pg_dump backups land. Empty = no backups. |
NOTTARIO_BACKUP_AT |
no | 03:00 |
Time of day for the daily backup, HH:MM 24h local time. |
NOTTARIO_BACKUP_KEEP_DAYS |
no | 7 |
Delete dumps older than this many days after each successful run. |
SELF_UPDATE_CHECK_ENABLED |
no | true |
Poll the upstream GitHub repository once a day and surface an admin-only banner when a newer commit lands on master. false skips the outbound request entirely. |
SELF_UPDATE_CHECK_INTERVAL |
no | 24h |
Go duration between checks. Clamped up to 1h — the anonymous GitHub API has a 60 req/h/IP limit that leaves plenty of headroom, but there's nothing to gain from a tighter cadence. |
SELF_UPDATE_UPSTREAM |
no | neverbot/nottario |
GitHub owner/repo to compare against. Change if you run a fork so the banner points at your own tree. |
NOTIFICATIONS_ENABLED |
no | true |
Produce per-user notifications (bell in the topbar, drawer, preferences under /me). false hides the bell, refuses writes, and returns empty reads — no rows are inserted. Existing rows are preserved so the feature can be flipped back on without loss. |
Secret files
Every secret variable also accepts a _FILE companion that points
at a file on disk:
SESSION_KEY_FILEGITHUB_OAUTH_CLIENT_SECRET_FILE
The file's contents are read and trailing whitespace is stripped, so
openssl rand -base64 32 > /run/secrets/session_key works without
extra ceremony. The _FILE variant takes precedence when both are
set — recommended under Docker secrets or Kubernetes mounted
secrets.
Container UID. The image runs as
nonroot(UID 65532, fixed by the distroless base image). The_FILEtargets must be readable by that UID. With Docker Composefile:secrets the mounted file inherits the host's owner; if the host file is0600 root:root, Nottario can't read it. Either widen to644orchown 65532:65532.
Backups
When NOTTARIO_BACKUP_DIR is set, an in-process goroutine fires
pg_dump --format=custom once a day at NOTTARIO_BACKUP_AT local
time. The container ships the matching postgresql-client so the
dump runs in-process; no sidecar needed. Files are named
nottario-YYYY-MM-DDTHH-MM-SS.dump and NOTTARIO_BACKUP_KEEP_DAYS
controls the rotation.
To restore: stop the container, drop the database, and run
pg_restore --clean --if-exists -d <DATABASE_URL> <file.dump>.
Upgrade flow
docker compose pull nottario
docker compose up -d nottario
Migrations run on every startup. A migration that fails will keep
the previous container running (Compose health check), so a bad
upgrade does not lose data. If you pin to a vX.Y.Z tag instead of
:latest, upgrades are explicit: bump the tag in your
compose.yml and pull+up.
Update notifications
To keep you from having to check GitHub yourself, an in-process
poller compares the commit SHA baked into the running binary against
the current refs/heads/master on the upstream repository. When
they differ, an admin-only banner appears under the topbar with the
exact docker compose pull && docker compose up -d command needed
to update. The poller never touches the container — it is purely
informational.
The check runs once at startup and then every
SELF_UPDATE_CHECK_INTERVAL (default 24h). It calls the anonymous
GitHub REST API (https://api.github.com/repos/{upstream}/commits/master)
with no authentication and a 5-second timeout; failures are logged
at warn level and the previous known-good state is preserved. Only
admins receive the update_available: true signal — regular
members can't run docker compose pull and there's no reason to
expose the running SHA to them.
To turn it off entirely (air-gapped hosts, privacy preferences),
set SELF_UPDATE_CHECK_ENABLED=false. To point at a fork, set
SELF_UPDATE_UPSTREAM=your/fork.