.env at the root of the plamotrack folder — one file that both Docker Compose and the app read. Edit it with a text editor, then run docker compose up -d to apply changes.
env.example, one of the release files in your plamotrack folder, lists the common keys with comments. Copy it to .env when you first install, then edit only what you need. This page covers every key.Database
Network & hosting
These four settings decide who can reach the instance and by what name. The deployment overview maps the four ways of running it onto them, and the details are below the tables.Authentication
Currency and localisation
Maintenance
Docker Compose (Git installations only)
An installation from the release files needs neither key. Leave them out, or delete them if you moved a Git installation onto the release files.Changes to
.env need docker compose up -d to take effect. Some settings (like REFERENCE_CURRENCY and POSTGRES_PASSWORD) are only read at first run and cannot be changed by editing .env after the database exists.The four network settings in detail
The API and the bundled web server read the same four lines, so a change to any of them is the line in.env and then docker compose up -d.
WEB_BIND
The interface the one published port listens on. 127.0.0.1, the default, means only the host itself can connect; a private-network address opens the login to that network over plain HTTP; 0.0.0.0 opens it on every interface. It is the reliable control, not the host firewall — on Linux, a published Docker port bypasses the INPUT rules ufw and firewalld work with (see Local & LAN). A non-loopback value is also a name the instance answers to, but 0.0.0.0 names nothing. Keep it on loopback behind a proxy on the same host; set it to the address a connector or proxy on another machine reaches. WEB_PORT is the port.
ALLOWED_HOSTS
The instance refuses a request whose Host header is not a name it knows, with 421 Misdirected Request and a JSON body naming this setting. That is what stops a page in your browser from pointing its own hostname at your instance (DNS rebinding). It is also the one setting that can lock you out of your own install — recoverably: nothing is written or lost while it is wrong, and the fix is the line and docker compose up -d.
Always known without listing: localhost, 127.0.0.1, [::1], a WEB_BIND address that names an interface, and the host of PUBLIC_BASE_URL. Everything else — nas.lan, plamotrack.home.arpa, a mesh DNS name, a container name, a name a reverse proxy forwards that is not the public one — goes here. Ports do not matter (nas.lan:8080 is nas.lan), nor does letter case or a trailing DNS dot. *.home.arpa matches every name under that suffix and is the only wildcard form: a bare *, a *:8080, or a * anywhere else is refused at startup, because an allowlist of everything is the hole the setting closes. WEB_BIND=0.0.0.0 names nothing, so the LAN address or hostname you actually type still has to be listed. Behind a proxy or tunnel the name is PUBLIC_BASE_URL’s host, which is known on its own; an SSH tunnel to localhost:8080 never needs either.
PUBLIC_BASE_URL
The address a browser uses when it isn’t http://localhost:<WEB_PORT>: scheme, host and port, nothing after. Three things hang off it.
- The origin half of the allowlist. A write from a browser — every browser sends an
Originheader — must come from the instance’s own origin, from a loopback origin against a loopback name, or from a listed one; anything else is403with the codeingress.origin_not_allowed. Behind TLS the app sees plain HTTP on its socket while the browser’s origin ishttps://…, so without this line every save from the browser is that403— reads and the login work, and the first save fails. Scripts,curland AI clients send noOriginand are not affected. An instance reached over plain HTTP by one name and through an HTTPS proxy by another is the case forPUBLIC_BASE_URL(the canonical one) plusALLOWED_ORIGINS(the rest). - The cookie. On plain HTTP the session cookie cannot be marked
Secure(a browser limitation), so its confidentiality rests on the network being yours. With anhttps://PUBLIC_BASE_URLit isSecureand__Host--prefixed; the API’s start log says which it is. - Installation identity. In OIDC mode it is required and must be
https://— orlocalhost/127.0.0.1while developing — because the provider’s callbacks and the OAuth server your AI clients connect to (<PUBLIC_BASE_URL>/mcp) are built from it, and every connected client is bound to it. Pick the name you mean to keep: change it later and every connected client signs in again.
TRUSTED_PROXIES
IPs or CIDR ranges of a reverse proxy or tunnel connector in front of the stack whose X-Forwarded-For should be believed for the visitor’s address. The rate limits key on that resolved address and the audit log records it; without the right entry every visitor is the proxy, and both see one address. A degradation, not a hole: nothing about the instance’s own identity — cookies, redirects, the OAuth issuer — ever comes from a forwarded header. That is PUBLIC_BASE_URL’s job.
A proxy on this same host is 127.0.0.1. Inside the bundled stack that entry also trusts the Docker network’s gateway, which is where a process on the host actually arrives from — Docker rewrites the source of connections that come in through a loopback-published port. A connector or proxy on another machine is its own address. Leave the setting empty when clients connect to the stack directly. Every hop in the header must be a valid IP address, with an optional port; a malformed or empty hop stops resolution at the last verified address.
In the bundled stack, nginx resolves the visitor’s address and passes it to the API in a private header the API trusts. Every container attached to the stack’s Compose network is inside that trust boundary: do not attach an untrusted companion container to it, and do not treat the audit address on a request another container sent straight to
api:8000 as verified. Nothing outside the stack can reach that port through the supplied Compose files — all published traffic passes through nginx, which overwrites a forged value.Bootstrap settings and runtime settings
Two keys are read once.POSTGRES_PASSWORD is used only when the database volume is first created; Troubleshooting covers what happens if you change it afterwards. REFERENCE_CURRENCY seeds the instance’s settings row when the database is first migrated, and from then on the row is the setting.
Interface language, formatting locale, time zone, date style, hour cycle and the reference currency are runtime settings: they live in the database, so every browser and every connected AI assistant sees the same values. Change them on the Settings page, or with GET and PATCH on /api/settings. A fresh install starts on en-AU for the language and the locale, UTC for the time zone, the locale’s own date style and hour cycle, and REFERENCE_CURRENCY for the currency. A full-archive export includes the settings row, and importing an archive updates it in place.
An instance updated from a version before these settings existed starts on the same en-AU and UTC defaults. The configured time zone is used when an import reads a CSV timestamp that carries no offset; stored dates, times, currency snapshots and identifiers are never reinterpreted. Downgrading past the release that introduced the settings removes the row, so note any values you changed before rolling back and set them again afterwards.