Skip to content

Configuration

openPRM is configured entirely with environment variables. Secrets can also be given as a file: set NAME_FILE to its path instead of NAME (supported for the credentials key, the enrollment code, the OIDC client secret and the notification tokens). On NixOS, put secrets in services.homefirst.openprm.environmentFile and plain settings in services.homefirst.openprm.settings.

VariableWhat it does
DATABASE_URLThe Postgres database. openPRM creates its tables itself on start.
OPENPRM_OWNER_PASSWORD_HASHBcrypt hash of the owner’s password (openPRM hash-password '<password>' prints one). Needed unless you sign in with OIDC.
OPENPRM_CREDENTIALS_KEYopenssl rand -base64 32. Encrypts the cloud keys and connected Google accounts’ tokens. Keep it with — but separate from — your backups.
VariableDefaultWhat it does
OPENPRM_HTTP_ADDR:8080Where the web UI and API listen. Use :8081 next to tendant.
OPENPRM_PUBLIC_URL—openPRM’s address as your browser reaches it.
OPENPRM_TRUSTED_PROXIES—Proxies (CIDRs) whose forwarded headers are trusted, e.g. 127.0.0.1,::1 behind nginx or tailscale serve.
OPENPRM_LLM_BACKENDollamaThe model that turns notes into facts (ollama, or stub for none).
OPENPRM_LLM_ENDPOINThttp://localhost:11434The Ollama address.
OPENPRM_LLM_MODELgemma4:12bThe Ollama model.
OPENPRM_LLM_THINKfalseLet a thinking model (gemma4) think before each step: true, false, or empty for the model default. Off is several times faster.
OPENPRM_REMINDER_CRONhourlyWhen reminders are checked (6-field cron).
OPENPRM_API_TOKEN—Bearer token for the ingestion API.
OPENPRM_EMAIL_MAILDIR—A Maildir to watch for notes sent by email.
OPENPRM_REQUIRE_DKIMfalseOnly trust an email’s sender when DKIM/SPF passed.

With an OpenID Connect provider configured (Authelia, Authentik, Keycloak, Pocket ID, Google, …) the sign-in screen shows Sign in with SSO. Each person who signs in gets their own openPRM user, created on first sign-in. The owner password stays available as a fallback.

VariableWhat it does
OPENPRM_OIDC_ISSUER_URLThe provider’s issuer URL (its discovery document lives under /.well-known/openid-configuration). With OPENPRM_OIDC_CLIENT_ID, this turns SSO on.
OPENPRM_OIDC_CLIENT_IDThe client registered for openPRM at the provider.
OPENPRM_OIDC_CLIENT_SECRET (or …_FILE)Its secret. Leave it empty for a public client. PKCE is always used.
OPENPRM_OIDC_REDIRECT_URLThe callback registered at the provider. Defaults to OPENPRM_PUBLIC_URL + /auth/oidc/callback.
OPENPRM_ADMIN_GROUPThe group that makes a user an admin.
OPENPRM_OIDC_GROUPS_CLAIMThe ID-token claim holding groups (default groups).

Registering openPRM at the provider: create a confidential (or public) client using the authorization-code flow. Allow the scopes openid email profile (and whatever puts groups into the ID token, if you use OPENPRM_ADMIN_GROUP). Register exactly one redirect URI: https://<your openPRM>/auth/oidc/callback. The desktop apps need nothing extra. They never talk to the provider themselves; openPRM does.

How the apps sign in:

  • Web: the page goes to the provider and comes back signed in, with the usual session cookie.
  • Desktop (Linux, macOS, Windows): the app opens your system browser and listens on a random port on 127.0.0.1. When the provider sends the browser back, openPRM forwards it to that port with a one-time code, never the session itself. The app trades the code at POST /auth/oidc/exchange for a device token and keeps it in the keystore. The code works once, expires after 60 seconds, and is bound to a PKCE secret that only the app holds. openPRM refuses any return address that isn’t a 127.0.0.1 or [::1] loopback.

A sign-in must finish within 10 minutes. Sign-ins that are in progress are kept in memory, so restarting openPRM during one means starting it again.

On NixOS, put the OPENPRM_OIDC_* settings (except the secret) in services.homefirst.openprm.settings and OPENPRM_OIDC_CLIENT_SECRET in environmentFile.

VariableWhat it does
OPENPRM_NTFY_URL, OPENPRM_NTFY_TOPIC, OPENPRM_NTFY_TOKEN (or _FILE), OPENPRM_NTFY_PRIORITY, OPENPRM_NTFY_TAGSPush reminders to ntfy.
OPENPRM_GOTIFY_URL, OPENPRM_GOTIFY_TOKEN (or _FILE), OPENPRM_GOTIFY_PRIORITYPush reminders to Gotify.
OPENPRM_NOTIFY_PRIVATEKeep personal details out of pushed notifications.

On NixOS these are services.homefirst.openprm.notify.*.

SettingWhat it does
OPENPRM_OWNER_PASSWORD_HASHbcrypt hash of the owner password (the local sign-in). OPENPRM_OWNER_PASSWORD (plaintext) is a dev convenience hashed at startup.
OPENPRM_API_TOKENBearer token for the machine endpoints (/api/capture, /api/export, /api/import, /api/sql).
OPENPRM_PUBLIC_URLWhen it is an https:// address, requests arriving for that host get a Secure session cookie even though a reverse proxy terminated TLS.
OPENPRM_TRUSTED_PROXIESComma-separated CIDRs/IPs of your reverse proxies (e.g. 127.0.0.1,10.0.0.0/8). Their X-Forwarded-Proto: https marks a request as HTTPS for the cookie’s Secure flag; the header is ignored from anyone else.

Sessions are stored in the database (only a hash of each token), so restarting or upgrading openPRM keeps everyone signed in. A session lasts 30 days from its last use; signing out ends it. The apps keep their session in the platform keystore. The owner (and admins) can download an export and restore one from Settings → Data.

Reminders always appear in openPRM. To also get them on your phone or desktop while openPRM is closed, point it at a ntfy topic and/or a Gotify application. Each reminder is sent once, when it comes due (birthdays and other dates, “catch up with…” cadences, follow-ups). A relay is switched on as soon as its required settings are present; you can use both at once. Delivery is best-effort: a relay that’s down is retried briefly, then logged — the reminder itself is never lost.

SettingWhat it does
OPENPRM_NTFY_URLYour ntfy server, e.g. https://ntfy.sh or https://ntfy.example.com. Needs OPENPRM_NTFY_TOPIC.
OPENPRM_NTFY_TOPICThe topic to publish to; subscribe to the same topic in the ntfy app. On a public server, pick a name nobody could guess or protect it with a token.
OPENPRM_NTFY_TOKEN (or OPENPRM_NTFY_TOKEN_FILE)Optional ntfy access token (tk_…), or user:password for basic auth.
OPENPRM_NTFY_PRIORITY1 (min) … 5 (max); unset uses the server default (3).
OPENPRM_NTFY_TAGSComma-separated ntfy tags / emoji added to every notification (e.g. bell).
OPENPRM_GOTIFY_URLYour Gotify server, e.g. https://gotify.example.com. Needs OPENPRM_GOTIFY_TOKEN.
OPENPRM_GOTIFY_TOKEN (or OPENPRM_GOTIFY_TOKEN_FILE)The token of a Gotify application (Gotify → Apps → Create).
OPENPRM_GOTIFY_PRIORITYSame 1–5 scale as ntfy, mapped to Gotify’s 1/3/5/8/10 (8+ pops up on Android); unset ⇒ 3 (Gotify 5).
OPENPRM_NOTIFY_PRIVATEtrue sends “You have a reminder in openPRM” instead of naming the person — use it with a relay you don’t run yourself.
OPENPRM_PUBLIC_URLTapping a notification opens this address (see below). Unset ⇒ notifications don’t link anywhere.

Notifications go to one topic/application for the whole household — everyone subscribed sees every reminder. Without OPENPRM_NOTIFY_PRIVATE a reminder names the person it’s about (e.g. “Catch up with Alice”), so that name passes through your ntfy/Gotify server.

openPRM can connect to homefirst.cloud, Home First’s hosted proxy. It works fully without it. The cloud recognizes this server by its own key pair — generated by openPRM, kept encrypted in its database, and only the public half ever leaves it — which you enroll once: by connecting openPRM to your Home First Cloud account (Settings → Home First Cloud), or with a one-time code from an operator.

SettingWhat it does
HOMEFIRST_CLOUD_ADDRThe cloud’s address. Unset ⇒ openPRM stays offline.
HOMEFIRST_SERVER_IDThis server’s id at the cloud for operator enrollment; codes are issued for it. Not needed when you link it to an account (the cloud assigns the id).
HOMEFIRST_HOME_LABELThis machine’s name on your account’s approval page (default: the hostname; you can change it when connecting).
OPENPRM_CREDENTIALS_KEY (or OPENPRM_CREDENTIALS_KEY_FILE)Base64 of 32 random bytes (openssl rand -base64 32). Encrypts the server’s keys at rest; without it the server can’t enroll. Keep it with your backups — the keys can’t be read without it.
HOMEFIRST_CLOUD_ENROLLMENT_CODE (or …_FILE)The one-time enrollment code. Used only while the server has no key; remove it once enrolled.
OPENPRM_CLOUD_KEY_ROTATION_INTERVALHow often the server key is replaced (default 720h, 30 days; 0 turns the schedule off).
OPENPRM_CLOUD_MAINTENANCE_CRONWhen the rotation check runs (6-field cron, default hourly).

Connecting your account: in Settings → Home First Cloud, an admin chooses Connect to Home First Cloud. openPRM shows a short code and a link; open it, sign in to your Home First Cloud account and approve the access openPRM asks for (Google: contacts, for the contacts import). openPRM then enrolls by itself. You can untick access; openPRM shows an Allow button when it later needs something you didn’t approve. Disconnect removes this server from your account and revokes its keys.

Enrolling with an operator code: get a code for your server id from whoever runs your homefirst.cloud (an operator runs pulumi stack output enrollmentCode-<server id> --show-secrets, or homefirst-cloud enroll-code <server id> on the box), set HOMEFIRST_CLOUD_ENROLLMENT_CODE and start openPRM. The log says “enrolled”; the code is now spent and never stored, so remove the variable — openPRM ignores it while enrolled.

Key rotation happens on the schedule above; a failed rotation is retried with growing delays. The old key is kept for the cloud’s grace period plus one day of slack, then destroyed.

If the log says the cloud no longer recognizes this server’s key (KEY_UNKNOWN), get a new code from the operator, clear the stored keys (DELETE FROM cloud_server_keys;), set the new code and restart. A code that is invalid, already used or expired is reported at startup; ask for a new one. A message about signed requests outside the cloud’s time window means the server’s clock is off — enable NTP.

HOMEFIRST_CLOUD_TOKEN from earlier releases is no longer used; openPRM warns while it is set.

Needs homefirst.cloud (above) and OPENPRM_CREDENTIALS_KEY, which also encrypts the connected Google accounts’ tokens. See Importing Google Contacts.

SettingWhat it does
OPENPRM_PUBLIC_URLopenPRM’s own address as your browser reaches it (e.g. https://prm.example.com). After you approve access at Google, homefirst.cloud sends your browser back here. Unset ⇒ the cloud shows a “you can close this tab” page instead.
OPENPRM_GOOGLE_CONTACTS_SYNC_INTERVALHow often each connected Google account is synced (default 3h, minimum 15m). A newly connected account syncs straight away.
OPENPRM_GOOGLE_CONTACTS_SYNC_CRONWhen openPRM checks for accounts due a sync (6-field cron, default every 10 minutes).
OPENPRM_GOOGLE_CONTACTS_SCOPEWho sees imported people: household (default — like everything else in openPRM, and an imported contact can join a person already in openPRM) or private (only the person who connected the account; only their private people are matched).

The backend’s README.md and SPEC.md in the repository describe every variable in more depth.