v2.31.0-dev23 58a92f3

reference.md RawHistoryFolder

Configuration Reference

Complete configuration reference with all options and their default values.

Full Configuration Example

# =============================================================================
# SERVER
# =============================================================================
[server]
registry_port = 5000                         # Container registry port
tls_cert_file = ""                           # PEM cert path (optional, for static TLS fallback)
tls_key_file = ""                            # PEM key path (optional, must be set with tls_cert_file)
force_https_redirect = false                 # Redirect all HTTP traffic to HTTPS (for direct-access setups)
gordon_domain = ""                           # Required: Gordon domain (registry + API)
data_dir = "~/.gordon"                       # Data directory (varies by install type)
max_blob_chunk_size = "95MB"                 # Max size per registry blob upload chunk
max_blob_size = "1GB"                        # Max cumulative size per registry blob/layer upload
registry_allowed_ips = []                    # IPs or CIDR ranges allowed to access the registry (empty = allow all)
proxy_allowed_ips = []                       # IPs or CIDR ranges allowed to reach HTTP proxy paths (empty = allow all, e.g. Cloudflare IPs)
registry_listen_address = ""                 # Bind address for registry (empty = all interfaces, "127.0.0.1" = loopback only)

# =============================================================================
# ENTRYPOINTS
# =============================================================================
[entrypoints.edge]
address = ":443"                             # Deployment-selected public TCP socket
protocol = "smart_tcp"                       # Sniff HTTP, h2c, TLS, passthrough, or explicit raw fallback
trusted_cidrs = []                            # Peer socket IP allowlist for all traffic on this entrypoint
# raw_fallback = "ssh-fallback"              # Optional TCP router for unknown non-HTTP/non-TLS bytes
# raw_fallback_trusted_cidrs = ["100.64.0.0/10"]
# allow_public_raw_fallback = false

# =============================================================================
# DNS
# =============================================================================
[dns]
resolvers = ["1.1.1.1:53", "8.8.8.8:53"] # Recursive resolvers for public DNS visibility checks
propagation_timeout = "5m"                 # Max wait for DNS-01 TXT propagation
polling_interval = "5s"                    # Interval between DNS-01 propagation checks

# =============================================================================
# AUTHENTICATION (required - Gordon won't start without credentials configured)
# =============================================================================
[auth]
enabled = true                               # Enable registry authentication (default: true)
secrets_backend = "unsafe"                   # "pass", "sops", or "unsafe"
token_secret = ""                            # Path in secrets backend to JWT signing key (REQUIRED)
token_expiry = "30d"                         # Token expiry duration
access_token_ttl = "15m"                     # Ephemeral access token lifetime (default: 15m)

# =============================================================================
# PUBLIC TLS / ACME
# =============================================================================
[tls.acme]
enabled = false                              # Enable public ACME certificates (requires HTTPS fallback on a TLS-capable entrypoint)
email = ""                                   # ACME account email when enabled
challenge = "auto"                           # "auto", "http-01", or "cloudflare-dns-01"
obtain_batch_size = 1                         # New certificate orders per reconcile run

# =============================================================================
# API (applies to both Registry and Admin endpoints)
# =============================================================================
[api.rate_limit]
enabled = true                               # Enable rate limiting (default: true)
global_rps = 500                             # Max requests/second globally
per_ip_rps = 50                              # Max requests/second per client IP
burst = 100                                  # Burst size for rate limiters
trusted_proxies = []                         # IPs/CIDRs trusted to set X-Forwarded-For

# =============================================================================
# LOGGING
# =============================================================================
[logging]
level = "info"                               # "debug", "info", "warn", "error"
format = "console"                           # "console" or "json"

[logging.file]
enabled = false                              # Enable file logging
path = ""                                    # Log file path (default: {data_dir}/logs/gordon.log)
max_size = 100                               # Max size in MB before rotation
max_backups = 3                              # Number of old files to keep
max_age = 28                                 # Days to keep old files

[logging.container_logs]
enabled = true                               # Enable container log collection
dir = ""                                     # Log directory (default: {data_dir}/container-logs)
max_size = 100                               # Max size in MB before rotation
max_backups = 3                              # Number of old files to keep
max_age = 28                                 # Days to keep old files

[logging.access_log]
enabled = false                              # Dedicated HTTP access log for reverse-proxy traffic
format = "json"                             # "json", "clf", or "combined"
output = "stdout"                           # "stdout", "file", or "journald"
file_path = ""                               # Required when output = "file"
max_size = 100                               # Max size in MB before rotation (file output)
max_backups = 3                              # Number of old files to keep (file output)
max_age = 28                                 # Days to keep old files (file output)
exclude_health_checks = true                 # Skip noisy readiness/liveness requests
syslog_identifier = "gordon-access"         # Journald identifier when output = "journald"

# =============================================================================
# TELEMETRY (OpenTelemetry)
# =============================================================================
[telemetry]
enabled = false                              # Enable OTLP telemetry export
endpoint = ""                                # OTLP HTTP endpoint URL
auth_token = ""                              # Base64-encoded user:password for Basic auth
traces = true                                # Export distributed traces
metrics = true                               # Export metrics
logs = true                                  # Bridge zerolog output to OTLP logs
trace_sample_rate = 1.0                      # Fraction of traces to sample (0.0–1.0)

# =============================================================================
# ENVIRONMENT
# =============================================================================
[env]
dir = ""                                     # Env files directory (default: {data_dir}/env)

# =============================================================================
# DEPLOYMENT
# =============================================================================
[deploy]
pull_policy = "if-tag-changed"               # "always", "if-tag-changed", "never"
readiness_mode = "auto"                      # "auto", "docker-health", "delay"
health_timeout = "90s"                       # Max wait for health-based readiness
readiness_delay = "5s"                       # Wait after running before considered ready
drain_mode = "auto"                          # "auto", "inflight", "delay"
drain_timeout = "30s"                        # Max wait for in-flight request drain
drain_delay = "2s"                           # Wait after cache invalidation before old stop

# =============================================================================
# CONTAINERS
# =============================================================================
[containers]
security_profile = "compat"                  # "compat" or "strict"

# =============================================================================
# AUTO-ROUTE
# =============================================================================
[auto_route]
enabled = false                              # Create routes from image labels automatically

# =============================================================================
# NETWORK ISOLATION
# =============================================================================
[network_isolation]
enabled = true                               # Enable per-app Docker networks
network_prefix = "gordon"                    # Prefix for created networks
internal = false                             # Create Docker internal networks (blocks direct egress)

# =============================================================================
# VOLUMES
# =============================================================================
[volumes]
auto_create = true                           # Auto-create volumes from Dockerfile VOLUME
prefix = "gordon"                            # Volume name prefix
preserve = true                              # Keep volumes when containers are removed

# =============================================================================
# ROUTES
# =============================================================================
[routes]
# "domain.com" = { image = "image:tag" }
# "insecure.domain.com" = { image = "image:tag", https = false }
# Legacy "http://domain.com" keys are read for compatibility and rewritten on save.

# =============================================================================
# EXTERNAL ROUTES
# =============================================================================
[external_routes]
# "domain.com" = "host:port"                 # Proxy to non-container services

# =============================================================================
# STANDALONE SERVICES
# =============================================================================
# [[services]]
# name = "rust"
# image = "registry.example.com:5000/rust:latest"
# enabled = true
# env_file = "/srv/gordon/services/rust.env"
#
# [[services.ports]]
# name = "game"
# container = 28015
# protocol = "udp"
# publish = "127.0.0.1:38015"
#
# [[services.ports]]
# name = "rcon"
# container = 28016
# protocol = "tcp"
# publish = "127.0.0.1:38016"
# trusted_cidrs = ["100.64.0.0/10"]

# =============================================================================
# NETWORK GROUPS
# =============================================================================
[network_groups]
# "group-name" = ["domain1.com", "domain2.com"]

# =============================================================================
# ATTACHMENTS
# =============================================================================
[attachments]
# "domain-or-group" = ["image1:tag", "image2:tag"]

# =============================================================================
# BACKUPS
# =============================================================================
[backups]
enabled = false                              # Enable backup service
schedule = "daily"                          # "hourly", "daily", "weekly", "monthly"
storage_dir = ""                            # Backup root (default: {data_dir}/backups)

[backups.retention]
hourly = 0                                   # Keep N hourly backups per DB
daily = 0                                    # Keep N daily backups per DB
weekly = 0                                   # Keep N weekly backups per DB
monthly = 0                                  # Keep N monthly backups per DB

# =============================================================================
# IMAGES
# =============================================================================
[images]
allowed_registries = []
require_digest = false

[images.prune]
enabled = false                              # Enable scheduled image cleanup
schedule = "daily"                          # "hourly", "daily", "weekly", "monthly"
keep_last = 3                                # Keep N newest tags per repository

# Note: retention values set to 0 keep no backups for that tier.
# For practical defaults, consider setting daily = 7.

Default Values Summary

Setting Default Description
server.registry_port 5000 Container registry port
server.tls_cert_file "" PEM cert path for static TLS (optional)
server.tls_key_file "" PEM key path for static TLS (optional)
server.force_https_redirect false Redirect all HTTP to HTTPS (for direct-access setups)
server.gordon_domain "" Required - Gordon domain
server.data_dir ~/.gordon Data directory
server.max_blob_chunk_size "95MB" Max size per registry blob upload chunk
server.max_blob_size "1GB" Max cumulative size per registry blob/layer upload
server.registry_allowed_ips [] IPs or CIDR ranges allowed to access the registry (empty = allow all)
server.proxy_allowed_ips [] IPs or CIDR ranges allowed to reach the proxy (empty = allow all)
server.registry_listen_address "" Bind address for registry (empty = all interfaces)
entrypoints.<name>.address none Deployment-selected listen address; edge is conventional for route-capable entrypoints but is not required when exactly one smart_tcp or tls_mux entrypoint exists
entrypoints.<name>.protocol none Entrypoint protocol: smart_tcp, tls_mux, tcp, or udp
entrypoints.<name>.trusted_cidrs [] Peer socket IP allowlist for all traffic on the entrypoint
entrypoints.<name>.raw_fallback "" TCP router used by smart TCP for unknown non-HTTP/non-TLS bytes
entrypoints.<name>.raw_fallback_trusted_cidrs [] Peer socket IP allowlist for smart TCP raw fallback
entrypoints.<name>.allow_public_raw_fallback false Explicit acknowledgement for public raw fallback exposure
dns.resolvers ["1.1.1.1:53", "8.8.8.8:53"] Recursive resolvers used for public DNS visibility checks, including ACME DNS-01 propagation
dns.propagation_timeout "5m" Maximum time to wait for DNS-01 TXT records to become visible through configured recursive resolvers
dns.polling_interval "5s" Interval between DNS-01 propagation checks
tls.acme.enabled false Enable public ACME certificates (requires HTTPS fallback on a TLS-capable entrypoint)
tls.acme.email "" ACME account email when enabled
tls.acme.challenge "auto" ACME challenge mode: auto, http-01, or cloudflare-dns-01
tls.acme.obtain_batch_size 1 Maximum new ACME certificate orders per reconcile run
auth.enabled true Enable authentication; when false, run local-only mode (loopback-only /v2/*, /admin/* disabled)
auth.secrets_backend "unsafe" Secrets storage
auth.token_expiry "30d" 30 days
auth.access_token_ttl "15m" Ephemeral access token lifetime
api.rate_limit.enabled true Enable rate limiting
api.rate_limit.global_rps 500 Global requests/second
api.rate_limit.per_ip_rps 50 Per-IP requests/second
api.rate_limit.burst 100 Burst size
api.rate_limit.trusted_proxies [] IPs/CIDRs trusted for X-Forwarded-For
logging.level "info" Log level
logging.format "console" Log format
logging.file.enabled false File logging disabled
logging.file.max_size 100 100 MB
logging.file.max_backups 3 Keep 3 old files
logging.file.max_age 28 28 days
logging.container_logs.enabled true Container logs enabled
logging.container_logs.max_size 100 100 MB
logging.container_logs.max_backups 3 Keep 3 old files
logging.container_logs.max_age 28 28 days
logging.access_log.enabled false Dedicated HTTP access log disabled
logging.access_log.format "json" Access log format (json, clf, combined)
logging.access_log.output "stdout" Access log sink (stdout, file, journald)
logging.access_log.max_size 100 100 MB for file output
logging.access_log.max_backups 3 Keep 3 old files for file output
logging.access_log.max_age 28 28 days for file output
logging.access_log.exclude_health_checks true Skip health-check requests
logging.access_log.syslog_identifier "gordon-access" Journald identifier
telemetry.enabled false Enable OTLP telemetry export
telemetry.endpoint "" OTLP HTTP endpoint URL
telemetry.auth_token "" Base64 user:password for Basic auth
telemetry.traces true Export distributed traces
telemetry.metrics true Export metrics
telemetry.logs true Bridge zerolog to OTLP logs
telemetry.trace_sample_rate 1.0 Fraction of traces to sample (0.0–1.0)
deploy.pull_policy "if-tag-changed" Pull on tag change
deploy.readiness_mode "auto" Readiness strategy (auto, docker-health, delay)
deploy.health_timeout "90s" Max wait for health-based readiness before deploy fails
deploy.readiness_delay "5s" Delay before container is considered ready
deploy.drain_mode "auto" Drain strategy (auto, inflight, delay)
deploy.drain_timeout "30s" Max wait for in-flight request drain before old stop
deploy.drain_delay "2s" Delay before stopping previous container after cache invalidation
containers.security_profile "compat" Runtime hardening profile: compat preserves existing behavior, strict enables read-only rootfs and narrower capabilities
auto_route.enabled false Auto-route disabled
network_isolation.enabled true Network isolation enabled
network_isolation.network_prefix "gordon" Network prefix
network_isolation.internal false Create Docker internal networks without direct external egress
volumes.auto_create true Auto-create volumes
volumes.prefix "gordon" Volume prefix
volumes.preserve true Keep volumes
services[].name none Standalone service name used by service:<service>:<port-name> traffic refs
services[].image none Container image for enabled standalone services
services[].enabled false Whether Gordon creates, starts, and reconciles the service container
services[].env [] Inline KEY=value environment entries
services[].env_file "" Env file loaded before inline entries
services[].ports[].name none Port name used by traffic service refs
services[].ports[].container none Container port number
services[].ports[].protocol none tcp or udp
services[].ports[].publish "" Host-side bind address, usually loopback, that the traffic manager dials
services[].ports[].private false Require matching service and entrypoint trusted_cidrs for this port
services[].ports[].public false Explicit public opt-out for admin port names such as rcon
services[].ports[].trusted_cidrs [] CIDRs allowed for private port routing; must match the target entrypoint
services[].volumes[].source "" Explicit named volume or bind source; omitted service volumes use image VOLUME metadata
services[].volumes[].target none Absolute container mount path
services[].volumes[].read_only false Mount explicit volume read-only
services[].readiness.type "none" none, tcp, or log
services[].readiness.path "" Log readiness path inside the container
services[].readiness.contains "" Text required in the readiness log
services[].readiness.timeout default wait Positive readiness timeout when set
services[].cleanup.preserve_volumes true Preserve managed image-discovered volumes on cleanup
services[].cleanup.remove_container true Remove old, disabled, or removed service containers
backups.enabled false Backup service disabled
backups.schedule "daily" Backup scheduler preset
backups.storage_dir "" Uses {server.data_dir}/backups when empty
backups.retention.hourly 0 Keep no hourly backups by default
backups.retention.daily 0 Keep no daily backups by default (recommend 7)
backups.retention.weekly 0 Keep no weekly backups by default
backups.retention.monthly 0 Keep no monthly backups by default
images.allowed_registries [] Explicit external registry allowlist; empty rejects explicit external registries; dangerous local/private registries are always rejected
images.require_digest false Require digest-pinned references for allowlisted external registries
images.prune.enabled false Scheduled image cleanup disabled
images.prune.schedule "daily" Cleanup schedule preset
images.prune.keep_last 3 Number of recent tags kept per repository

Note: for all backups.retention.* keys, 0 means keep no backups for that retention tier.

Environment Variables

All configuration options can be set via environment variables using the pattern:

GORDON_<SECTION>_<KEY>=value

Examples:

GORDON_SERVER_PORT=8088
GORDON_SERVER_GORDON_DOMAIN=gordon.example.com
GORDON_AUTH_ENABLED=true
GORDON_LOGGING_LEVEL=debug
GORDON_NETWORK_ISOLATION_ENABLED=true

Nested keys use underscores:

GORDON_LOGGING_FILE_ENABLED=true
GORDON_LOGGING_FILE_MAX_SIZE=200
GORDON_LOGGING_CONTAINER_LOGS_ENABLED=false

Security Environment Variables

These special environment variables take priority over config file values:

Variable Description
GORDON_AUTH_TOKEN_SECRET JWT signing secret (avoids storing secret on disk)

Example:

export GORDON_AUTH_TOKEN_SECRET="your-secure-32-char-secret-here"
gordon serve

Pull Policy Options

Value Behavior
"always" Always pull image before deploying
"if-tag-changed" Pull only if image tag differs from running container
"never" Never pull, use local image only

Secrets Backend Options

Value Description
"pass" Unix password manager (recommended for production)
"sops" Mozilla SOPS encrypted files
"unsafe" Plain text files (development only)

Log Level Options

Value Description
"debug" Verbose debugging information
"info" General operational information
"warn" Warning conditions
"error" Error conditions only
source
1# Configuration Reference
2
3Complete configuration reference with all options and their default values.
4
5## Full Configuration Example
6
7```toml
8# =============================================================================
9# SERVER
10# =============================================================================
11[server]
12registry_port = 5000                         # Container registry port
13tls_cert_file = ""                           # PEM cert path (optional, for static TLS fallback)
14tls_key_file = ""                            # PEM key path (optional, must be set with tls_cert_file)
15force_https_redirect = false                 # Redirect all HTTP traffic to HTTPS (for direct-access setups)
16gordon_domain = ""                           # Required: Gordon domain (registry + API)
17data_dir = "~/.gordon"                       # Data directory (varies by install type)
18max_blob_chunk_size = "95MB"                 # Max size per registry blob upload chunk
19max_blob_size = "1GB"                        # Max cumulative size per registry blob/layer upload
20registry_allowed_ips = []                    # IPs or CIDR ranges allowed to access the registry (empty = allow all)
21proxy_allowed_ips = []                       # IPs or CIDR ranges allowed to reach HTTP proxy paths (empty = allow all, e.g. Cloudflare IPs)
22registry_listen_address = ""                 # Bind address for registry (empty = all interfaces, "127.0.0.1" = loopback only)
23
24# =============================================================================
25# ENTRYPOINTS
26# =============================================================================
27[entrypoints.edge]
28address = ":443"                             # Deployment-selected public TCP socket
29protocol = "smart_tcp"                       # Sniff HTTP, h2c, TLS, passthrough, or explicit raw fallback
30trusted_cidrs = []                            # Peer socket IP allowlist for all traffic on this entrypoint
31# raw_fallback = "ssh-fallback"              # Optional TCP router for unknown non-HTTP/non-TLS bytes
32# raw_fallback_trusted_cidrs = ["100.64.0.0/10"]
33# allow_public_raw_fallback = false
34
35# =============================================================================
36# DNS
37# =============================================================================
38[dns]
39resolvers = ["1.1.1.1:53", "8.8.8.8:53"] # Recursive resolvers for public DNS visibility checks
40propagation_timeout = "5m"                 # Max wait for DNS-01 TXT propagation
41polling_interval = "5s"                    # Interval between DNS-01 propagation checks
42
43# =============================================================================
44# AUTHENTICATION (required - Gordon won't start without credentials configured)
45# =============================================================================
46[auth]
47enabled = true                               # Enable registry authentication (default: true)
48secrets_backend = "unsafe"                   # "pass", "sops", or "unsafe"
49token_secret = ""                            # Path in secrets backend to JWT signing key (REQUIRED)
50token_expiry = "30d"                         # Token expiry duration
51access_token_ttl = "15m"                     # Ephemeral access token lifetime (default: 15m)
52
53# =============================================================================
54# PUBLIC TLS / ACME
55# =============================================================================
56[tls.acme]
57enabled = false                              # Enable public ACME certificates (requires HTTPS fallback on a TLS-capable entrypoint)
58email = ""                                   # ACME account email when enabled
59challenge = "auto"                           # "auto", "http-01", or "cloudflare-dns-01"
60obtain_batch_size = 1                         # New certificate orders per reconcile run
61
62# =============================================================================
63# API (applies to both Registry and Admin endpoints)
64# =============================================================================
65[api.rate_limit]
66enabled = true                               # Enable rate limiting (default: true)
67global_rps = 500                             # Max requests/second globally
68per_ip_rps = 50                              # Max requests/second per client IP
69burst = 100                                  # Burst size for rate limiters
70trusted_proxies = []                         # IPs/CIDRs trusted to set X-Forwarded-For
71
72# =============================================================================
73# LOGGING
74# =============================================================================
75[logging]
76level = "info"                               # "debug", "info", "warn", "error"
77format = "console"                           # "console" or "json"
78
79[logging.file]
80enabled = false                              # Enable file logging
81path = ""                                    # Log file path (default: {data_dir}/logs/gordon.log)
82max_size = 100                               # Max size in MB before rotation
83max_backups = 3                              # Number of old files to keep
84max_age = 28                                 # Days to keep old files
85
86[logging.container_logs]
87enabled = true                               # Enable container log collection
88dir = ""                                     # Log directory (default: {data_dir}/container-logs)
89max_size = 100                               # Max size in MB before rotation
90max_backups = 3                              # Number of old files to keep
91max_age = 28                                 # Days to keep old files
92
93[logging.access_log]
94enabled = false                              # Dedicated HTTP access log for reverse-proxy traffic
95format = "json"                             # "json", "clf", or "combined"
96output = "stdout"                           # "stdout", "file", or "journald"
97file_path = ""                               # Required when output = "file"
98max_size = 100                               # Max size in MB before rotation (file output)
99max_backups = 3                              # Number of old files to keep (file output)
100max_age = 28                                 # Days to keep old files (file output)
101exclude_health_checks = true                 # Skip noisy readiness/liveness requests
102syslog_identifier = "gordon-access"         # Journald identifier when output = "journald"
103
104# =============================================================================
105# TELEMETRY (OpenTelemetry)
106# =============================================================================
107[telemetry]
108enabled = false                              # Enable OTLP telemetry export
109endpoint = ""                                # OTLP HTTP endpoint URL
110auth_token = ""                              # Base64-encoded user:password for Basic auth
111traces = true                                # Export distributed traces
112metrics = true                               # Export metrics
113logs = true                                  # Bridge zerolog output to OTLP logs
114trace_sample_rate = 1.0                      # Fraction of traces to sample (0.0–1.0)
115
116# =============================================================================
117# ENVIRONMENT
118# =============================================================================
119[env]
120dir = ""                                     # Env files directory (default: {data_dir}/env)
121
122# =============================================================================
123# DEPLOYMENT
124# =============================================================================
125[deploy]
126pull_policy = "if-tag-changed"               # "always", "if-tag-changed", "never"
127readiness_mode = "auto"                      # "auto", "docker-health", "delay"
128health_timeout = "90s"                       # Max wait for health-based readiness
129readiness_delay = "5s"                       # Wait after running before considered ready
130drain_mode = "auto"                          # "auto", "inflight", "delay"
131drain_timeout = "30s"                        # Max wait for in-flight request drain
132drain_delay = "2s"                           # Wait after cache invalidation before old stop
133
134# =============================================================================
135# CONTAINERS
136# =============================================================================
137[containers]
138security_profile = "compat"                  # "compat" or "strict"
139
140# =============================================================================
141# AUTO-ROUTE
142# =============================================================================
143[auto_route]
144enabled = false                              # Create routes from image labels automatically
145
146# =============================================================================
147# NETWORK ISOLATION
148# =============================================================================
149[network_isolation]
150enabled = true                               # Enable per-app Docker networks
151network_prefix = "gordon"                    # Prefix for created networks
152internal = false                             # Create Docker internal networks (blocks direct egress)
153
154# =============================================================================
155# VOLUMES
156# =============================================================================
157[volumes]
158auto_create = true                           # Auto-create volumes from Dockerfile VOLUME
159prefix = "gordon"                            # Volume name prefix
160preserve = true                              # Keep volumes when containers are removed
161
162# =============================================================================
163# ROUTES
164# =============================================================================
165[routes]
166# "domain.com" = { image = "image:tag" }
167# "insecure.domain.com" = { image = "image:tag", https = false }
168# Legacy "http://domain.com" keys are read for compatibility and rewritten on save.
169
170# =============================================================================
171# EXTERNAL ROUTES
172# =============================================================================
173[external_routes]
174# "domain.com" = "host:port"                 # Proxy to non-container services
175
176# =============================================================================
177# STANDALONE SERVICES
178# =============================================================================
179# [[services]]
180# name = "rust"
181# image = "registry.example.com:5000/rust:latest"
182# enabled = true
183# env_file = "/srv/gordon/services/rust.env"
184#
185# [[services.ports]]
186# name = "game"
187# container = 28015
188# protocol = "udp"
189# publish = "127.0.0.1:38015"
190#
191# [[services.ports]]
192# name = "rcon"
193# container = 28016
194# protocol = "tcp"
195# publish = "127.0.0.1:38016"
196# trusted_cidrs = ["100.64.0.0/10"]
197
198# =============================================================================
199# NETWORK GROUPS
200# =============================================================================
201[network_groups]
202# "group-name" = ["domain1.com", "domain2.com"]
203
204# =============================================================================
205# ATTACHMENTS
206# =============================================================================
207[attachments]
208# "domain-or-group" = ["image1:tag", "image2:tag"]
209
210# =============================================================================
211# BACKUPS
212# =============================================================================
213[backups]
214enabled = false                              # Enable backup service
215schedule = "daily"                          # "hourly", "daily", "weekly", "monthly"
216storage_dir = ""                            # Backup root (default: {data_dir}/backups)
217
218[backups.retention]
219hourly = 0                                   # Keep N hourly backups per DB
220daily = 0                                    # Keep N daily backups per DB
221weekly = 0                                   # Keep N weekly backups per DB
222monthly = 0                                  # Keep N monthly backups per DB
223
224# =============================================================================
225# IMAGES
226# =============================================================================
227[images]
228allowed_registries = []
229require_digest = false
230
231[images.prune]
232enabled = false                              # Enable scheduled image cleanup
233schedule = "daily"                          # "hourly", "daily", "weekly", "monthly"
234keep_last = 3                                # Keep N newest tags per repository
235
236# Note: retention values set to 0 keep no backups for that tier.
237# For practical defaults, consider setting daily = 7.
238```
239
240## Default Values Summary
241
242| Setting | Default | Description |
243|---------|---------|-------------|
244| `server.registry_port` | `5000` | Container registry port |
245| `server.tls_cert_file` | `""` | PEM cert path for static TLS (optional) |
246| `server.tls_key_file` | `""` | PEM key path for static TLS (optional) |
247| `server.force_https_redirect` | `false` | Redirect all HTTP to HTTPS (for direct-access setups) |
248| `server.gordon_domain` | `""` | **Required** - Gordon domain |
249| `server.data_dir` | `~/.gordon` | Data directory |
250| `server.max_blob_chunk_size` | `"95MB"` | Max size per registry blob upload chunk |
251| `server.max_blob_size` | `"1GB"` | Max cumulative size per registry blob/layer upload |
252| `server.registry_allowed_ips` | `[]` | IPs or CIDR ranges allowed to access the registry (empty = allow all) |
253| `server.proxy_allowed_ips` | `[]` | IPs or CIDR ranges allowed to reach the proxy (empty = allow all) |
254| `server.registry_listen_address` | `""` | Bind address for registry (empty = all interfaces) |
255| `entrypoints.<name>.address` | none | Deployment-selected listen address; `edge` is conventional for route-capable entrypoints but is not required when exactly one `smart_tcp` or `tls_mux` entrypoint exists |
256| `entrypoints.<name>.protocol` | none | Entrypoint protocol: `smart_tcp`, `tls_mux`, `tcp`, or `udp` |
257| `entrypoints.<name>.trusted_cidrs` | `[]` | Peer socket IP allowlist for all traffic on the entrypoint |
258| `entrypoints.<name>.raw_fallback` | `""` | TCP router used by smart TCP for unknown non-HTTP/non-TLS bytes |
259| `entrypoints.<name>.raw_fallback_trusted_cidrs` | `[]` | Peer socket IP allowlist for smart TCP raw fallback |
260| `entrypoints.<name>.allow_public_raw_fallback` | `false` | Explicit acknowledgement for public raw fallback exposure |
261| `dns.resolvers` | `["1.1.1.1:53", "8.8.8.8:53"]` | Recursive resolvers used for public DNS visibility checks, including ACME DNS-01 propagation |
262| `dns.propagation_timeout` | `"5m"` | Maximum time to wait for DNS-01 TXT records to become visible through configured recursive resolvers |
263| `dns.polling_interval` | `"5s"` | Interval between DNS-01 propagation checks |
264| `tls.acme.enabled` | `false` | Enable public ACME certificates (requires HTTPS fallback on a TLS-capable entrypoint) |
265| `tls.acme.email` | `""` | ACME account email when enabled |
266| `tls.acme.challenge` | `"auto"` | ACME challenge mode: `auto`, `http-01`, or `cloudflare-dns-01` |
267| `tls.acme.obtain_batch_size` | `1` | Maximum new ACME certificate orders per reconcile run |
268| `auth.enabled` | `true` | Enable authentication; when `false`, run local-only mode (loopback-only `/v2/*`, `/admin/*` disabled) |
269| `auth.secrets_backend` | `"unsafe"` | Secrets storage |
270| `auth.token_expiry` | `"30d"` | 30 days |
271| `auth.access_token_ttl` | `"15m"` | Ephemeral access token lifetime |
272| `api.rate_limit.enabled` | `true` | Enable rate limiting |
273| `api.rate_limit.global_rps` | `500` | Global requests/second |
274| `api.rate_limit.per_ip_rps` | `50` | Per-IP requests/second |
275| `api.rate_limit.burst` | `100` | Burst size |
276| `api.rate_limit.trusted_proxies` | `[]` | IPs/CIDRs trusted for X-Forwarded-For |
277| `logging.level` | `"info"` | Log level |
278| `logging.format` | `"console"` | Log format |
279| `logging.file.enabled` | `false` | File logging disabled |
280| `logging.file.max_size` | `100` | 100 MB |
281| `logging.file.max_backups` | `3` | Keep 3 old files |
282| `logging.file.max_age` | `28` | 28 days |
283| `logging.container_logs.enabled` | `true` | Container logs enabled |
284| `logging.container_logs.max_size` | `100` | 100 MB |
285| `logging.container_logs.max_backups` | `3` | Keep 3 old files |
286| `logging.container_logs.max_age` | `28` | 28 days |
287| `logging.access_log.enabled` | `false` | Dedicated HTTP access log disabled |
288| `logging.access_log.format` | `"json"` | Access log format (`json`, `clf`, `combined`) |
289| `logging.access_log.output` | `"stdout"` | Access log sink (`stdout`, `file`, `journald`) |
290| `logging.access_log.max_size` | `100` | 100 MB for file output |
291| `logging.access_log.max_backups` | `3` | Keep 3 old files for file output |
292| `logging.access_log.max_age` | `28` | 28 days for file output |
293| `logging.access_log.exclude_health_checks` | `true` | Skip health-check requests |
294| `logging.access_log.syslog_identifier` | `"gordon-access"` | Journald identifier |
295| `telemetry.enabled` | `false` | Enable OTLP telemetry export |
296| `telemetry.endpoint` | `""` | OTLP HTTP endpoint URL |
297| `telemetry.auth_token` | `""` | Base64 `user:password` for Basic auth |
298| `telemetry.traces` | `true` | Export distributed traces |
299| `telemetry.metrics` | `true` | Export metrics |
300| `telemetry.logs` | `true` | Bridge zerolog to OTLP logs |
301| `telemetry.trace_sample_rate` | `1.0` | Fraction of traces to sample (0.0–1.0) |
302| `deploy.pull_policy` | `"if-tag-changed"` | Pull on tag change |
303| `deploy.readiness_mode` | `"auto"` | Readiness strategy (`auto`, `docker-health`, `delay`) |
304| `deploy.health_timeout` | `"90s"` | Max wait for health-based readiness before deploy fails |
305| `deploy.readiness_delay` | `"5s"` | Delay before container is considered ready |
306| `deploy.drain_mode` | `"auto"` | Drain strategy (`auto`, `inflight`, `delay`) |
307| `deploy.drain_timeout` | `"30s"` | Max wait for in-flight request drain before old stop |
308| `deploy.drain_delay` | `"2s"` | Delay before stopping previous container after cache invalidation |
309| `containers.security_profile` | `"compat"` | Runtime hardening profile: `compat` preserves existing behavior, `strict` enables read-only rootfs and narrower capabilities |
310| `auto_route.enabled` | `false` | Auto-route disabled |
311| `network_isolation.enabled` | `true` | Network isolation enabled |
312| `network_isolation.network_prefix` | `"gordon"` | Network prefix |
313| `network_isolation.internal` | `false` | Create Docker internal networks without direct external egress |
314| `volumes.auto_create` | `true` | Auto-create volumes |
315| `volumes.prefix` | `"gordon"` | Volume prefix |
316| `volumes.preserve` | `true` | Keep volumes |
317| `services[].name` | none | Standalone service name used by `service:<service>:<port-name>` traffic refs |
318| `services[].image` | none | Container image for enabled standalone services |
319| `services[].enabled` | `false` | Whether Gordon creates, starts, and reconciles the service container |
320| `services[].env` | `[]` | Inline `KEY=value` environment entries |
321| `services[].env_file` | `""` | Env file loaded before inline entries |
322| `services[].ports[].name` | none | Port name used by traffic service refs |
323| `services[].ports[].container` | none | Container port number |
324| `services[].ports[].protocol` | none | `tcp` or `udp` |
325| `services[].ports[].publish` | `""` | Host-side bind address, usually loopback, that the traffic manager dials |
326| `services[].ports[].private` | `false` | Require matching service and entrypoint `trusted_cidrs` for this port |
327| `services[].ports[].public` | `false` | Explicit public opt-out for admin port names such as `rcon` |
328| `services[].ports[].trusted_cidrs` | `[]` | CIDRs allowed for private port routing; must match the target entrypoint |
329| `services[].volumes[].source` | `""` | Explicit named volume or bind source; omitted service volumes use image `VOLUME` metadata |
330| `services[].volumes[].target` | none | Absolute container mount path |
331| `services[].volumes[].read_only` | `false` | Mount explicit volume read-only |
332| `services[].readiness.type` | `"none"` | `none`, `tcp`, or `log` |
333| `services[].readiness.path` | `""` | Log readiness path inside the container |
334| `services[].readiness.contains` | `""` | Text required in the readiness log |
335| `services[].readiness.timeout` | default wait | Positive readiness timeout when set |
336| `services[].cleanup.preserve_volumes` | `true` | Preserve managed image-discovered volumes on cleanup |
337| `services[].cleanup.remove_container` | `true` | Remove old, disabled, or removed service containers |
338| `backups.enabled` | `false` | Backup service disabled |
339| `backups.schedule` | `"daily"` | Backup scheduler preset |
340| `backups.storage_dir` | `""` | Uses `{server.data_dir}/backups` when empty |
341| `backups.retention.hourly` | `0` | Keep no hourly backups by default |
342| `backups.retention.daily` | `0` | Keep no daily backups by default (recommend `7`) |
343| `backups.retention.weekly` | `0` | Keep no weekly backups by default |
344| `backups.retention.monthly` | `0` | Keep no monthly backups by default |
345| `images.allowed_registries` | `[]` | Explicit external registry allowlist; empty rejects explicit external registries; dangerous local/private registries are always rejected |
346| `images.require_digest` | `false` | Require digest-pinned references for allowlisted external registries |
347| `images.prune.enabled` | `false` | Scheduled image cleanup disabled |
348| `images.prune.schedule` | `"daily"` | Cleanup schedule preset |
349| `images.prune.keep_last` | `3` | Number of recent tags kept per repository |
350
351Note: for all `backups.retention.*` keys, `0` means keep no backups for that retention tier.
352
353## Environment Variables
354
355All configuration options can be set via environment variables using the pattern:
356
357```
358GORDON_<SECTION>_<KEY>=value
359```
360
361Examples:
362```bash
363GORDON_SERVER_PORT=8088
364GORDON_SERVER_GORDON_DOMAIN=gordon.example.com
365GORDON_AUTH_ENABLED=true
366GORDON_LOGGING_LEVEL=debug
367GORDON_NETWORK_ISOLATION_ENABLED=true
368```
369
370Nested keys use underscores:
371```bash
372GORDON_LOGGING_FILE_ENABLED=true
373GORDON_LOGGING_FILE_MAX_SIZE=200
374GORDON_LOGGING_CONTAINER_LOGS_ENABLED=false
375```
376
377### Security Environment Variables
378
379These special environment variables take priority over config file values:
380
381| Variable | Description |
382|----------|-------------|
383| `GORDON_AUTH_TOKEN_SECRET` | JWT signing secret (avoids storing secret on disk) |
384
385Example:
386```bash
387export GORDON_AUTH_TOKEN_SECRET="your-secure-32-char-secret-here"
388gordon serve
389```
390
391## Pull Policy Options
392
393| Value | Behavior |
394|-------|----------|
395| `"always"` | Always pull image before deploying |
396| `"if-tag-changed"` | Pull only if image tag differs from running container |
397| `"never"` | Never pull, use local image only |
398
399## Secrets Backend Options
400
401| Value | Description |
402|-------|-------------|
403| `"pass"` | Unix password manager (recommended for production) |
404| `"sops"` | Mozilla SOPS encrypted files |
405| `"unsafe"` | Plain text files (development only) |
406
407## Log Level Options
408
409| Value | Description |
410|-------|-------------|
411| `"debug"` | Verbose debugging information |
412| `"info"` | General operational information |
413| `"warn"` | Warning conditions |
414| `"error"` | Error conditions only |
415
416## Related
417
418- [Configuration Overview](./index.md)
419- [Authentication](./auth.md)
420- [Telemetry](./telemetry.md)
421- [Network Isolation](./network-isolation.md)
422- [Volumes](./volumes.md)
423- [Standalone Services](./services.md)
424- [Images](./images.md)

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 7

Tags 106

↑↓ moveenter openesc close