Configuration reference
This is the single source of truth for everything freshdock reads. Configuration comes from three places:
- Labels on each container — what to update and when (per-container behaviour).
- Environment variables — fleet-wide settings, registry credentials, the
runflags, and notification secrets. This is the primary way to configure a deployment: nothing to mount. - An optional
freshdock.tomlfile — needed only to declare notification targets, and to hold credentials for a registry whose host can’t be spelled as an env-var name. Environment variables override the file, per field.
You usually don’t need a file. Registry credentials, the
[settings]defaults, and therunflags all have environment variables — a container deployment never has to mount afreshdock.toml. The one thing env vars can’t do is declare a notification target; that block has to live in the file (its secrets can still come from the environment). See notifications.
- New here? Start with the quickstart.
- Just need the command flags? See the CLI reference.
Contents
- Labels — per-container behaviour
- Environment variables — the primary fleet-wide config
- The optional
freshdock.tomlfile — when you need one [settings]— fleet-wide defaults[registry.<name>]— registry credentials[notifications.<name>]— notification targets- A complete example
Labels
freshdock is opt-in: a container with no freshdock.enable=true is ignored
entirely. All behaviour is driven by these Docker labels (set them in compose under
labels: or with docker run --label).
| Label | Values | Default | Meaning |
|---|---|---|---|
freshdock.enable | true / false | false | Master switch. Without true, the container is invisible to freshdock and every other label is ignored. |
freshdock.mode | live / nightly / weekly / monthly / watch / off | watch (or [settings] default_mode) | How and when this container updates. See scheduling. |
freshdock.schedule | 5-field cron | the mode’s default | Override the cron for a calendar mode. Ignored for live / watch / off. See cron syntax. |
freshdock.notify | true / false | false | Emit notifications for this container’s update events. Requires a configured [notifications.*] target. See notifications. |
freshdock.cleanup | true / false | [settings] cleanup (else false) | After a healthy update, remove the image the old container ran. Overrides the global [settings] cleanup. See health & cleanup. |
Values are case-insensitive and tolerate surrounding whitespace. An invalid value is reported with the offending label named.
When freshdock.enable=true but freshdock.mode is absent, the mode is watch
(detect-and-notify, never mutate) — a non-destructive default. Change this
fleet-wide fallback with [settings] default_mode (or
FRESHDOCK_DEFAULT_MODE); an explicit freshdock.mode label always wins.
Mode vs. schedule.
freshdock.scheduleonly refines the calendar modes (nightly/weekly/monthly).liveandwatchare polled on the daemon’srun --intervalinstead and ignore the label. See scheduling.
Health-gate timings. The post-update health timeout and the grace period for containers without a healthcheck are currently hardcoded — not label/config/env-configurable. See health & rollback: timings.
Pinned images. A container whose image is pinned to a digest (
repo@sha256:…) has no moving tag to follow. freshdock reports it aspinned (no check)and never updates it.
Environment variables
Environment variables are the primary way to configure freshdock — a container
deployment can run entirely from them, no file mounted. They also override the
file per field (a lone …_TOKEN replaces the file token while keeping the file
username). For registry and notification targets, the <NAME> is the table name,
upper-cased, with - → _.
| Variable | Sets / overrides | Notes |
|---|---|---|
FRESHDOCK_CONFIG | config file path | The --config flag wins over it. |
FRESHDOCK_REGISTRY_<NAME>_USERNAME | [registry.<name>] username | <NAME> = alias (DOCKERHUB, GHCR, QUAY, LSCR). Hosts with dots can’t be expressed unambiguously — configure those in the file. |
FRESHDOCK_REGISTRY_<NAME>_TOKEN | [registry.<name>] token | A token (with or without a username) is enough to create a registry entry from the environment alone — no file needed. |
FRESHDOCK_NOTIFY_<NAME>_BOT_TOKEN | a Telegram target’s bot_token | Overrides a secret on a target declared in the file — env can’t create the target itself. |
FRESHDOCK_NOTIFY_<NAME>_PASSWORD | an SMTP target’s password | Same: overrides a secret on a file-declared target. |
FRESHDOCK_DEFAULT_MODE | [settings] default_mode | One of live/nightly/weekly/monthly/watch/off. An invalid value warns and the file value (else watch) applies. |
FRESHDOCK_CLEANUP | [settings] cleanup | true/false/1/0, case-insensitive. An invalid value warns and the file value applies. |
FRESHDOCK_PRUNE_DANGLING | [settings] prune_dangling | Same boolean forms as FRESHDOCK_CLEANUP. |
FRESHDOCK_INTERVAL, FRESHDOCK_TICK, FRESHDOCK_STOP_TIMEOUT | the run flags of the same name | The flag wins over the env var. An invalid value is a startup error (it is the flag). See the CLI reference. |
NO_COLOR | --no-color | Any non-empty value disables colored output. |
RUST_LOG | log verbosity | e.g. info, freshdock=debug, trace. Default info. |
DOCKER_HOST | Docker daemon endpoint | Honoured by the underlying Docker client (bollard). |
freshdock --help prints the same override list (after_long_help).
The optional freshdock.toml file
The file is optional — freshdock runs without it. Reach for it only when you need something environment variables can’t express:
- Declaring a notification target (a
[notifications.<name>]block). Env vars can supply that target’s secret, but the target itself must be declared here. - Registry credentials for a custom host with dots (e.g.
registry.example.com), whose name can’t be spelled as an env-var name.
Everything else — the four registry aliases, the [settings] defaults, the run
flags — has an environment variable, so most deployments need no file at all.
When present, it is resolved in this order:
--config <path>flag$FRESHDOCK_CONFIG./freshdock.tomlin the working directory
An explicit path (flag or env) that doesn’t exist is an error; a missing default
./freshdock.toml is fine (you get an empty config). Secrets in the file are
redacted in all log output, even at RUST_LOG=trace, and can be supplied via
environment variables instead.
The file has three top-level tables, all optional: [settings], [registry.*],
and [notifications.*].
[settings]
Fleet-wide defaults. Every key is optional — and each has an environment variable (shown below) that overrides it.
[settings]
default_mode = "watch" # fallback mode for an enabled container with no
# freshdock.mode label. Invalid → warn + fall back to watch.
cleanup = false # remove the replaced image after a healthy update;
# overridable per container with freshdock.cleanup.
prune_dangling = false # additionally run a daemon-wide dangling-image prune
# after each successful update (no per-container override).
| Key | Env var | Type | Default | Notes |
|---|---|---|---|---|
default_mode | FRESHDOCK_DEFAULT_MODE | string (a mode name) | unset → watch | Applied to enabled containers without a freshdock.mode label. A freshdock.mode label always overrides it. |
cleanup | FRESHDOCK_CLEANUP | bool | false | Default for freshdock.cleanup. Best-effort; a shared image in use elsewhere is kept, and a cleanup failure never fails the update. |
prune_dangling | FRESHDOCK_PRUNE_DANGLING | bool | false | Daemon-wide; prunes untagged images after a success. Best-effort. |
[registry.<name>]
One table per registry. <name> may be a friendly alias (dockerhub, ghcr,
quay, lscr) or a literal host ("registry.example.com"); both fold onto the
same registry as the matching image reference. For the four aliases you can skip
the file entirely and set FRESHDOCK_REGISTRY_<NAME>_TOKEN (and optionally
_USERNAME) instead.
[registry.ghcr]
username = "octocat" # any non-empty value works for a GHCR PAT
token = "ghp_xxx" # personal access token (read:packages for GHCR)
[registry.dockerhub]
username = "myuser" # required for Docker Hub
token = "dckr_pat_xxx"
[registry."registry.example.com"]
token = "…" # username optional
| Key | Type | Required | Notes |
|---|---|---|---|
username | string | depends on registry | Docker Hub needs the real account name; GHCR and most others accept any non-empty value with a PAT. |
token | string (secret) | yes | Password or personal access token. Redacted in logs. |
For per-registry guidance (PAT scopes, the alias list, a smoke test, and what’s out of scope), see registry-auth.md.
[notifications.<name>]
One table per target, selected by type. This is the one thing that requires the
file — env vars can supply a target’s secret but can’t declare the target. Every
target may set an optional triggers list to subscribe to a subset of events; omit
it (or use []) to receive all three (available, succeeded, failed). Payload
formats and the event/mode matrix are documented in notifications.md.
[notifications.ops-webhook]
type = "webhook"
url = "https://example.com/hooks/freshdock"
# triggers omitted → all of available, succeeded, failed
[notifications.discord]
type = "discord"
webhook_url = "https://discord.com/api/webhooks/123/abc"
triggers = ["succeeded", "failed"]
[notifications.tg]
type = "telegram"
bot_token = "123456:ABC-DEF" # or FRESHDOCK_NOTIFY_TG_BOT_TOKEN
chat_id = "987654321"
triggers = ["failed"]
[notifications.email]
type = "smtp"
host = "smtp.example.com"
port = 587 # default 587
username = "freshdock@example.com" # username + password together, or neither
password = "s3cr3t" # or FRESHDOCK_NOTIFY_EMAIL_PASSWORD
from = "freshdock@example.com"
to = ["admin@example.com"] # non-empty list
starttls = true # default true; false → implicit TLS (465)
triggers = ["succeeded", "failed"]
Per-type keys:
type | Keys | Notes |
|---|---|---|
webhook | url (secret) | Generic JSON POST. |
discord | webhook_url (secret) | Posts a coloured embed. |
telegram | bot_token (secret), chat_id | Plain-text message via the Bot API. |
smtp | host, port (=587), username?, password? (secret), from, to (list), starttls (=true) | username+password must be set together or both omitted (anonymous relay). |
All targets also accept triggers = ["available", "succeeded", "failed"] (subset
allowed).
A complete example
File-free (environment only)
A deployment with a private GHCR image, cleanup on, and no notifications needs no
file at all — just environment:
FRESHDOCK_DEFAULT_MODE=nightly
FRESHDOCK_CLEANUP=true
FRESHDOCK_REGISTRY_GHCR_USERNAME=octocat
FRESHDOCK_REGISTRY_GHCR_TOKEN=ghp_xxx
(Set these under environment: in compose, Environment= in a systemd unit, or
export in a shell.)
With a file (for notifications)
Once you want notifications, declare the target in a freshdock.toml and keep the
secret in the environment:
# freshdock.toml
[settings]
default_mode = "watch"
cleanup = true
prune_dangling = false
[registry.ghcr]
username = "octocat"
token = "ghp_xxx"
[notifications.discord]
type = "discord"
webhook_url = "https://discord.com/api/webhooks/123/abc"
triggers = ["succeeded", "failed"]
A copy-paste starting point with every section commented out lives at
freshdock.toml.example in the repository root.
Runnable compose stacks live in examples/compose/.