Environment variables
Every setting is read from the environment - a .env file next to the
compose file, or your Docker manager’s stack environment. Most can also be
changed on the dashboard’s Settings page; a variable
set in the environment always wins. Empty is the same as unset.
- Secret: never shown by value, and never saved from the Settings page.
- Environment only: read before the database opens, so the Settings page cannot change it.
- Applies on restart: read once at start; a change takes effect when the doctor restarts.
offturns it off: on by default; setoff(ornonefor a list) to disable it.
Build and mode
Section titled “Build and mode”DOCTOR_MODE
Section titled “DOCTOR_MODE”observe- diagnose and notify, never touch anything <- start heresuggest- propose an action, wait for you to approve it in the dashboardauto- apply allowed actions without asking
Default: observe · One of: observe, suggest, auto
DOCTOR_POLL_INTERVAL
Section titled “DOCTOR_POLL_INTERVAL”Poll interval: from the start of one poll to the next.
Default: 30 · Type: whole number
DOCTOR_POLL_CONCURRENCY
Section titled “DOCTOR_POLL_CONCURRENCY”Containers read at once during a poll. Applies on restart.
Default: 6 · Type: whole number · Applies on restart
DOCKER_HOST
Section titled “DOCKER_HOST”The Docker endpoint: the socket proxy, never the raw socket. The compose file sets it from DOCTOR_DOCKER_HOST.
Default: tcp://doctor-socket-proxy:2375 · Environment only
DOCTOR_REQUIRE_OPT_IN
Section titled “DOCTOR_REQUIRE_OPT_IN”True watches only containers labelled doctor.enable=true.
Default: off · Type: on / off
Deployment
Section titled “Deployment”DOCTOR_DOCKER_MANAGER
Section titled “DOCTOR_DOCKER_MANAGER”In words, for the diagnosis, the hand-off brief and the Settings page’s labels; neither changes what the doctor does. Both optional. The Docker manager’s name: Portainer, Coolify, Komodo, Dockge…
Default: unset
DOCTOR_DEPLOY_METHOD
Section titled “DOCTOR_DEPLOY_METHOD”How a change reaches the host.
Default: unset
DOCTOR_HOST_KIND
Section titled “DOCTOR_HOST_KIND”What the doctor runs on. auto reads it from the kernel: a Synology says so, and then DSM’s own md0/md1 system arrays are not called degraded. Set synology or generic to override. The name is what diagnoses and the Host page call it; empty says “the host”.
Default: auto · One of: auto, synology, generic
DOCTOR_HOST_NAME
Section titled “DOCTOR_HOST_NAME”The machine itself. auto tells a Synology NAS from any other Linux by its kernel; synology keeps DSM’s md0/md1 system arrays from reading as degraded and uses its names for drives and pools. The name is what the host is called in diagnoses and on the Host page - empty says “the host”.
Default: unset
DOCTOR_LLM_PROVIDER
Section titled “DOCTOR_LLM_PROVIDER”Set DOCTOR_LLM_PROVIDER=openai and point at any OpenAI-compatible endpoint. The base URL can only be set here, never from the Settings page, since the API key is sent to it. Verify it in one command before you rely on it: docker compose exec container-doctor python -m app.selftest Free tiers, limits and prices below are as of October 2026 - check the vendor’s page, these change often. Google Gemini - free tier, no card. See https://sebastianbuechler.github.io/container-doctor/guides/models/ (“Free options, ranked”) for the privacy caveat: free-tier inputs may be used for training.
Default: anthropic · One of: anthropic, openai · Applies on restart
DOCTOR_MODEL
Section titled “DOCTOR_MODEL”Built-in prices (USD per million tokens, in / out): claude-opus-5-5 4/20, claude-sonnet-5-5 2/10, claude-haiku-5-5 0.10/0.50, claude-fable-5 10/50.
Default: claude-opus-5-5
DOCTOR_OPENAI_BASE_URL
Section titled “DOCTOR_OPENAI_BASE_URL”OpenAI-compatible endpoint (Ollama, LM Studio, OpenRouter, vLLM, …). Environment-only, like every URL a secret is sent to: a setting saved from the page could otherwise send the key to a host of its choosing.
Default: unset · Environment only
ANTHROPIC_API_KEY
Section titled “ANTHROPIC_API_KEY”Anthropic API key. Without it the doctor still detects incidents and shows them in the dashboard - it just cannot explain them.
Default: unset · Secret
DOCTOR_OPENAI_API_KEY
Section titled “DOCTOR_OPENAI_API_KEY”OpenAI-compatible endpoint (Ollama, LM Studio, OpenRouter, vLLM, …). Environment-only, like every URL a secret is sent to: a setting saved from the page could otherwise send the key to a host of its choosing.
Default: unset · Secret
DOCTOR_EFFORT
Section titled “DOCTOR_EFFORT”Low | medium | high | xhigh | max - how hard the model thinks per incident. Only applies to Anthropic models; ignored elsewhere.
Default: medium · One of: low, medium, high, xhigh, max
DOCTOR_LLM_TEMPERATURE
Section titled “DOCTOR_LLM_TEMPERATURE”Reasoning models reject temperature (GPT-6 Luna does at any reasoning effort above none). The request drops it automatically if the vendor complains; set -1 to never send it and skip the extra round trip.
Default: 0.2 · Type: number
DOCTOR_PRICE_IN_PER_MTOK
Section titled “DOCTOR_PRICE_IN_PER_MTOK”USD per million tokens, so the spend meter works for a non-Anthropic vendor. Leave at -1 to price known Anthropic models from the built-in table and treat everything else as free. Set both to 0 to say “this really is free”.
Default: -1 · Type: number
DOCTOR_PRICE_OUT_PER_MTOK
Section titled “DOCTOR_PRICE_OUT_PER_MTOK”USD per million tokens. Unset prices Anthropic models from a built-in table and counts anything else as free - hence the call cap above.
Default: -1 · Type: number
DOCTOR_DAILY_USD_BUDGET
Section titled “DOCTOR_DAILY_USD_BUDGET”No new calls today once recorded spend reaches this (calls in flight can overshoot slightly; set a limit with the provider for an absolute ceiling). Manual re-diagnoses count too. 0 disables the cap.
Default: 1 · Type: number
DOCTOR_DAILY_CALL_LIMIT
Section titled “DOCTOR_DAILY_CALL_LIMIT”No new calls after this many today. This is the cap that matters on a free tier, where the dollar meter reads zero all day. 0 disables it.
Default: 0 · Type: whole number
DOCTOR_DIAGNOSIS_CACHE_HOURS
Section titled “DOCTOR_DIAGNOSIS_CACHE_HOURS”Identical failures reuse a stored diagnosis for this many hours (no API call).
Default: 6 · Type: whole number
DOCTOR_LLM_LOG_DAYS
Section titled “DOCTOR_LLM_LOG_DAYS”Every request as it was sent, on the LLM page, for this many days. 0 keeps none; the daily spend totals are kept either way.
Default: 14 · Type: whole number
Detection
Section titled “Detection”DOCTOR_CPU_THRESHOLD
Section titled “DOCTOR_CPU_THRESHOLD”Share of the WHOLE host’s CPU, not of a single core.
Default: 85 · Type: number
DOCTOR_MEM_THRESHOLD
Section titled “DOCTOR_MEM_THRESHOLD”Share of the container’s memory limit (or of host RAM when no limit is set).
Default: 90 · Type: number
DOCTOR_RESOURCE_BREACH_POLLS
Section titled “DOCTOR_RESOURCE_BREACH_POLLS”Consecutive polls a breach must persist for, so one backup spike is quiet.
Default: 4 · Type: whole number
DOCTOR_RESTART_LOOP_COUNT
Section titled “DOCTOR_RESTART_LOOP_COUNT”Consecutive polls a breach must persist for, so one backup spike is quiet.
Default: 3 · Type: whole number
DOCTOR_RESTART_LOOP_WINDOW_MINUTES
Section titled “DOCTOR_RESTART_LOOP_WINDOW_MINUTES”Consecutive polls a breach must persist for, so one backup spike is quiet.
Default: 15 · Type: whole number
DOCTOR_LOG_LINES
Section titled “DOCTOR_LOG_LINES”Consecutive polls a breach must persist for, so one backup spike is quiet.
Default: 120 · Type: whole number
DOCTOR_LOG_MAX_AGE_MINUTES
Section titled “DOCTOR_LOG_MAX_AGE_MINUTES”Log lines older than this are never read; 0 reads the whole tail.
Default: 60 · Type: whole number
DOCTOR_LOG_ERROR_BURST
Section titled “DOCTOR_LOG_ERROR_BURST”Lines matching DOCTOR_LOG_ERROR_PATTERN by wording.
Default: 5 · Type: whole number
DOCTOR_LOG_LEVEL_ERROR_BURST
Section titled “DOCTOR_LOG_LEVEL_ERROR_BURST”Lines the app itself marked ERROR. Higher, because one ERROR line is weaker evidence than “no space left on device”.
Default: 10 · Type: whole number
DOCTOR_LOG_FATAL_THRESHOLD
Section titled “DOCTOR_LOG_FATAL_THRESHOLD”A single FATAL / CRITICAL line opens an incident on its own.
Default: 1 · Type: whole number
DOCTOR_DEPLOY_SETTLE_MINUTES
Section titled “DOCTOR_DEPLOY_SETTLE_MINUTES”Redeploys. A stop that Docker announced with a signal (docker stop, Compose, a Docker manager) is not a crash, and a container that exits and is replaced within DOCTOR_DIE_GRACE_SECONDS was redeployed. For DOCTOR_DEPLOY_SETTLE_MINUTES after any redeploy, errors other containers log while it restarts do not count, and a failing health check waits. 0 turns the window off.
Default: 3 · Type: number
DOCTOR_DIE_GRACE_SECONDS
Section titled “DOCTOR_DIE_GRACE_SECONDS”A nonzero exit nobody asked for waits this long before it is a crash: if the container was replaced meanwhile, it was a redeploy.
Default: 30 · Type: number
DOCTOR_LOG_IGNORE_PATTERN
Section titled “DOCTOR_LOG_IGNORE_PATTERN”Log lines to never count, host-wide. Prefer the per-container label doctor.ignore_log - noise is usually one container’s habit.
Default: unset
DOCTOR_DISK_PATHS
Section titled “DOCTOR_DISK_PATHS”Free space is a property of the filesystem, so /data reports all of the volume it lives on without mounting it. To watch another volume, mount an empty directory on it read-only (never the volume root) and add it here: one path per volume, each with its own forecast.
Default: none · Type: comma-separated list
DOCTOR_DISK_THRESHOLD
Section titled “DOCTOR_DISK_THRESHOLD”A watched filesystem this full (%) is a warning…
Default: 95 · Type: number
DOCTOR_DISK_CRITICAL
Section titled “DOCTOR_DISK_CRITICAL”…and this full, critical.
Default: 98 · Type: number
DOCTOR_DISK_FORECAST_DAYS
Section titled “DOCTOR_DISK_FORECAST_DAYS”The fill-rate forecast: an incident when a filesystem is on course to be full within DOCTOR_DISK_FORECAST_DAYS, critical within the _CRITICAL_DAYS. The rate is fitted over DOCTOR_DISK_TREND_WINDOW_DAYS of samples, one per DOCTOR_DISK_SAMPLE_MINUTES.
Default: 21 · Type: whole number
DOCTOR_DISK_FORECAST_CRITICAL_DAYS
Section titled “DOCTOR_DISK_FORECAST_CRITICAL_DAYS”How far back the fill-rate is fitted, and how close to full is worth saying something about. A percentage says how full; these say whether it is going anywhere.
Default: 5 · Type: whole number
DOCTOR_DISK_TREND_WINDOW_DAYS
Section titled “DOCTOR_DISK_TREND_WINDOW_DAYS”How far back the fill-rate is fitted, and how close to full is worth saying something about. A percentage says how full; these say whether it is going anywhere.
Default: 14 · Type: whole number
DOCTOR_MDSTAT_PATH
Section titled “DOCTOR_MDSTAT_PATH”Software RAID (md) state; off turns the RAID check off.
Default: /proc/mdstat · off turns it off
DOCTOR_SYSFS_PATH
Section titled “DOCTOR_SYSFS_PATH”Array layout, scrub results and per-disk read errors; off skips them.
Default: /sys · Applies on restart · off turns it off
DOCTOR_RAID_ERRORS_PER_DAY
Section titled “DOCTOR_RAID_ERRORS_PER_DAY”New corrected read errors on one drive within a day that make its warning critical (0 never escalates), and how many days a drive warns after its last new one.
Default: 10 · Type: whole number
DOCTOR_RAID_ERRORS_DAYS
Section titled “DOCTOR_RAID_ERRORS_DAYS”How long a drive’s newly corrected read errors keep its warning up. md’s own count only goes back to 0 on a reboot, so without a window a drive that had a bad day would warn until the next one.
Default: 7 · Type: whole number
DOCTOR_PROC_PATH
Section titled “DOCTOR_PROC_PATH”The host itself (Host page). Read from /proc, which is system-wide; off turns it off. An incident opens when a condition lasts DOCTOR_HOST_BREACH_POLLS.
Default: /proc · Applies on restart · off turns it off
DOCTOR_HOST_MEM_AVAILABLE_PCT
Section titled “DOCTOR_HOST_MEM_AVAILABLE_PCT”Below this share of memory available (the kernel’s MemAvailable, which counts reclaimable cache) the host is about to swap or OOM-kill.
Default: 5 · Type: number
DOCTOR_HOST_SWAP_IN_PER_S
Section titled “DOCTOR_HOST_SWAP_IN_PER_S”Pages read back from swap per second. Swap being used is normal - Linux, DSM especially, parks idle pages there - swap being read back steadily is not.
Default: 256 · Type: number
DOCTOR_HOST_LOAD_PER_CORE
Section titled “DOCTOR_HOST_LOAD_PER_CORE”The 5-minute load average per CPU. Linux load counts processes waiting on disks as well as on CPU, so it reads high during a scrub.
Default: 2 · Type: number
DOCTOR_HOST_IOWAIT_PCT
Section titled “DOCTOR_HOST_IOWAIT_PCT”Share of CPU time spent waiting on disks.
Default: 40 · Type: number
DOCTOR_HOST_TEMP_C
Section titled “DOCTOR_HOST_TEMP_C”Pages read back from swap per second. Swap being used is normal - Linux, DSM especially, parks idle pages there - swap being read back steadily is not.
Default: 80 · Type: number
DOCTOR_HOST_BREACH_POLLS
Section titled “DOCTOR_HOST_BREACH_POLLS”Consecutive polls a host breach must last: ten is five minutes at the default interval, so a backup’s burst of I/O wait stays quiet.
Default: 10 · Type: whole number
DOCTOR_HOST_SAMPLE_MINUTES
Section titled “DOCTOR_HOST_SAMPLE_MINUTES”One stored point per this many minutes, for the Host page’s charts and each drive’s temperature and sleep.
Default: 5 · Type: whole number
Internet and DNS
Section titled “Internet and DNS”DOCTOR_NET_CHECK_SECONDS
Section titled “DOCTOR_NET_CHECK_SECONDS”Internet and DNS (Network page), checked from the doctor’s container.
Default: 60 · Type: whole number · Applies on restart
DOCTOR_NET_TCP_TARGETS
Section titled “DOCTOR_NET_TCP_TARGETS”Addresses, not names: reaching them says the line works, whatever DNS does.
Default: 1.1.1.1:443, 9.9.9.9:443 · Type: comma-separated list
DOCTOR_NET_DNS_NAMES
Section titled “DOCTOR_NET_DNS_NAMES”Resolved the way containers resolve names.
Default: cloudflare.com, github.com · Type: comma-separated list
DOCTOR_NET_DNS_SERVERS
Section titled “DOCTOR_NET_DNS_SERVERS”Your own DNS servers, each checked on its own: ip, ip:port or a container name.
Default: none · Type: comma-separated list
DOCTOR_NET_HTTP_URLS
Section titled “DOCTOR_NET_HTTP_URLS”DNS servers asked directly - a Pi-hole, AdGuard, the router - as ip, ip:port or a container name on a network the doctor shares. Empty by default: which ones exist is the network’s business.
Default: https://www.cloudflare.com/cdn-cgi/trace · Type: comma-separated list
DOCTOR_NET_FAIL_ROUNDS
Section titled “DOCTOR_NET_FAIL_ROUNDS”Rounds in a row a check must fail before an incident opens, and pass before it closes.
Default: 3 · Type: whole number
DOCTOR_NET_TIMEOUT
Section titled “DOCTOR_NET_TIMEOUT”Internet and DNS, checked from the doctor’s container every this many seconds. 0 turns the checks off. “none” empties any of the lists.
Default: 5 · Type: number
Drive health
Section titled “Drive health”DOCTOR_SMART_URL
Section titled “DOCTOR_SMART_URL”The SMART sidecar’s metrics page. off turns drive health off.
Default: http://doctor-smart:9633/metrics · off turns it off
DOCTOR_SMART_TEMP_C
Section titled “DOCTOR_SMART_TEMP_C”The SMART sidecar’s metrics page. off turns drive health off.
Default: 55 · Type: number
DOCTOR_SMART_NVME_TEMP_C
Section titled “DOCTOR_SMART_NVME_TEMP_C”The SMART sidecar’s metrics page. off turns drive health off.
Default: 70 · Type: number
DOCTOR_SMART_WEAR_PCT
Section titled “DOCTOR_SMART_WEAR_PCT”Share of an SSD’s rated write endurance used before it is worth a word.
Default: 90 · Type: number
DOCTOR_SMART_COLD_DEVICES
Section titled “DOCTOR_SMART_COLD_DEVICES”Cold drives: read only every DOCTOR_SMART_COLD_HOURS (default once a day) instead of every five minutes, by a second reader in the sidecar. For drives that even the question “are you asleep?” wakes - an expansion unit in deep sleep powers up for it. List their device files, comma separated; the everyday reader then leaves them alone. Their sleep is not tracked.
Default: none · Type: comma-separated list
DOCTOR_SMART_COLD_HOURS
Section titled “DOCTOR_SMART_COLD_HOURS”Cold drives: read only every DOCTOR_SMART_COLD_HOURS, by a second reader in the sidecar, because even asking whether they sleep wakes them - an expansion unit in deep sleep powers up for it. Their device files, comma separated, as for DOCTOR_SMART_DEVICES; the sidecar reads the same list.
Default: 24 · Type: number
DOCTOR_SMART_COLD_URL
Section titled “DOCTOR_SMART_COLD_URL”Cold drives: read only every DOCTOR_SMART_COLD_HOURS, by a second reader in the sidecar, because even asking whether they sleep wakes them - an expansion unit in deep sleep powers up for it. Their device files, comma separated, as for DOCTOR_SMART_DEVICES; the sidecar reads the same list.
Default: http://doctor-smart:9634/metrics
Remediation
Section titled “Remediation”DOCTOR_AUTO_ACTIONS
Section titled “DOCTOR_AUTO_ACTIONS”Auto-applies: only in auto mode.
Default: restart_container · Any of: none, notify_only, restart_container, stop_container, prune_images
DOCTOR_MIN_CONFIDENCE
Section titled “DOCTOR_MIN_CONFIDENCE”observe- diagnose and notify, never touch anything <- start heresuggest- propose an action, wait for you to approve it in the dashboardauto- apply allowed actions without asking
Default: 0.75 · Type: number
DOCTOR_MAX_ACTIONS_PER_CONTAINER_PER_HOUR
Section titled “DOCTOR_MAX_ACTIONS_PER_CONTAINER_PER_HOUR”Circuit breakers: at most this many actions on one container, and on the whole host, in any hour. doctor.max_actions_per_hour tightens the first.
Default: 3 · Type: whole number
DOCTOR_MAX_ACTIONS_GLOBAL_PER_HOUR
Section titled “DOCTOR_MAX_ACTIONS_GLOBAL_PER_HOUR”Circuit breakers: at most this many actions on one container, and on the whole host, in any hour. doctor.max_actions_per_hour tightens the first.
Default: 10 · Type: whole number
DOCTOR_ACTION_COOLDOWN_MINUTES
Section titled “DOCTOR_ACTION_COOLDOWN_MINUTES”Blocks re-running the same action for the same fingerprint.
Default: 30 · Type: whole number
DOCTOR_VERIFY_DELAY
Section titled “DOCTOR_VERIFY_DELAY”Seconds to wait after an action before checking whether it actually helped.
Default: 45 · Type: whole number
Incident lifecycle
Section titled “Incident lifecycle”DOCTOR_INCIDENT_DEDUP_HOURS
Section titled “DOCTOR_INCIDENT_DEDUP_HOURS”A recurrence within this many hours of the last sighting folds into the open incident instead of opening a new one.
Default: 24 · Type: whole number
DOCTOR_AUTO_RESOLVE_HOURS
Section titled “DOCTOR_AUTO_RESOLVE_HOURS”An incident whose condition has not re-fired for this long resolves itself; 0 turns that off.
Default: 12 · Type: whole number
DOCTOR_RETENTION_DAYS
Section titled “DOCTOR_RETENTION_DAYS”Read GitHub release notes for images with a newer version, to link them and flag the ones that mention breaking changes. One unauthenticated request per such image per check.
Default: 30 · Type: whole number
Access
Section titled “Access”DOCTOR_OIDC_ISSUER
Section titled “DOCTOR_OIDC_ISSUER”OIDC sign-in through your own provider (Pocket ID, Authentik, Keycloak…). Empty issuer turns it off. The provider’s callback URL is <DOCTOR_PUBLIC_URL>/auth/callback.
Default: unset · Environment only
DOCTOR_OIDC_CLIENT_ID
Section titled “DOCTOR_OIDC_CLIENT_ID”The client ID registered with the provider for the doctor.
Default: unset · Environment only
DOCTOR_PUBLIC_URL
Section titled “DOCTOR_PUBLIC_URL”The dashboard’s own address, as the browser reaches it. Also used for the links in notifications.
Default: unset · Environment only
DOCTOR_WEB_PASSWORD
Section titled “DOCTOR_WEB_PASSWORD”Protects the dashboard. Required; a long random one, e.g. openssl rand -base64 24. With neither a password nor OIDC set, the dashboard and its API refuse every request, because the dashboard can restart containers. Known placeholders (change-me, changeme, password, admin, doctor, secret, 123456, the user name…) are refused: the doctor logs a warning and treats sign-in as unconfigured. Under 12 characters works, with a warning at startup.
Default: unset · Secret
DOCTOR_OIDC_CLIENT_SECRET
Section titled “DOCTOR_OIDC_CLIENT_SECRET”The client ID registered with the provider for the doctor.
Default: unset · Secret
DOCTOR_OIDC_ALLOWED_GROUPS
Section titled “DOCTOR_OIDC_ALLOWED_GROUPS”Comma-separated groups allowed in; empty lets in any account the provider authenticates.
Default: none · Type: comma-separated list · Environment only
DOCTOR_SESSION_HOURS
Section titled “DOCTOR_SESSION_HOURS”Hours an unused session lasts.
Default: 12 · Type: whole number · Environment only
DOCTOR_SESSION_SECRET
Section titled “DOCTOR_SESSION_SECRET”Signs the session cookie. Unset, one is generated once and kept in the data directory (session_secret, mode 0600). openssl rand -base64 32
Default: unset · Secret
DOCTOR_WEB_PASSWORD_FALLBACK
Section titled “DOCTOR_WEB_PASSWORD_FALLBACK”With OIDC on, the password is refused unless this is true - a way back in when the provider itself is what is broken.
Default: off · Type: on / off · Environment only
DOCTOR_WIDGET_TOKEN
Section titled “DOCTOR_WIDGET_TOKEN”Read-only token for a Homepage tile: opens /api/widget, a few counts, and nothing else. openssl rand -hex 24
Default: unset · Secret
Briefing
Section titled “Briefing”DOCTOR_BRIEFING
Section titled “DOCTOR_BRIEFING”The summary at the top of the dashboard. false leaves the facts without a model’s words. An empty model uses DOCTOR_MODEL; a smaller one is plenty.
Default: on · Type: on / off
DOCTOR_BRIEFING_MODEL
Section titled “DOCTOR_BRIEFING_MODEL”A smaller model is plenty for three lines of summary. Empty: DOCTOR_MODEL.
Default: unset
DOCTOR_BRIEFING_REFRESH_MINUTES
Section titled “DOCTOR_BRIEFING_REFRESH_MINUTES”How often a section may be rewritten when its facts change without its level changing. A new critical incident does not wait for this.
Default: 15 · Type: whole number
Classifier
Section titled “Classifier”DOCTOR_CLASSIFIER
Section titled “DOCTOR_CLASSIFIER”A decision model’s second opinion on judgement signals (error bursts, health checks, CPU/memory) before they become incidents. off | shadow | on. shadow records verdicts and changes nothing - run it that way first.
Default: off · One of: off, shadow, on
DOCTOR_CLASSIFIER_PROVIDER
Section titled “DOCTOR_CLASSIFIER_PROVIDER”Openrouter: a decision model via OpenRouter’s Decisions API (Jev). chat: the diagnosis’s own model; uncalibrated, so it never hides anything.
Default: openrouter · One of: openrouter, chat
DOCTOR_CLASSIFIER_MODEL
Section titled “DOCTOR_CLASSIFIER_MODEL”Pinned rather than -latest, so verdicts do not drift under you.
Default: typesafe/jev-1.13
DOCTOR_CLASSIFIER_URL
Section titled “DOCTOR_CLASSIFIER_URL”The Decisions API endpoint the key is sent to.
Default: https://openrouter.ai/api/alpha/decisions · Environment only
DOCTOR_CLASSIFIER_API_KEY
Section titled “DOCTOR_CLASSIFIER_API_KEY”An OpenRouter key. Give it its own credit limit on openrouter.ai. Unset: the diagnosis’s DOCTOR_OPENAI_API_KEY, if that is an OpenRouter one.
Default: unset · Secret
DOCTOR_CLASSIFIER_SUPPRESS_AT
Section titled “DOCTOR_CLASSIFIER_SUPPRESS_AT”Likely-noise probability at or above which a signal opens no incident (on).
Default: 0.9 · Type: number
DOCTOR_CLASSIFIER_DAILY_CALLS
Section titled “DOCTOR_CLASSIFIER_DAILY_CALLS”Its own caps, separate from the diagnosis’s.
Default: 500 · Type: whole number
DOCTOR_CLASSIFIER_DAILY_USD
Section titled “DOCTOR_CLASSIFIER_DAILY_USD”Probability of noise at or above which a signal opens no incident.
Default: 0.1 · Type: number
DOCTOR_CLASSIFIER_MAX_PER_MINUTE
Section titled “DOCTOR_CLASSIFIER_MAX_PER_MINUTE”A host coming back up fires everything at once; past this, the rules decide alone until the minute is over.
Default: 10 · Type: whole number
DOCTOR_CLASSIFIER_CACHE_HOURS
Section titled “DOCTOR_CLASSIFIER_CACHE_HOURS”A host coming back up fires everything at once; past this, the rules decide alone until the minute is over.
Default: 6 · Type: whole number
DOCTOR_CLASSIFIER_TIMEOUT
Section titled “DOCTOR_CLASSIFIER_TIMEOUT”A host coming back up fires everything at once; past this, the rules decide alone until the minute is over.
Default: 5 · Type: number
Updates
Section titled “Updates”DOCTOR_IMAGE_CHECK_HOURS
Section titled “DOCTOR_IMAGE_CHECK_HOURS”How often to ask the registries what they publish; 0 turns the check off.
Default: 12 · Type: whole number · Applies on restart
DOCTOR_UPDATE_COOLDOWN_DAYS
Section titled “DOCTOR_UPDATE_COOLDOWN_DAYS”Days a release must be on Docker Hub before it counts as newer - match your Dependabot or Renovate cooldown, if you use one. 0: at once.
Default: 3 · Type: whole number
DOCTOR_RELEASE_NOTES
Section titled “DOCTOR_RELEASE_NOTES”Read GitHub release notes for images with a newer version.
Default: on · Type: on / off
DOCTOR_GITHUB_TOKEN
Section titled “DOCTOR_GITHUB_TOKEN”Redeploy a stack from the Updates page when its image has a new build. The doctor runs a GitHub Actions workflow in the repository the stacks are deployed from, which redeploys the stack - see examples/redeploy-workflow.yml for what it must accept. A fine-grained token on that repository only, with Actions: read and write, and Contents: read. Unset, the page only reports.
Default: unset · Secret
GitHub
Section titled “GitHub”DOCTOR_DEPLOY_REPO
Section titled “DOCTOR_DEPLOY_REPO”Owner/repository the stacks are deployed from; see examples/redeploy-workflow.yml.
Default: unset
DOCTOR_DEPLOY_WORKFLOW
Section titled “DOCTOR_DEPLOY_WORKFLOW”Owner/repository the stacks are deployed from; see examples/redeploy-workflow.yml.
Default: deploy-stacks.yml
DOCTOR_DEPLOY_REF
Section titled “DOCTOR_DEPLOY_REF”Owner/repository the stacks are deployed from; see examples/redeploy-workflow.yml.
Default: main
Notifications
Section titled “Notifications”DOCTOR_NTFY_URL
Section titled “DOCTOR_NTFY_URL”Ntfy push notifications, off until both a server URL and a topic are set. The URL and token are environment-only. On ntfy.sh anyone who knows or guesses a topic’s name can read it, so pick a long random one (openssl rand -hex 16), protect it with an access token, or run your own ntfy server.
Default: unset · Environment only
DOCTOR_NTFY_TOPIC
Section titled “DOCTOR_NTFY_TOPIC”The ntfy topic notifications are published to. No default: a topic on a public server is readable by anyone who guesses its name, so it has to be chosen - long and random on ntfy.sh.
Default: unset
DOCTOR_NTFY_TOKEN
Section titled “DOCTOR_NTFY_TOKEN”Access token for a protected ntfy topic.
Default: unset · Secret
Startup and runtime
Section titled “Startup and runtime”DOCTOR_BUILD
Section titled “DOCTOR_BUILD”Stamped into the image by CI. “dev” means a local build.
Default: dev · Environment only
DOCTOR_CLASSIFIER_MAX_STATE_CHARS
Section titled “DOCTOR_CLASSIFIER_MAX_STATE_CHARS”Evidence sent per call, in characters (about 3,000 tokens).
Default: 12000 · Type: whole number
DOCTOR_CLASSIFIER_PRICE_PER_MTOK
Section titled “DOCTOR_CLASSIFIER_PRICE_PER_MTOK”Input price, USD per million tokens, when OpenRouter does not report the cost itself. Jev’s as of October 2026 - check the model page.
Default: 0.042 · Type: number
DOCTOR_DATA_DIR
Section titled “DOCTOR_DATA_DIR”Where the database lives inside the container; mount a volume here.
Default: /data · Environment only
DOCTOR_DISK_SAMPLE_MINUTES
Section titled “DOCTOR_DISK_SAMPLE_MINUTES”How often a disk’s free space is recorded for the fill forecast.
Default: 60 · Type: whole number
DOCTOR_IGNORE_CONTAINERS
Section titled “DOCTOR_IGNORE_CONTAINERS”Comma-separated container names the doctor must never look at or touch.
Default: none · Type: comma-separated list
DOCTOR_LLM_MAX_RETRIES
Section titled “DOCTOR_LLM_MAX_RETRIES”Retries on 429 / 5xx, honouring Retry-After. Free tiers rate-limit hard.
Default: 3 · Type: whole number
DOCTOR_LLM_TIMEOUT
Section titled “DOCTOR_LLM_TIMEOUT”Free tiers rate-limit hard (Gemini free: 10/minute); retry rather than lose the diagnosis.
Default: 180 · Type: number
DOCTOR_LOG_ERROR_PATTERN
Section titled “DOCTOR_LOG_ERROR_PATTERN”The wording that counts as an error, as a Python regular expression. The default matches fatal, panic, traceback, segfault, out of memory, oomkill, connection refused, no such host, permission denied, disk full, no space left, deadlock and unhandled exception, case-insensitively.
Default: (?i)\b(fatal|panic|traceback|segfault|out of memory|oomkill|connection refused|no such host|permission denied|disk full|no space left|deadlock|unhandled exception)\b
DOCTOR_LOG_LEVEL
Section titled “DOCTOR_LOG_LEVEL”The release, X.Y.Z, for an image the Release workflow built; empty otherwise.
Default: INFO · Environment only
DOCTOR_MAX_OUTPUT_TOKENS
Section titled “DOCTOR_MAX_OUTPUT_TOKENS”Upper bound on the length of one answer.
Default: 4000 · Type: whole number
DOCTOR_OIDC_GROUPS_CLAIM
Section titled “DOCTOR_OIDC_GROUPS_CLAIM”The ID token claim holding the user’s groups, for DOCTOR_OIDC_ALLOWED_GROUPS.
Default: groups · Environment only
DOCTOR_OIDC_SCOPES
Section titled “DOCTOR_OIDC_SCOPES”Scopes requested at sign-in, space-separated.
Default: openid profile email groups · Environment only
DOCTOR_SELF_NAME
Section titled “DOCTOR_SELF_NAME”The doctor’s own container name, which it never diagnoses or restarts.
Default: container-doctor
DOCTOR_SETTINGS_EDITABLE
Section titled “DOCTOR_SETTINGS_EDITABLE”Settings can be changed on the Settings page by anyone who can sign in; a variable set here always overrides what was saved there. false makes the page read-only.
Default: on · Type: on / off · Environment only
DOCTOR_VERSION
Section titled “DOCTOR_VERSION”The release, X.Y.Z, for an image the Release workflow built; empty otherwise.
Default: unset · Environment only
DOCTOR_WEB_HOST
Section titled “DOCTOR_WEB_HOST”Address and port the dashboard listens on inside the container.
Default: 0.0.0.0 · Environment only
DOCTOR_WEB_PORT
Section titled “DOCTOR_WEB_PORT”Address and port the dashboard listens on inside the container.
Default: 8080 · Type: whole number · Environment only
DOCTOR_WEB_USER
Section titled “DOCTOR_WEB_USER”The user name that password signs in as.
Default: doctor · Environment only
Read by the compose file
Section titled “Read by the compose file”These never reach the doctor: the reference compose file reads them itself.
DOCTOR_PROXY_ALLOW_POST
Section titled “DOCTOR_PROXY_ALLOW_POST”Set to 0 to close the socket proxy’s only write route. The doctor then physically cannot restart anything, whatever mode it is in. (This maps to ALLOW_RESTARTS on the proxy; the global POST gate is always off, which is what keeps /containers/create - arbitrary host mounts - out of reach.)
DOCTOR_PROXY_ALLOW_IMAGES
Section titled “DOCTOR_PROXY_ALLOW_IMAGES”0 denies the read-only GET /images/
DOCTOR_DOCKER_HOST
Section titled “DOCTOR_DOCKER_HOST”Where the doctor reaches Docker. Point it at a socket proxy you already run (see https://sebastianbuechler.github.io/container-doctor/guides/socket-proxy/, “Reusing yours instead”).
COMPOSE_PROFILES
Section titled “COMPOSE_PROFILES”Drive health from the doctor-smart sidecar (Storage page). The sidecar is opt-in, since it has raw disk access: start the stack with docker compose --profile smart up -d, or set COMPOSE_PROFILES=smart. “auto” finds the drives; or list their device files, space or comma separated. Give SATA drives their type, /dev/sata1;sat, or smartctl may read a WD as SCSI.
DOCTOR_SMART_DEVICES
Section titled “DOCTOR_SMART_DEVICES”Drive health from the doctor-smart sidecar (Storage page). The sidecar is opt-in, since it has raw disk access: start the stack with docker compose --profile smart up -d, or set COMPOSE_PROFILES=smart. “auto” finds the drives; or list their device files, space or comma separated. Give SATA drives their type, /dev/sata1;sat, or smartctl may read a WD as SCSI.
DOCTOR_PORT
Section titled “DOCTOR_PORT”Read by compose.example.yaml itself: the dashboard’s port on the host, and where the database lives on the host and who owns it. Create the directory and chown it to DOCTOR_UID:DOCTOR_GID before the first start.
DOCTOR_DATA_VOLUME
Section titled “DOCTOR_DATA_VOLUME”Read by compose.example.yaml itself: the dashboard’s port on the host, and where the database lives on the host and who owns it. Create the directory and chown it to DOCTOR_UID:DOCTOR_GID before the first start.
DOCTOR_UID
Section titled “DOCTOR_UID”Read by compose.example.yaml itself: the dashboard’s port on the host, and where the database lives on the host and who owns it. Create the directory and chown it to DOCTOR_UID:DOCTOR_GID before the first start.
DOCTOR_GID
Section titled “DOCTOR_GID”Read by compose.example.yaml itself: the dashboard’s port on the host, and where the database lives on the host and who owns it. Create the directory and chown it to DOCTOR_UID:DOCTOR_GID before the first start.
DOCTOR_IMAGE_TAG
Section titled “DOCTOR_IMAGE_TAG”Pin to a specific published image instead of tracking latest, e.g. X.Y.Z or a sha-
Pin to a specific published image instead of tracking latest, e.g. X.Y.Z or a sha-