* fix(journey): authorize reads of the journey share link GET /api/journeys/:id/share-link now requires journey access (canAccessJourney), matching the create/delete share-link routes and the get_journey_share_link MCP tool. Returns no link when the caller lacks access to the journey. * feat(costs): rework Budget into Costs — Splitwise-style, multi-currency, mobile Renames the Budget addon to "Costs" (UI only) and reworks it into a Tricount/ Splitwise-style cost tracker: multiple payers per expense, equal split across chosen members, settle-up with persisted history + undo, 12 fixed categories, per-expense currency with live FX conversion to a user-set display currency (Settings -> Display), and locale-correct money formatting. Adds a desktop and a dedicated mobile layout. A migration backfills existing budget items (single payer, split members, currency). Closes #551 (per-expense currency). Also switches the app font to self-hosted Poppins (Geist for secondary subtext), replacing the Google Fonts CDN dependency. * fix(costs): neutral dashboard dark palette + liquid glass, full page width, entry-count badge - Dark mode used a warm oklch palette that read brownish; switch to the neutral zinc tokens used by the dashboard (#121215 bg, #f4f4f5 ink) and add a subtle backdrop-blur glass on cards. - Costs now uses the full available page width on desktop instead of a 1280px cap. - Render the expense count next to the Expenses title as a badge. - Adapt budget/journey unit tests to the new payer-based settlement model and the Costs rename (category default 'other', Costs tab/CostsPanel). * fix(costs): drop the entry-count badge, always show row edit/delete actions Removes the count badge next to the Expenses title and makes the per-row edit/delete actions permanently visible (no longer hover-only) on desktop too. * feat(costs): currency-native money formatting, custom select/date, rename addon to Costs - Format every amount in its own currency convention (symbol position, grouping and decimal separators) regardless of app language, via a currency->locale map (EUR -> '12,00 €', USD -> '$12.00', JPY -> '¥12', ...). Previously Intl used the app locale, so EUR showed the symbol in front under an English UI. - Use TREK's CustomSelect (searchable, with symbols) and CustomDatePicker in the add/edit expense modal instead of the native <select>/<input type=date>. - Rename the 'Budget Planner' add-on to 'Costs' in the admin list (display only; id/tables/permissions/MCP stay 'budget') via seed + a migration for existing DBs. * feat(auth): configurable session duration via SESSION_DURATION Adds a SESSION_DURATION env var (ms-style strings: 1h, 7d, 30d, ...) controlling how long a session stays valid before re-login. It drives both the trek_session JWT exp claim and the cookie maxAge from one source, so they never drift. Invalid values warn at startup and fall back to the default (24h — unchanged). The MFA challenge token and MCP OAuth tokens keep their own TTL. Implements the request from discussion #946. Documented in the env-var wiki page, .env.example and docker-compose.yml.
9.8 KiB
Environment Variables
Complete reference for all environment variables TREK reads.
How to Set Variables
- Docker Compose — use the
environment:block or a.envfile alongsidedocker-compose.yml - Docker run — pass each variable with
-e VARIABLE=value - Helm — use
env:for plain values andsecretEnv:for sensitive values invalues.yaml - Unraid — set in the container template editor
Core
| Variable | Description | Default |
|---|---|---|
PORT |
Server port | 3000 |
HOST |
Bind address for the HTTP server (e.g. 127.0.0.1, 10.0.0.72). Source / Proxmox installs only — do not set this in Docker or any containerized deployment. See note below. |
all interfaces |
NODE_ENV |
Environment (production / development) |
production |
ENCRYPTION_KEY |
At-rest encryption key — see resolution order below | auto |
TZ |
Timezone for logs, reminders, and cron jobs (e.g. Europe/Berlin) |
UTC |
LOG_LEVEL |
info = concise user actions; debug = verbose details |
info |
DEFAULT_LANGUAGE |
Default language on the login page — see supported codes below | en |
SESSION_DURATION |
How long a login session stays valid before re-login is required. Applies to both the trek_session JWT exp claim and the cookie maxAge, so they never drift apart. Accepts ms-style strings: 1h, 12h, 7d, 30d, 90d. Invalid values warn at startup and fall back to the default. Does not affect the short-lived MFA challenge token or MCP OAuth tokens (those keep their own TTL). |
24h |
ALLOWED_ORIGINS |
Comma-separated origins for CORS and email notification links | same-origin |
ALLOW_INTERNAL_NETWORK |
Allow outbound requests to private/RFC-1918 IPs. Set true if Immich or other integrated services are on your local network. Loopback (127.x) and link-local (169.254.x) addresses remain blocked regardless. |
false |
APP_URL |
Public base URL (e.g. https://trek.example.com). Required when OIDC is enabled — must match the redirect URI registered with your IdP. Also used as the base URL for email notification links. |
— |
HOST — Source and Proxmox installs only
By default TREK binds to all network interfaces (0.0.0.0), which is the correct behaviour inside a container because Docker handles port exposure at the host level. Setting HOST overrides the bind address at the Node.js level.
When to use it: only when running TREK directly on a host (git sources or the Proxmox community script) and you need to restrict which interface the server listens on — for example, to expose TREK only on a LAN interface while keeping it off the public-facing one.
Never set HOST in Docker, Docker Compose, Helm, or Unraid deployments. Use Docker's -p <host-ip>:<host-port>:<container-port> syntax or your orchestrator's port binding instead.
# .env — source / Proxmox installs only
HOST=10.0.0.72 # bind only on this LAN interface
PORT=3001
When HOST is set, the startup banner includes a Host: line confirming the bound address.
ENCRYPTION_KEY — Resolution Order
server/src/config.ts resolves the encryption key in this order:
ENCRYPTION_KEYenv var — explicit value, always takes priority. Persisted todata/.encryption_keyautomatically.data/.encryption_keyfile — present on any install that has started at least once.data/.jwt_secretfile — one-time fallback for existing installs upgrading without a pre-set key. The value is immediately persisted todata/.encryption_keyso JWT rotation cannot break decryption later.- Auto-generated — fresh install with none of the above; persisted to
data/.encryption_key.
Setting ENCRYPTION_KEY explicitly is recommended so you can back it up independently of the data volume.
DEFAULT_LANGUAGE — Supported Codes
Verified in server/src/config.ts (line 107):
de, en, es, fr, hu, nl, br, cs, pl, ru, zh, zh-TW, it, ar
Note:
id(Indonesian / Bahasa Indonesia) appears inclient/src/i18n/supportedLanguages.tsbut is not in the server's supported-codes list inconfig.ts. SettingDEFAULT_LANGUAGE=idwill fall back toenwith a warning in the server log.
HTTPS / Proxy
These three variables work together behind a TLS-terminating reverse proxy. See Reverse-Proxy for the full explanation.
| Variable | Description | Default |
|---|---|---|
FORCE_HTTPS |
When true: 301-redirects HTTP→HTTPS, sends HSTS (max-age=31536000), adds CSP upgrade-insecure-requests, forces cookie secure flag. Only useful behind a TLS proxy. Requires TRUST_PROXY. |
false |
HSTS_INCLUDE_SUBDOMAINS |
When true: adds the includeSubDomains directive to the HSTS header, extending HTTPS enforcement to all subdomains. Only effective when HSTS is active (FORCE_HTTPS=true or NODE_ENV=production). Leave false if you run other services on sibling subdomains over plain HTTP. |
false |
TRUST_PROXY |
Number of trusted proxy hops. Tells Express to read the real client IP from X-Forwarded-For and protocol from X-Forwarded-Proto. Defaults to 1 automatically in production. Required for FORCE_HTTPS to detect the forwarded protocol. |
1 (production) |
COOKIE_SECURE |
Controls the secure flag on the trek_session cookie. Auto-derived as true when NODE_ENV=production or FORCE_HTTPS=true. Set to false only as an escape hatch for LAN testing without TLS — not recommended in production. |
auto |
Warning:
FORCE_HTTPS=truewithoutTRUST_PROXYset causes a redirect loop.
OIDC / SSO
For setup instructions, see OIDC-SSO.
| Variable | Description | Default |
|---|---|---|
OIDC_ISSUER |
OpenID Connect provider URL (e.g. https://auth.example.com) |
— |
OIDC_CLIENT_ID |
OIDC client ID | — |
OIDC_CLIENT_SECRET |
OIDC client secret | — |
OIDC_DISPLAY_NAME |
Label shown on the SSO login button | SSO |
OIDC_ONLY |
Force SSO-only mode: disables password login and registration, overrides Admin > Settings toggles, cannot be changed at runtime. First SSO login becomes admin on a fresh instance. | false |
OIDC_ADMIN_CLAIM |
OIDC claim used to identify admin users (e.g. groups) |
— |
OIDC_ADMIN_VALUE |
Value of the OIDC claim that grants admin role (e.g. app-trek-admins) |
— |
OIDC_SCOPE |
Space-separated OIDC scopes to request. Fully replaces the default — always include openid email profile plus any extra scopes (e.g. add groups when using OIDC_ADMIN_CLAIM) |
openid email profile |
OIDC_DISCOVERY_URL |
Override the auto-constructed OIDC discovery endpoint. Required for providers with a non-standard path (e.g. Authentik) | — |
Email / SMTP
SMTP settings can be configured via the Admin panel or overridden with environment variables. Env vars take priority over the database values.
| Variable | Description | Default |
|---|---|---|
SMTP_HOST |
SMTP server hostname (e.g. smtp.example.com) |
— |
SMTP_PORT |
SMTP server port. Port 465 enables implicit TLS (secure: true); all other ports use STARTTLS or plain. |
— |
SMTP_USER |
SMTP authentication username | — |
SMTP_PASS |
SMTP authentication password | — |
SMTP_FROM |
Sender address for outbound emails (e.g. TREK <noreply@example.com>) |
— |
SMTP_SKIP_TLS_VERIFY |
Set true to disable TLS certificate validation. Useful for self-signed certs on internal SMTP relays — not recommended in production. |
false |
SMTP_HOST, SMTP_PORT, and SMTP_FROM are all required for email delivery to work. SMTP_USER and SMTP_PASS are optional (for unauthenticated relays).
Initial Setup
These variables only take effect on first boot, before any user exists.
| Variable | Description | Default |
|---|---|---|
ADMIN_EMAIL |
Email for the first admin account | admin@trek.local |
ADMIN_PASSWORD |
Password for the first admin account | random |
Both variables must be set together. If either is omitted, the account is created with email admin@trek.local and a randomly generated password that is printed to the server log. Once any user exists, these variables have no effect.
MCP
For setup instructions, see MCP-Overview.
| Variable | Description | Default |
|---|---|---|
MCP_RATE_LIMIT |
Max MCP API requests per user per minute | 300 |
MCP_MAX_SESSION_PER_USER |
Max concurrent MCP sessions per user | 20 |
Booking Import (KDE Itinerary)
| Variable | Description | Default |
|---|---|---|
KITINERARY_EXTRACTOR_PATH |
Full path to the kitinerary-extractor binary. When unset, TREK searches /usr/lib/*/libexec/kf6/kitinerary-extractor and then PATH. Set this if you install the binary to a non-standard location. |
auto-detected |
The official TREK Docker image bundles the binary automatically: on amd64 it downloads the static release from https://cdn.kde.org/ci-builds/pim/kitinerary/; on arm64 it installs libkitinerary-bin via apt (Debian trixie). When running TREK from source, install libkitinerary-bin (Debian trixie / Ubuntu 25.04+) or download the static binary directly and place it anywhere on PATH. The GET /api/health/features endpoint returns { "bookingImport": true } when the binary is found, and the Import button in the Reservations panel is hidden when it is not.
Other
| Variable | Description | Default |
|---|---|---|
DEMO_MODE |
Enable demo mode (hourly data resets). Not intended for regular use. | false |
Related Pages
- Reverse-Proxy — HTTPS proxy setup and the
FORCE_HTTPS/TRUST_PROXY/COOKIE_SECUREtrio - OIDC-SSO — complete OIDC configuration guide
- MCP-Overview — MCP server setup and rate limiting
- Encryption-Key-Rotation — rotating the
ENCRYPTION_KEYwithout losing data