Configuring Progress Watch via environment variables

Everything is an environment variable. There are no config files to edit and no encrypted credentials baked into the image, so the same container runs on a home NAS and in the cloud.

General

VariableDefaultWhat it does
SECRET_KEY_BASE/data/progresswatch/progresswatch.envGenerated on first start and kept on the volume, so leave it unset. Set it yourself where there is no volume, or where several containers have to share it.
DATABASE_URLsqlite3:/data/progresswatch/db.sqlite3Where spaces and task structure live. The default file is what the Docker volume holds; point it at postgresql://… for a cloud deployment. Progress itself is never written here.
FORCE_SSLfalseSet true when something in front terminates TLS. It also drives assume_ssl, so leaving it off keeps the app usable over plain HTTP instead of redirecting to a certificate you do not have.
PORT3000The port Puma binds inside the container. docker-compose.yml publishes it on 7979, because a service you leave running for weeks should not hold the port your own dev servers want.
RAILS_LOG_LEVELinfoLogs go to stdout and nowhere else. This is how much of them.
RATE_LIMIT_PER_HOUR—How many spaces and tasks one address may create per hour. Unset means no limit, which is the right answer for a server only you can reach. Reporting progress is never limited.

Behind a proxy, RATE_LIMIT_PER_HOUR is only as good as the address the app sees. Rails reads X-Forwarded-For and trusts it from private ranges, which is what a reverse proxy on the same host sends — but if the header does not arrive, every request looks like one client and the limit locks out everybody at once rather than nobody.

Redis

Redis holds two unrelated things: the current progress of every task, and the Sidekiq queue. They are two logical databases of one server by default, and either can be moved to its own instance.

VariableDefaultWhat it does
REDIS_URL—The server used for both roles, split into db 0 for progress and db 1 for the queue. Unset, the image runs its own Redis inside the container and snapshots it to the volume.
PROGRESS_REDIS_URLREDIS_URL, db 0Overrides the progress store alone.
SIDEKIQ_REDIS_URLREDIS_URL, db 1Overrides the queue alone.
PROGRESS_TTL_SECONDS86400How long a task keeps its progress without being written to. Every report refreshes it, so this is really how long an abandoned task stays on screen.
PROGRESS_KEY_PREFIXpw:progressKey prefix for the progress store, so it can share a database with something else.

Limits

Text past a limit is cut to it, the last character an ellipsis. A values object with more keys, or a longer key, is refused with 400 instead. These defaults are for a server of your own; progress.watch keeps each of them lower.

VariableDefaultWhat it does
MAX_TASK_TITLE_LENGTH500Longest task title kept, in characters
MAX_TASK_SOURCE_LENGTH200Longest task source kept
MAX_SPACE_TITLE_LENGTH200Longest space name kept
MAX_VALUES_KEY_COUNT50Most keys in a report's values
MAX_VALUES_KEY_LENGTH100Longest key in values
MAX_VALUES_STRING_LENGTH10000Longest string in values, a log line included

Notifications

Both keys unset means the feature does not exist: no button on a space, and nothing stored about anyone. There is nothing to register with Apple or Google — whoever made the browser runs the push service. Generate a pair once and do not rotate it; existing subscriptions are bound to it and browsers are not told.

VariableDefaultWhat it does
VAPID_PUBLIC_KEY—Public half of the pair that signs every push. Handed to the browser when it subscribes.
VAPID_PRIVATE_KEY—Private half. Never leaves the server.
VAPID_SUBJECThttps://github.com/progress-watch/progresswatchA contact address the push services can reach if something goes wrong. Nobody verifies it.
PUSH_CONTENTfullfull puts the task title in the notification, minimal sends "Task completed" and nothing identifying.
PUSH_RELAYhttps://progress.watchWhere a notification for the iOS app is sent to be signed and handed to Apple: only the app's publisher holds the key Apple asks for, so a self-hosted server cannot deliver one itself. The relay sees the device and the text of the notification, never a space UUID, and nothing is sent until somebody turns notifications on in the app. PUSH_CONTENT=minimal keeps task titles out of it. false turns it off, and the app then offers no notifications on this server.

Process sizing

VariableDefaultWhat it does
RAILS_MAX_THREADS5Puma threads per process, and the size of both the database and the Redis connection pool.
WEB_CONCURRENCY0Puma worker processes. Zero runs a single process, which is the right answer on a small box.
SIDEKIQ_CONCURRENCY5Threads in the Sidekiq process. Sending notifications is the only job there is.