Config Reference
Complete field reference for the dockward JSON configuration file, including defaults and validation rules.
Last updated: March 4, 2026
Config Reference
All configuration is loaded from a single JSON file. Default path: /etc/dockward/config.json. Override with -config <path>.
For a walkthrough with annotated examples, see Configuration.
Top-Level Structure
{
"runtime": "docker",
"registry": { ... },
"api": { ... },
"audit": { ... },
"monitor": { ... },
"notifications": { ... },
"push": { ... },
"services": [ ... ]
}
runtime
Specifies the container runtime to use for all compose operations.
| Field | Type | Default | Description |
|---|---|---|---|
runtime |
string | "docker" |
Container runtime executable: "docker" or "podman". Both support the same compose subcommand syntax |
"runtime": "podman"
Both Docker and Podman use the same compose command syntax (docker compose / podman compose), making them interchangeable. This setting determines which executable is called.
registry
Controls the registry polling behaviour used by full-mode services.
| Field | Type | Default | Description |
|---|---|---|---|
url |
string | "http://localhost:5000" |
Base URL of the local Docker registry |
poll_interval |
integer | 300 |
Seconds between registry poll cycles (image digest comparison) |
insecure |
boolean | false |
Skip TLS verification when connecting to registry (for self-signed certificates) |
"registry": {
"url": "http://localhost:5000",
"poll_interval": 300,
"insecure": false
}
Only set insecure: true for private registries with self-signed certificates. Never use with public registries.
monitor
Controls container resource stat collection (CPU, memory). Independent of registry polling.
| Field | Type | Default | Description |
|---|---|---|---|
stats_interval |
integer | registry.poll_interval |
Seconds between container stat collections. Set lower than poll_interval (e.g. 30) to get fresher CPU/memory data in the UI and /status endpoint without polling the registry more often |
"monitor": {
"stats_interval": 30
}
docker_health
Controls Docker daemon health checking. Dockward continuously monitors Docker connectivity to detect when the daemon is unavailable.
| Field | Type | Default | Description |
|---|---|---|---|
check_interval |
integer | 30 |
Seconds between Docker daemon health checks (min: 5, max: 3600) |
timeout |
integer | 5 |
Timeout for each health check request in seconds (min: 1, max: 30, must be less than check_interval) |
"docker_health": {
"check_interval": 30,
"timeout": 5
}
Health status is exposed via:
/healthendpoint (returns 503 when Docker is unavailable)- Prometheus metrics:
docker_daemon_healthy,docker_daemon_consecutive_failures,docker_daemon_checks_total
See Docker Daemon Health Checks for details.
api
Controls the HTTP API server. Supports multiple listen addresses.
| Field | Type | Default | Description |
|---|---|---|---|
address |
string[] | ["127.0.0.1:9090"] |
List of host:port addresses to listen on. Multiple entries start one HTTP server per address, all sharing the same handler |
"api": {
"address": ["127.0.0.1:9090"]
}
Multiple addresses (e.g. localhost + LAN):
"api": {
"address": ["127.0.0.1:9090", "10.0.0.5:9090"]
}
Using "0.0.0.0:9090" exposes the API to your network. The API has no authentication — only do this on trusted networks or behind a reverse proxy with auth.
api.address changed from a single string to an array of host:port strings. The separate api.port field was removed. Migrate by combining the old address and port: "address": "127.0.0.1" + "port": "9090" becomes "address": ["127.0.0.1:9090"].
audit
Audit logging is opt-in. Omit the section or leave path empty to disable it.
| Field | Type | Default | Description |
|---|---|---|---|
path |
string | "" |
Absolute path to the audit log file. Created if it does not exist. Empty disables audit logging |
"audit": {
"path": "/var/log/dockward/audit.jsonl"
}
The file is written in JSON Lines format — one JSON object per line. Each entry contains: timestamp, service, event, message, level, and optional fields (old_digest, new_digest, container, reason). See Audit Log Guide for event types and usage.
notifications
All notification channels are optional. Omit any channel to disable it. See Notifications Reference for template fields and event types.
notifications.discord
| Field | Type | Required | Description |
|---|---|---|---|
webhook_url |
string | yes | Discord channel webhook URL |
notifications.smtp
| Field | Type | Required | Description |
|---|---|---|---|
host |
string | yes | SMTP server hostname |
port |
integer | yes | SMTP server port |
from |
string | yes | Sender address |
to |
string | yes | Recipient address |
username |
string | no | SMTP auth username |
password |
string | no | SMTP auth password |
notifications.webhooks
Array of custom webhook definitions.
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | yes | Identifier for this webhook |
url |
string | yes | Endpoint URL |
method |
string | yes | HTTP method (e.g. "POST") |
headers |
object | no | Key-value HTTP headers; values support $ENV_VAR expansion |
body |
string | no | Request body; Go text/template with notification fields |
push
Optional. When warden_url is set, every audit entry is forwarded to the warden asynchronously. Push is fire-and-forget — agent operation is not affected by warden availability.
| Field | Type | Default | Description |
|---|---|---|---|
warden_url |
string | "" |
Warden base URL (e.g. https://warden.example.com). Empty disables push |
token |
string | "" |
Bearer token matching the warden’s agents[].token. $ENV_VAR expansion supported |
machine_id |
string | "" |
Identifier shown in the warden dashboard (e.g. ovh-01) |
"push": {
"warden_url": "https://warden.example.com",
"token": "$DOCKWARD_PUSH_TOKEN",
"machine_id": "ovh-01"
}
services
Array of service definitions. Each service is independent — fields used depend on which modes are enabled.
| Field | Type | Default | Description |
|---|---|---|---|
name |
string | required | Unique service identifier used in API paths, metrics labels, and notifications |
images |
[]string | — | Registry image references (e.g. ["api:latest", "worker:latest"]). Required when auto_update: true. One deploy per compose project when any image changes |
silent |
boolean | false |
Skip validation and monitoring for this service. Use for internal or externally-managed services referenced for healer-only purposes |
compose_files |
[]string | — | Absolute paths to compose files, applied in order. Required when auto_update: true |
compose_project |
string | — | Docker Compose project name (-p flag). Required when auto_update: true |
container_name |
string | — | Container name for event matching. Used for standalone containers or as fallback |
env_file |
string | — | Path to a .env file. Variables are loaded into the process environment before running compose, making them available for ${VAR} interpolation in compose files |
auto_update |
boolean | false |
Enable registry polling and auto-deploy for this service |
auto_start |
boolean | false |
When true and digests match, start the compose project if no containers are running. Forces down+up if containers are stuck (created/restarting) |
auto_heal |
boolean | false |
Enable auto-restart on unhealthy health status |
compose_watch |
boolean | false |
Re-deploy on compose file content change (no image pull). Computes SHA-256 of all compose_files each poll cycle; runs compose up -d when the hash changes. First run stores the hash without deploying |
cpu_threshold |
float | 0 |
Alert when CPU usage exceeds this percentage. 0 disables. Uses same cooldown as heal_cooldown |
memory_threshold |
float | 0 |
Alert when memory usage exceeds this percentage. 0 disables. Uses same cooldown as heal_cooldown |
health_grace |
integer | 60 |
Seconds to wait after deploy before evaluating container health |
heal_cooldown |
integer | 300 |
Minimum seconds between consecutive auto-restarts |
heal_max_restarts |
integer | 3 |
Maximum consecutive failed restarts before giving up |
Validation Rules
Global Validation (Fatal)
These validation errors cause dockward to exit immediately:
runtimemust be"docker"or"podman"api.portmust be a valid port number (1-65535)registry.poll_intervalmust be 10-86400 secondsdocker_health.check_intervalmust be 5-3600 secondsdocker_health.timeoutmust be 1-30 seconds and less thancheck_interval
Service Validation (Non-Fatal)
As of v1.0.0-alpha.9: Service-level validation errors are non-fatal. Invalid services are logged as warnings and excluded from monitoring, while valid services continue operating normally.
Invalid services trigger warnings like:
[config] WARNING: 1 service(s) failed validation and will be skipped:
- service[18] "otel-collector": compose_file[0] not found: "/srv/observability/docker-compose.yml"
Service validation rules:
auto_update: truerequires at least one entry inimages, at least one entry incompose_files, andcompose_projectauto_heal: truerequires at least one ofcompose_projectorcontainer_namefor Docker event matchingcompose_filespaths must be absolute, must exist, and must be regular files (no directories or symlinks)compose_projectmust match pattern^[a-zA-Z0-9_-]{1,64}$(security: prevents command injection)env_filepath must be absolute and must exist if specified- Path traversal attempts (
..) are forbidden in all file paths (security) silent: trueskips all validation rules for the service
Monitoring invalid services: Use GET /health to see config_warnings array with reasons for each skipped service.
Full Example
{
"runtime": "docker",
"registry": {
"url": "http://localhost:5000",
"poll_interval": 300,
"insecure": false
},
"monitor": {
"stats_interval": 30
},
"docker_health": {
"check_interval": 30,
"timeout": 5
},
"api": {
"address": ["127.0.0.1:9090"]
},
"audit": {
"path": "/var/log/dockward/audit.jsonl"
},
"notifications": {
"discord": {
"webhook_url": "https://discord.com/api/webhooks/ID/TOKEN"
},
"smtp": {
"host": "smtp.example.com",
"port": 587,
"from": "alerts@example.com",
"to": "ops@example.com",
"username": "",
"password": ""
},
"webhooks": [
{
"name": "my-webhook",
"url": "https://example.com/hook",
"method": "POST",
"headers": {
"Authorization": "Bearer $MY_TOKEN"
},
"body": "{\"service\":\"{{ .Service }}\",\"event\":\"{{ .Event }}\"}"
}
]
},
"push": {
"warden_url": "https://warden.example.com",
"token": "$DOCKWARD_PUSH_TOKEN",
"machine_id": "ovh-01"
},
"services": [
{
"name": "myapp",
"images": ["myapp:latest"],
"silent": false,
"compose_files": [
"/srv/myapp/docker-compose.yml",
"/srv/myapp/docker-compose.override.yml"
],
"compose_project": "myapp",
"container_name": "",
"env_file": "/srv/myapp/.env",
"auto_update": true,
"auto_start": true,
"auto_heal": true,
"compose_watch": false,
"cpu_threshold": 80,
"memory_threshold": 85,
"health_grace": 60,
"heal_cooldown": 300,
"heal_max_restarts": 3
},
{
"name": "standalone-api",
"container_name": "standalone-api",
"auto_heal": true,
"heal_cooldown": 120,
"heal_max_restarts": 5
}
]
}