TMA CloudTMA Cloud
Reference

Environment Variables

Complete reference for all environment variables in TMA Cloud.

Complete reference for all environment variables in TMA Cloud.

Application Configuration

VariableRequiredDefaultDescription
APP_ENVNodevelopmentproduction or development
PORTNo3000App is served on
BACKEND_URLYes (OnlyOffice)-Public backend URL
WEB_DIST_DIRNoauto-detectedFolder with the built web app

APP_ENV: production turns on secure cookies and refuses development-only keys. update.sh renames an older NODE_ENV line in .env to APP_ENV.

WEB_DIST_DIR: The Docker image sets it to /app/web. A source checkout finds apps/tma-cloud-web/dist without it.

PORT: Without Docker, the API listens on this port. With Docker Compose, it is the host port: compose.yml publishes ${PORT}:3000 and sets PORT=3000 inside the container, so the app always listens on 3000, the port the image exposes and its health check uses. With docker run, map the port instead: -p 8080:3000.

The server listens on every address, IPv6 and IPv4 alike, so a client that tries IPv6 first (Windows does for localhost, and anyone does for a name with an IPv6 address) connects at once instead of waiting to fall back. This includes containers with IPv6 turned off. Only on a kernel without IPv6 at all does it listen on IPv4 alone; the startup log says which.

BACKEND_URL: The URL users and the OnlyOffice document server use to reach the app, including the port if it is not 80 or 443. OnlyOffice downloads files and sends saves to this URL, so set it to the public address behind a reverse proxy. It does not change the port the app listens on.

Reverse proxy trust is configured in Settings → Administration → Known proxies, not through an environment variable. See Known Proxies.

Database Configuration

VariableRequiredDefaultDescription
DATABASE_URLYes-PostgreSQL connection URL
DB_CONTAINERNoauto-detectedDocker container name for backup/restore script
BACKUP_RETAIN_COUNTNo10Number of database backups to keep before pruning
DB_HELD_CURSOR_LIMITNo3Folder ZIP downloads that may hold a database connection at once
DB_POOL_MAXNo20Database connections each process keeps open

DATABASE_URL: A libpq connection URI:

DATABASE_URL=postgresql://user:password@host:5432/tma_cloud_storage?sslmode=require
  • The scheme is postgresql:// or postgres://. The port defaults to 5432.
  • Query parameters are libpq parameters, for example sslmode, sslrootcert, sslcert, sslkey, application_name, connect_timeout, and options.
  • sslmode has its libpq meaning, the same as in psql and pg_dump: disable, require (encrypt, do not verify the certificate), verify-ca (verify against sslrootcert), or verify-full (also check the host name). Without sslmode, the app connects without TLS.
  • Percent-encode characters that have a meaning in a URL when they appear in the user, password, or database name: @ as %40, : as %3A, / as %2F, % as %25.
  • The URL must name a database. The app does not start without DATABASE_URL.

Background jobs are stored in the job_queue and job_schedules tables of the same database.

DB_POOL_MAX: The API and the worker each keep their own pool, so the database needs room for twice this many connections, plus any backup or admin sessions.

DB_HELD_CURSOR_LIMIT: A folder ZIP lists its files through a database cursor. Trees of up to 20,000 entries are read at the start and the connection goes back to the pool within milliseconds. A larger tree keeps its connection for the whole download, and this variable caps how many such downloads can do that at once, per API process. Every folder ZIP takes a slot while it reads its tree, so when all slots are held by large downloads, new folder downloads wait for a free slot before they start. Keep it well below DB_POOL_MAX.

Redis Configuration

VariableRequiredDefaultDescription
REDIS_URLYes-Redis connection URL

REDIS_URL: redis://[user]:password@host:port/database, for example redis://:password@localhost:6379/0. Use rediss:// to connect over TLS. The port defaults to 6379 and the database to 0. Leave out the user to use the default user, and leave out :password@ when Redis has no password. Percent-encode reserved characters in the password, as for DATABASE_URL.

Note: REDIS_URL must be set, but the Redis server is optional. If the app cannot reach it, it keeps running without caching.

Authentication

VariableRequiredDefaultDescription
JWT_SECRETYes-Secret key for JWT tokens
FORCE_INSECURE_COOKIESNofalseIf true, auth cookie has no Secure flag in production
JWT_SECRET_FILENo-Path to a file holding JWT_SECRET

The session timeout is not an environment variable. The first user sets it in Settings → Administration; see Session Timeout and Recently Opened.

File Storage

VariableRequiredDefaultDescription
FILE_ENCRYPTION_KEYYes (production)Development defaultKEKs for files and the bucket secret
FILE_ENCRYPTION_KEY_FILENo-Path to a file holding FILE_ENCRYPTION_KEY

FILE_ENCRYPTION_KEY: A single key, or a keyring of version:key entries after a rotation: one per line in a key file, comma-separated in .env. A key without a version is version 1. The highest version encrypts new data and the others still decrypt. In production the newest key must be a random 32-byte key, written as base64 (44 characters) or hex (64 characters). The server refuses to start with a passphrase. Generate a key with tma-server key generate. Outside production a passphrase is accepted and stretched with PBKDF2.

Docker: docker-compose.yml sets FILE_ENCRYPTION_KEY_FILE=/run/secrets/file_encryption_key for the app and worker and mounts secrets/file_encryption_key there. Leave FILE_ENCRYPTION_KEY empty in .env. See Docker Deployment.

_FILE variables: The key can be given as FILE_ENCRYPTION_KEY_FILE instead, holding the path of a file that contains it, for example FILE_ENCRYPTION_KEY_FILE=/run/secrets/file_encryption_key. This keeps the key out of docker inspect output and the process environment. Setting both is an error. Lines starting with # in the file are ignored.

Startup check: The API and the worker compare each key in the keyring with a check value stored in the kek_checks table and refuse to start if one does not match, or if stored data uses a version the keyring lacks. See Security Model.

Note: File contents use bounded streaming. The multipart uploader buffers at most four parts per active upload. Per-file size is controlled by the max upload size setting in Settings → Storage.

Key rotation: ./rotate.sh key on Docker, or tma-server rotate key. See Key Rotation.

Storage Bucket

The S3-compatible bucket is not configured through environment variables. The first user connects it in Settings → Storage, and its secret access key is stored encrypted in the database. See Storage Bucket.

Note: tma-server s3 protect-all applies bucket protections (public access block, HTTPS-only policy, versioning, optional encryption, lifecycle) to the saved bucket. Lifecycle aborts incomplete multipart after 1 day and deletes noncurrent versions after 7 days. Review orphans periodically from Settings → Administration; see Orphan Review.

OnlyOffice Background Save

VariableRequiredDefaultDescription
ONLYOFFICE_REJECT_UNAUTHORIZEDNotrueSet to false for a self-signed OnlyOffice cert

Force-save runs every five minutes. The standalone worker must be running for scheduled force-save commands.

ONLYOFFICE_REJECT_UNAUTHORIZED applies when the app downloads a saved document from the document server. Keep it enabled unless the document server uses a self-signed certificate on a trusted network.

Logging Configuration

VariableRequiredDefaultDescription
LOG_LEVELNoinfoLog level (error, warn, info, debug, trace)
LOG_FORMATNotextjson for one JSON object per line
RUST_LOGNo-Per-module filter; overrides LOG_LEVEL
METRICS_ALLOWED_IPSNo127.0.0.1,::ffff:127.0.0.1,::1Comma-separated IPs allowed to access /metrics. Loopback in either family matches loopback, so 127.0.0.1 also admits ::1

See Logging.

Update Feed

VariableRequiredDefaultDescription
VERSIONS_URLNohttps://tma-cloud.github.io/updates/versions.jsonThe release feed behind /api/version/latest (https only)

The feed is published from the TMA-Cloud/updates repository. Point VERSIONS_URL at another copy (for example a branch's raw versions.json) to try a release before it is published to everyone; desktop apps signed in to this server then update to the version it names.

Background Worker

VariableRequiredDefaultDescription
WORKER_CONCURRENCYNo5The most jobs the worker runs at once per queue
UPLOAD_MEMORY_MBNo512Memory uploads may buffer at once across the server (at least 64). When it is in use, further large uploads wait their turn instead of the server running out of memory

update.sh renames an older AUDIT_WORKER_CONCURRENCY line in .env to WORKER_CONCURRENCY. Audit events do not go through the worker; see Audit Logs.

Last updated on

On this page