main bac21c6

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)

[server.http]                                # Registry HTTP server timeouts (Go durations)
read_header_timeout = "10s"                  # Max time to read request headers
read_timeout = "5m"                          # Max time to read a whole request
write_timeout = "5m"                         # Max time to write a whole response
idle_timeout = "120s"                        # Keep-alive idle timeout

# =============================================================================
# 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

[traffic.http]                               # HTTP servers behind entrypoints (apps + admin API)
read_header_timeout = "5s"                   # Max time to read request headers
idle_timeout = "30s"                         # Keep-alive idle timeout
transfer_idle_timeout = "2m"                 # Cut a transfer only after this long without data (no fixed read/write timeout)

# =============================================================================
# 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

# Workload logs are streamed from the container runtime with
# `gordon apps logs APP --service SERVICE`. The accepted
# logging.container_logs fields are not connected to a production file sink.

[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                                  # Export Gordon, access, and app logs
trace_sample_rate = 1.0                      # Fraction of traces to sample (0.0–1.0)

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

# =============================================================================
# NETWORK ISOLATION
# =============================================================================
[network_isolation]
enabled = true                               # Installation network policy for Gordon-managed networks
network_prefix = "gordon"                    # Prefix filter for `gordon daemon 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

# =============================================================================
# ADMINISTRATIVE APP BIND MOUNTS
# =============================================================================
# A named policy is the only way an app manifest may reference a host path.
# App manifests declare [[services.<name>.bind]] with name = "<mount>"; direct host
# paths are always rejected, and the policy's allowlists are exact and
# non-empty. read_only on the policy and readonly on the bind both force
# read-only: either side wins and a bind never weakens its policy.
# [app_mounts.app-logs]
# source = "/srv/gordon/host-logs"           # Required; absolute, normalized
# read_only = true                           # Force read-only for this mount
# allowed_apps = ["metrics-agent"]           # Required; exact, non-empty
# allowed_services = ["web"]                 # Required; exact, non-empty
# root = "/srv/gordon"                       # Optional; default: parent of source

# =============================================================================
# ADMINISTRATIVE APP DEVICES (CDI)
# =============================================================================
# A named device grant is the only way an app manifest may request host
# devices. Manifests declare devices = ["<name>"]; raw /dev paths are
# always rejected, and the policy's allowlists are exact and non-empty.
# Aggregate "=all" CDI selectors are rejected: name every device
# explicitly. Device-bearing creates require Podman 5.4+ or Docker 28.3+
# with native CDI configured.
# [app_devices.transcode-gpu]
# cdi = ["example.com/gpu=GPU-device-uuid"]  # Required; explicit, non-empty
# allowed_apps = ["video"]                   # Required; exact, non-empty
# allowed_services = ["transcoder"]          # Required; exact, non-empty

# =============================================================================
# ADMINISTRATIVE APP CAPABILITIES
# =============================================================================
# A named capability grant is the only way an app manifest may add Linux
# capabilities. The manifest declares capabilities = ["<name>"] (a policy
# name, not a capability). Granted capabilities are added on top of Gordon's
# defaults; cap_drop = ALL, no-new-privileges, and non-privileged mode always
# remain. Allowed names (no CAP_ prefix): AUDIT_WRITE, CHOWN, DAC_OVERRIDE,
# FOWNER, FSETID, IPC_LOCK, KILL, MKNOD, NET_ADMIN, NET_BIND_SERVICE,
# NET_RAW, SETFCAP, SETGID, SETPCAP, SETUID, SYS_CHROOT, SYS_NICE,
# SYS_RESOURCE. ALL, SYS_ADMIN, SYS_PTRACE, SYS_MODULE and the rest are
# rejected. allowed_apps and allowed_services are exact and non-empty.
# [app_capabilities.vm-net]
# add = ["NET_ADMIN"]                        # Required; allowed set only
# allowed_apps = ["myapp"]             # Required; exact, non-empty
# allowed_services = ["worker"]              # Required; exact, non-empty

# REMOVED in v3: [routes], [attachments], [network_groups],
# app-like [[services]], [service_routes], [auto_route], [previews].
# Declare apps in standalone files (see ./apps.md). The standalone
# [[services]] table below stays valid for installation-level L4 workloads.

# =============================================================================
# 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"]

# =============================================================================
# BACKUPS
# =============================================================================
[backups.databases]
enabled = false                              # Enable PostgreSQL backups
schedule = "daily"                          # "hourly", "daily", "weekly", "monthly"
time = ""                                   # "HH:MM" server local time (empty: preset default)
storage_dir = ""                            # Backup root (default: {data_dir}/backups)

[backups.databases.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

[backups.volumes]
enabled = false                              # Enable S3 volume archives (see backups.md)
schedule = "daily"                          # "hourly", "daily", "weekly", "monthly"
time = ""                                   # "HH:MM" server local time (empty: preset default)
max_concurrency = 2                          # Volumes archived in parallel

# =============================================================================
# IMAGES
# =============================================================================
[images]
# Defaults: docker.io/registry-1.docker.io, ghcr.io, quay.io, Gordon registry.
# Add private or other registries as exact hostname+port entries.
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)
server.http.read_header_timeout "10s" Registry servers: max time to read request headers (env GORDON_SERVER_HTTP_READ_HEADER_TIMEOUT)
server.http.read_timeout "5m" Registry servers: max time to read a whole request (env GORDON_SERVER_HTTP_READ_TIMEOUT)
server.http.write_timeout "5m" Registry servers: max time to write a whole response (env GORDON_SERVER_HTTP_WRITE_TIMEOUT)
server.http.idle_timeout "120s" Registry servers: keep-alive idle timeout (env GORDON_SERVER_HTTP_IDLE_TIMEOUT)
traffic.http.read_header_timeout "5s" Entrypoint HTTP servers: max time to read request headers (env GORDON_TRAFFIC_HTTP_READ_HEADER_TIMEOUT)
traffic.http.idle_timeout "30s" Entrypoint HTTP servers: keep-alive idle timeout (env GORDON_TRAFFIC_HTTP_IDLE_TIMEOUT)
traffic.http.transfer_idle_timeout "2m" Entrypoint HTTP servers: inactivity timeout for request bodies and responses (env GORDON_TRAFFIC_HTTP_TRANSFER_IDLE_TIMEOUT)
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/*, TCP /admin/* not registered, owner-only admin socket for local gordon apps)
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.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 Export Gordon, proxy access, and app container logs to OTLP
telemetry.trace_sample_rate 1.0 Fraction of traces to sample (0.0–1.0)
containers.security_profile "compat" Runtime hardening profile: compat preserves existing behavior, strict enables read-only rootfs and narrower capabilities
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
app_mounts.<name>.source none Required host source of a named administrative bind; absolute and normalized. The only host path that mount may come from
app_mounts.<name>.allowed_apps none Required exact, non-empty app allowlist for this mount (no wildcard or empty-means-all form)
app_mounts.<name>.allowed_services none Required exact, non-empty service allowlist for this mount
app_mounts.<name>.read_only false Force every bind resolved under this policy read-only; a manifest bind can never weaken it
app_mounts.<name>.root parent of source Optional administrative boundary the resolved source must stay under
app_devices.<name>.cdi none Required explicit, non-empty CDI device IDs granted under this logical name (no =all aggregate form)
app_devices.<name>.allowed_apps none Required exact, non-empty app allowlist for this grant (no wildcard or empty-means-all form)
app_devices.<name>.allowed_services none Required exact, non-empty service allowlist for this grant
app_capabilities.<name>.add none Required explicit, non-empty Linux capability names (no CAP_ prefix) added on top of Gordon's defaults. Only the documented safe set is accepted; ALL and SYS_ADMIN are rejected
app_capabilities.<name>.allowed_apps none Required exact, non-empty app allowlist for this grant
app_capabilities.<name>.allowed_services none Required exact, non-empty service allowlist for this grant
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.databases.enabled false PostgreSQL backups disabled
backups.databases.schedule "daily" hourly, daily, weekly, or monthly
backups.databases.time "" HH:MM server local time; empty uses the preset default
backups.databases.storage_dir "" Uses {server.data_dir}/backups when empty
backups.databases.retention.hourly 0 Keep no hourly backups by default
backups.databases.retention.daily 0 Keep no daily backups by default (recommend 7)
backups.databases.retention.weekly 0 Keep no weekly backups by default
backups.databases.retention.monthly 0 Keep no monthly backups by default
backups.volumes.enabled false S3 volume archives disabled
backups.volumes.schedule "daily" hourly, daily, weekly, or monthly
backups.volumes.time "" HH:MM server local time; empty uses the preset default
backups.volumes.max_concurrency 2 Volumes archived in parallel
backups.volumes.retention.keep 14 Archives kept per app + volume
images.allowed_registries [] Additional exact hostname+port entries. Defaults allow Docker Hub (docker.io and registry-1.docker.io), ghcr.io, quay.io, and Gordon's registry. This allowlist does not configure registry credentials and is not DNS/IP or runtime egress enforcement.
images.require_digest false Require valid SHA-256 digest-pinned references for every registry, including Gordon
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.databases.retention.* keys, 0 means keep no backups for that retention tier. The top-level backups.enabled, backups.schedule, backups.storage_dir, and backups.retention.* keys are aliases of the backups.databases.* keys.

Every volume backup key, including compression, the helper image, and the backups.volumes.s3.* settings, is listed in Backups.

App Manifest HTTP Interfaces

[[services.<name>.http]] declares HTTP interfaces in a standalone app manifest (see App Manifest).

Key Values Default Description
services.<name>.http[].visibility "public", "internal" "public" public is proxied by host and may terminate TLS; internal is reachable only from the app's private network
services.<name>.http[].host hostname none Required for public interfaces; must be absent for visibility = "internal"
services.<name>.http[].port integer none Required container port for every interface
services.<name>.http[].tls "auto", "always", "never" "auto" Public interfaces only; visibility = "internal" rejects any declared value

visibility = "internal" creates no proxy route, host reservation, certificate target, or host port publication. A container port declared by both an internal HTTP interface and an externally backed interface (public HTTP or TCP) is rejected, as are duplicate internal HTTP ports.

Environment Variables

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

GORDON_<SECTION>_<KEY>=value

Examples:

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[server.http]                                # Registry HTTP server timeouts (Go durations)
25read_header_timeout = "10s"                  # Max time to read request headers
26read_timeout = "5m"                          # Max time to read a whole request
27write_timeout = "5m"                         # Max time to write a whole response
28idle_timeout = "120s"                        # Keep-alive idle timeout
29
30# =============================================================================
31# ENTRYPOINTS
32# =============================================================================
33[entrypoints.edge]
34address = ":443"                             # Deployment-selected public TCP socket
35protocol = "smart_tcp"                       # Sniff HTTP, h2c, TLS, passthrough, or explicit raw fallback
36trusted_cidrs = []                            # Peer socket IP allowlist for all traffic on this entrypoint
37# raw_fallback = "ssh-fallback"              # Optional TCP router for unknown non-HTTP/non-TLS bytes
38# raw_fallback_trusted_cidrs = ["100.64.0.0/10"]
39# allow_public_raw_fallback = false
40
41[traffic.http]                               # HTTP servers behind entrypoints (apps + admin API)
42read_header_timeout = "5s"                   # Max time to read request headers
43idle_timeout = "30s"                         # Keep-alive idle timeout
44transfer_idle_timeout = "2m"                 # Cut a transfer only after this long without data (no fixed read/write timeout)
45
46# =============================================================================
47# DNS
48# =============================================================================
49[dns]
50resolvers = ["1.1.1.1:53", "8.8.8.8:53"] # Recursive resolvers for public DNS visibility checks
51propagation_timeout = "5m"                 # Max wait for DNS-01 TXT propagation
52polling_interval = "5s"                    # Interval between DNS-01 propagation checks
53
54# =============================================================================
55# AUTHENTICATION (required - Gordon won't start without credentials configured)
56# =============================================================================
57[auth]
58enabled = true                               # Enable registry authentication (default: true)
59secrets_backend = "unsafe"                   # "pass", "sops", or "unsafe"
60token_secret = ""                            # Path in secrets backend to JWT signing key (REQUIRED)
61token_expiry = "30d"                         # Token expiry duration
62access_token_ttl = "15m"                     # Ephemeral access token lifetime (default: 15m)
63
64# =============================================================================
65# PUBLIC TLS / ACME
66# =============================================================================
67[tls.acme]
68enabled = false                              # Enable public ACME certificates (requires HTTPS fallback on a TLS-capable entrypoint)
69email = ""                                   # ACME account email when enabled
70challenge = "auto"                           # "auto", "http-01", or "cloudflare-dns-01"
71obtain_batch_size = 1                         # New certificate orders per reconcile run
72
73# =============================================================================
74# API (applies to both Registry and Admin endpoints)
75# =============================================================================
76[api.rate_limit]
77enabled = true                               # Enable rate limiting (default: true)
78global_rps = 500                             # Max requests/second globally
79per_ip_rps = 50                              # Max requests/second per client IP
80burst = 100                                  # Burst size for rate limiters
81trusted_proxies = []                         # IPs/CIDRs trusted to set X-Forwarded-For
82
83# =============================================================================
84# LOGGING
85# =============================================================================
86[logging]
87level = "info"                               # "debug", "info", "warn", "error"
88format = "console"                           # "console" or "json"
89
90[logging.file]
91enabled = false                              # Enable file logging
92path = ""                                    # Log file path (default: {data_dir}/logs/gordon.log)
93max_size = 100                               # Max size in MB before rotation
94max_backups = 3                              # Number of old files to keep
95max_age = 28                                 # Days to keep old files
96
97# Workload logs are streamed from the container runtime with
98# `gordon apps logs APP --service SERVICE`. The accepted
99# logging.container_logs fields are not connected to a production file sink.
100
101[logging.access_log]
102enabled = false                              # Dedicated HTTP access log for reverse-proxy traffic
103format = "json"                             # "json", "clf", or "combined"
104output = "stdout"                           # "stdout", "file", or "journald"
105file_path = ""                               # Required when output = "file"
106max_size = 100                               # Max size in MB before rotation (file output)
107max_backups = 3                              # Number of old files to keep (file output)
108max_age = 28                                 # Days to keep old files (file output)
109exclude_health_checks = true                 # Skip noisy readiness/liveness requests
110syslog_identifier = "gordon-access"         # Journald identifier when output = "journald"
111
112# =============================================================================
113# TELEMETRY (OpenTelemetry)
114# =============================================================================
115[telemetry]
116enabled = false                              # Enable OTLP telemetry export
117endpoint = ""                                # OTLP HTTP endpoint URL
118auth_token = ""                              # Base64-encoded user:password for Basic auth
119traces = true                                # Export distributed traces
120metrics = true                               # Export metrics
121logs = true                                  # Export Gordon, access, and app logs
122trace_sample_rate = 1.0                      # Fraction of traces to sample (0.0–1.0)
123
124# =============================================================================
125# CONTAINERS
126# =============================================================================
127[containers]
128security_profile = "compat"                  # "compat" or "strict"
129
130# =============================================================================
131# NETWORK ISOLATION
132# =============================================================================
133[network_isolation]
134enabled = true                               # Installation network policy for Gordon-managed networks
135network_prefix = "gordon"                    # Prefix filter for `gordon daemon networks`
136internal = false                             # Create Docker internal networks (blocks direct egress)
137
138# =============================================================================
139# VOLUMES
140# =============================================================================
141[volumes]
142auto_create = true                           # Auto-create volumes from Dockerfile VOLUME
143prefix = "gordon"                            # Volume name prefix
144preserve = true                              # Keep volumes when containers are removed
145
146# =============================================================================
147# ADMINISTRATIVE APP BIND MOUNTS
148# =============================================================================
149# A named policy is the only way an app manifest may reference a host path.
150# App manifests declare [[services.<name>.bind]] with name = "<mount>"; direct host
151# paths are always rejected, and the policy's allowlists are exact and
152# non-empty. read_only on the policy and readonly on the bind both force
153# read-only: either side wins and a bind never weakens its policy.
154# [app_mounts.app-logs]
155# source = "/srv/gordon/host-logs"           # Required; absolute, normalized
156# read_only = true                           # Force read-only for this mount
157# allowed_apps = ["metrics-agent"]           # Required; exact, non-empty
158# allowed_services = ["web"]                 # Required; exact, non-empty
159# root = "/srv/gordon"                       # Optional; default: parent of source
160
161# =============================================================================
162# ADMINISTRATIVE APP DEVICES (CDI)
163# =============================================================================
164# A named device grant is the only way an app manifest may request host
165# devices. Manifests declare devices = ["<name>"]; raw /dev paths are
166# always rejected, and the policy's allowlists are exact and non-empty.
167# Aggregate "=all" CDI selectors are rejected: name every device
168# explicitly. Device-bearing creates require Podman 5.4+ or Docker 28.3+
169# with native CDI configured.
170# [app_devices.transcode-gpu]
171# cdi = ["example.com/gpu=GPU-device-uuid"]  # Required; explicit, non-empty
172# allowed_apps = ["video"]                   # Required; exact, non-empty
173# allowed_services = ["transcoder"]          # Required; exact, non-empty
174
175# =============================================================================
176# ADMINISTRATIVE APP CAPABILITIES
177# =============================================================================
178# A named capability grant is the only way an app manifest may add Linux
179# capabilities. The manifest declares capabilities = ["<name>"] (a policy
180# name, not a capability). Granted capabilities are added on top of Gordon's
181# defaults; cap_drop = ALL, no-new-privileges, and non-privileged mode always
182# remain. Allowed names (no CAP_ prefix): AUDIT_WRITE, CHOWN, DAC_OVERRIDE,
183# FOWNER, FSETID, IPC_LOCK, KILL, MKNOD, NET_ADMIN, NET_BIND_SERVICE,
184# NET_RAW, SETFCAP, SETGID, SETPCAP, SETUID, SYS_CHROOT, SYS_NICE,
185# SYS_RESOURCE. ALL, SYS_ADMIN, SYS_PTRACE, SYS_MODULE and the rest are
186# rejected. allowed_apps and allowed_services are exact and non-empty.
187# [app_capabilities.vm-net]
188# add = ["NET_ADMIN"]                        # Required; allowed set only
189# allowed_apps = ["myapp"]             # Required; exact, non-empty
190# allowed_services = ["worker"]              # Required; exact, non-empty
191
192# REMOVED in v3: [routes], [attachments], [network_groups],
193# app-like [[services]], [service_routes], [auto_route], [previews].
194# Declare apps in standalone files (see ./apps.md). The standalone
195# [[services]] table below stays valid for installation-level L4 workloads.
196
197# =============================================================================
198# EXTERNAL ROUTES
199# =============================================================================
200[external_routes]
201# "domain.com" = "host:port"                 # Proxy to non-container services
202
203# =============================================================================
204# STANDALONE SERVICES
205# =============================================================================
206# [[services]]
207# name = "rust"
208# image = "registry.example.com:5000/rust:latest"
209# enabled = true
210# env_file = "/srv/gordon/services/rust.env"
211#
212# [[services.ports]]
213# name = "game"
214# container = 28015
215# protocol = "udp"
216# publish = "127.0.0.1:38015"
217#
218# [[services.ports]]
219# name = "rcon"
220# container = 28016
221# protocol = "tcp"
222# publish = "127.0.0.1:38016"
223# trusted_cidrs = ["100.64.0.0/10"]
224
225# =============================================================================
226# BACKUPS
227# =============================================================================
228[backups.databases]
229enabled = false                              # Enable PostgreSQL backups
230schedule = "daily"                          # "hourly", "daily", "weekly", "monthly"
231time = ""                                   # "HH:MM" server local time (empty: preset default)
232storage_dir = ""                            # Backup root (default: {data_dir}/backups)
233
234[backups.databases.retention]
235hourly = 0                                   # Keep N hourly backups per DB
236daily = 0                                    # Keep N daily backups per DB
237weekly = 0                                   # Keep N weekly backups per DB
238monthly = 0                                  # Keep N monthly backups per DB
239
240[backups.volumes]
241enabled = false                              # Enable S3 volume archives (see backups.md)
242schedule = "daily"                          # "hourly", "daily", "weekly", "monthly"
243time = ""                                   # "HH:MM" server local time (empty: preset default)
244max_concurrency = 2                          # Volumes archived in parallel
245
246# =============================================================================
247# IMAGES
248# =============================================================================
249[images]
250# Defaults: docker.io/registry-1.docker.io, ghcr.io, quay.io, Gordon registry.
251# Add private or other registries as exact hostname+port entries.
252allowed_registries = []
253require_digest = false
254
255[images.prune]
256enabled = false                              # Enable scheduled image cleanup
257schedule = "daily"                          # "hourly", "daily", "weekly", "monthly"
258keep_last = 3                                # Keep N newest tags per repository
259
260# Note: retention values set to 0 keep no backups for that tier.
261# For practical defaults, consider setting daily = 7.
262```
263
264## Default Values Summary
265
266| Setting | Default | Description |
267|---------|---------|-------------|
268| `server.registry_port` | `5000` | Container registry port |
269| `server.tls_cert_file` | `""` | PEM cert path for static TLS (optional) |
270| `server.tls_key_file` | `""` | PEM key path for static TLS (optional) |
271| `server.force_https_redirect` | `false` | Redirect all HTTP to HTTPS (for direct-access setups) |
272| `server.gordon_domain` | `""` | **Required** - Gordon domain |
273| `server.data_dir` | `~/.gordon` | Data directory |
274| `server.max_blob_chunk_size` | `"95MB"` | Max size per registry blob upload chunk |
275| `server.max_blob_size` | `"1GB"` | Max cumulative size per registry blob/layer upload |
276| `server.registry_allowed_ips` | `[]` | IPs or CIDR ranges allowed to access the registry (empty = allow all) |
277| `server.proxy_allowed_ips` | `[]` | IPs or CIDR ranges allowed to reach the proxy (empty = allow all) |
278| `server.registry_listen_address` | `""` | Bind address for registry (empty = all interfaces) |
279| `server.http.read_header_timeout` | `"10s"` | Registry servers: max time to read request headers (env `GORDON_SERVER_HTTP_READ_HEADER_TIMEOUT`) |
280| `server.http.read_timeout` | `"5m"` | Registry servers: max time to read a whole request (env `GORDON_SERVER_HTTP_READ_TIMEOUT`) |
281| `server.http.write_timeout` | `"5m"` | Registry servers: max time to write a whole response (env `GORDON_SERVER_HTTP_WRITE_TIMEOUT`) |
282| `server.http.idle_timeout` | `"120s"` | Registry servers: keep-alive idle timeout (env `GORDON_SERVER_HTTP_IDLE_TIMEOUT`) |
283| `traffic.http.read_header_timeout` | `"5s"` | Entrypoint HTTP servers: max time to read request headers (env `GORDON_TRAFFIC_HTTP_READ_HEADER_TIMEOUT`) |
284| `traffic.http.idle_timeout` | `"30s"` | Entrypoint HTTP servers: keep-alive idle timeout (env `GORDON_TRAFFIC_HTTP_IDLE_TIMEOUT`) |
285| `traffic.http.transfer_idle_timeout` | `"2m"` | Entrypoint HTTP servers: inactivity timeout for request bodies and responses (env `GORDON_TRAFFIC_HTTP_TRANSFER_IDLE_TIMEOUT`) |
286| `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 |
287| `entrypoints.<name>.protocol` | none | Entrypoint protocol: `smart_tcp`, `tls_mux`, `tcp`, or `udp` |
288| `entrypoints.<name>.trusted_cidrs` | `[]` | Peer socket IP allowlist for all traffic on the entrypoint |
289| `entrypoints.<name>.raw_fallback` | `""` | TCP router used by smart TCP for unknown non-HTTP/non-TLS bytes |
290| `entrypoints.<name>.raw_fallback_trusted_cidrs` | `[]` | Peer socket IP allowlist for smart TCP raw fallback |
291| `entrypoints.<name>.allow_public_raw_fallback` | `false` | Explicit acknowledgement for public raw fallback exposure |
292| `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 |
293| `dns.propagation_timeout` | `"5m"` | Maximum time to wait for DNS-01 TXT records to become visible through configured recursive resolvers |
294| `dns.polling_interval` | `"5s"` | Interval between DNS-01 propagation checks |
295| `tls.acme.enabled` | `false` | Enable public ACME certificates (requires HTTPS fallback on a TLS-capable entrypoint) |
296| `tls.acme.email` | `""` | ACME account email when enabled |
297| `tls.acme.challenge` | `"auto"` | ACME challenge mode: `auto`, `http-01`, or `cloudflare-dns-01` |
298| `tls.acme.obtain_batch_size` | `1` | Maximum new ACME certificate orders per reconcile run |
299| `auth.enabled` | `true` | Enable authentication; when `false`, run local-only mode (loopback-only `/v2/*`, TCP `/admin/*` not registered, owner-only admin socket for local `gordon apps`) |
300| `auth.secrets_backend` | `"unsafe"` | Secrets storage |
301| `auth.token_expiry` | `"30d"` | 30 days |
302| `auth.access_token_ttl` | `"15m"` | Ephemeral access token lifetime |
303| `api.rate_limit.enabled` | `true` | Enable rate limiting |
304| `api.rate_limit.global_rps` | `500` | Global requests/second |
305| `api.rate_limit.per_ip_rps` | `50` | Per-IP requests/second |
306| `api.rate_limit.burst` | `100` | Burst size |
307| `api.rate_limit.trusted_proxies` | `[]` | IPs/CIDRs trusted for X-Forwarded-For |
308| `logging.level` | `"info"` | Log level |
309| `logging.format` | `"console"` | Log format |
310| `logging.file.enabled` | `false` | File logging disabled |
311| `logging.file.max_size` | `100` | 100 MB |
312| `logging.file.max_backups` | `3` | Keep 3 old files |
313| `logging.file.max_age` | `28` | 28 days |
314| `logging.access_log.enabled` | `false` | Dedicated HTTP access log disabled |
315| `logging.access_log.format` | `"json"` | Access log format (`json`, `clf`, `combined`) |
316| `logging.access_log.output` | `"stdout"` | Access log sink (`stdout`, `file`, `journald`) |
317| `logging.access_log.max_size` | `100` | 100 MB for file output |
318| `logging.access_log.max_backups` | `3` | Keep 3 old files for file output |
319| `logging.access_log.max_age` | `28` | 28 days for file output |
320| `logging.access_log.exclude_health_checks` | `true` | Skip health-check requests |
321| `logging.access_log.syslog_identifier` | `"gordon-access"` | Journald identifier |
322| `telemetry.enabled` | `false` | Enable OTLP telemetry export |
323| `telemetry.endpoint` | `""` | OTLP HTTP endpoint URL |
324| `telemetry.auth_token` | `""` | Base64 `user:password` for Basic auth |
325| `telemetry.traces` | `true` | Export distributed traces |
326| `telemetry.metrics` | `true` | Export metrics |
327| `telemetry.logs` | `true` | Export Gordon, proxy access, and app container logs to OTLP |
328| `telemetry.trace_sample_rate` | `1.0` | Fraction of traces to sample (0.0–1.0) |
329| `containers.security_profile` | `"compat"` | Runtime hardening profile: `compat` preserves existing behavior, `strict` enables read-only rootfs and narrower capabilities |
330| `network_isolation.enabled` | `true` | Network isolation enabled |
331| `network_isolation.network_prefix` | `"gordon"` | Network prefix |
332| `network_isolation.internal` | `false` | Create Docker internal networks without direct external egress |
333| `volumes.auto_create` | `true` | Auto-create volumes |
334| `volumes.prefix` | `"gordon"` | Volume prefix |
335| `volumes.preserve` | `true` | Keep volumes |
336| `app_mounts.<name>.source` | none | Required host source of a named administrative bind; absolute and normalized. The only host path that mount may come from |
337| `app_mounts.<name>.allowed_apps` | none | Required exact, non-empty app allowlist for this mount (no wildcard or empty-means-all form) |
338| `app_mounts.<name>.allowed_services` | none | Required exact, non-empty service allowlist for this mount |
339| `app_mounts.<name>.read_only` | `false` | Force every bind resolved under this policy read-only; a manifest bind can never weaken it |
340| `app_mounts.<name>.root` | parent of `source` | Optional administrative boundary the resolved source must stay under |
341| `app_devices.<name>.cdi` | none | Required explicit, non-empty CDI device IDs granted under this logical name (no `=all` aggregate form) |
342| `app_devices.<name>.allowed_apps` | none | Required exact, non-empty app allowlist for this grant (no wildcard or empty-means-all form) |
343| `app_devices.<name>.allowed_services` | none | Required exact, non-empty service allowlist for this grant |
344| `app_capabilities.<name>.add` | none | Required explicit, non-empty Linux capability names (no `CAP_` prefix) added on top of Gordon's defaults. Only the documented safe set is accepted; `ALL` and `SYS_ADMIN` are rejected |
345| `app_capabilities.<name>.allowed_apps` | none | Required exact, non-empty app allowlist for this grant |
346| `app_capabilities.<name>.allowed_services` | none | Required exact, non-empty service allowlist for this grant |
347| `services[].name` | none | Standalone service name used by `service:<service>:<port-name>` traffic refs |
348| `services[].image` | none | Container image for enabled standalone services |
349| `services[].enabled` | `false` | Whether Gordon creates, starts, and reconciles the service container |
350| `services[].env` | `[]` | Inline `KEY=value` environment entries |
351| `services[].env_file` | `""` | Env file loaded before inline entries |
352| `services[].ports[].name` | none | Port name used by traffic service refs |
353| `services[].ports[].container` | none | Container port number |
354| `services[].ports[].protocol` | none | `tcp` or `udp` |
355| `services[].ports[].publish` | `""` | Host-side bind address, usually loopback, that the traffic manager dials |
356| `services[].ports[].private` | `false` | Require matching service and entrypoint `trusted_cidrs` for this port |
357| `services[].ports[].public` | `false` | Explicit public opt-out for admin port names such as `rcon` |
358| `services[].ports[].trusted_cidrs` | `[]` | CIDRs allowed for private port routing; must match the target entrypoint |
359| `services[].volumes[].source` | `""` | Explicit named volume or bind source; omitted service volumes use image `VOLUME` metadata |
360| `services[].volumes[].target` | none | Absolute container mount path |
361| `services[].volumes[].read_only` | `false` | Mount explicit volume read-only |
362| `services[].readiness.type` | `"none"` | `none`, `tcp`, or `log` |
363| `services[].readiness.path` | `""` | Log readiness path inside the container |
364| `services[].readiness.contains` | `""` | Text required in the readiness log |
365| `services[].readiness.timeout` | default wait | Positive readiness timeout when set |
366| `services[].cleanup.preserve_volumes` | `true` | Preserve managed image-discovered volumes on cleanup |
367| `services[].cleanup.remove_container` | `true` | Remove old, disabled, or removed service containers |
368| `backups.databases.enabled` | `false` | PostgreSQL backups disabled |
369| `backups.databases.schedule` | `"daily"` | `hourly`, `daily`, `weekly`, or `monthly` |
370| `backups.databases.time` | `""` | `HH:MM` server local time; empty uses the preset default |
371| `backups.databases.storage_dir` | `""` | Uses `{server.data_dir}/backups` when empty |
372| `backups.databases.retention.hourly` | `0` | Keep no hourly backups by default |
373| `backups.databases.retention.daily` | `0` | Keep no daily backups by default (recommend `7`) |
374| `backups.databases.retention.weekly` | `0` | Keep no weekly backups by default |
375| `backups.databases.retention.monthly` | `0` | Keep no monthly backups by default |
376| `backups.volumes.enabled` | `false` | S3 volume archives disabled |
377| `backups.volumes.schedule` | `"daily"` | `hourly`, `daily`, `weekly`, or `monthly` |
378| `backups.volumes.time` | `""` | `HH:MM` server local time; empty uses the preset default |
379| `backups.volumes.max_concurrency` | `2` | Volumes archived in parallel |
380| `backups.volumes.retention.keep` | `14` | Archives kept per app + volume |
381| `images.allowed_registries` | `[]` | Additional exact hostname+port entries. Defaults allow Docker Hub (`docker.io` and `registry-1.docker.io`), `ghcr.io`, `quay.io`, and Gordon's registry. This allowlist does not configure registry credentials and is not DNS/IP or runtime egress enforcement. |
382| `images.require_digest` | `false` | Require valid SHA-256 digest-pinned references for every registry, including Gordon |
383| `images.prune.enabled` | `false` | Scheduled image cleanup disabled |
384| `images.prune.schedule` | `"daily"` | Cleanup schedule preset |
385| `images.prune.keep_last` | `3` | Number of recent tags kept per repository |
386
387Note: for all `backups.databases.retention.*` keys, `0` means keep no backups for that retention tier. The top-level `backups.enabled`, `backups.schedule`, `backups.storage_dir`, and `backups.retention.*` keys are aliases of the `backups.databases.*` keys.
388
389Every volume backup key, including compression, the helper image, and the `backups.volumes.s3.*` settings, is listed in [Backups](./backups.md).
390
391## App Manifest HTTP Interfaces
392
393`[[services.<name>.http]]` declares HTTP interfaces in a standalone app manifest (see [App Manifest](./apps.md)).
394
395| Key | Values | Default | Description |
396|-----|--------|---------|-------------|
397| `services.<name>.http[].visibility` | `"public"`, `"internal"` | `"public"` | `public` is proxied by host and may terminate TLS; `internal` is reachable only from the app's private network |
398| `services.<name>.http[].host` | hostname | none | Required for public interfaces; must be absent for `visibility = "internal"` |
399| `services.<name>.http[].port` | integer | none | Required container port for every interface |
400| `services.<name>.http[].tls` | `"auto"`, `"always"`, `"never"` | `"auto"` | Public interfaces only; `visibility = "internal"` rejects any declared value |
401
402`visibility = "internal"` creates no proxy route, host reservation, certificate target, or host port publication. A container port declared by both an internal HTTP interface and an externally backed interface (public HTTP or TCP) is rejected, as are duplicate internal HTTP ports.
403
404## Environment Variables
405
406All configuration options can be set via environment variables using the pattern:
407
408```
409GORDON_<SECTION>_<KEY>=value
410```
411
412Examples:
413```bash
414GORDON_SERVER_GORDON_DOMAIN=gordon.example.com
415GORDON_AUTH_ENABLED=true
416GORDON_LOGGING_LEVEL=debug
417GORDON_NETWORK_ISOLATION_ENABLED=true
418```
419
420Nested keys use underscores:
421```bash
422GORDON_LOGGING_FILE_ENABLED=true
423GORDON_LOGGING_FILE_MAX_SIZE=200
424GORDON_LOGGING_CONTAINER_LOGS_ENABLED=false
425```
426
427### Security Environment Variables
428
429These special environment variables take priority over config file values:
430
431| Variable | Description |
432|----------|-------------|
433| `GORDON_AUTH_TOKEN_SECRET` | JWT signing secret (avoids storing secret on disk) |
434
435Example:
436```bash
437export GORDON_AUTH_TOKEN_SECRET="your-secure-32-char-secret-here"
438gordon serve
439```
440
441## Pull Policy Options
442
443| Value | Behavior |
444|-------|----------|
445| `"always"` | Always pull image before deploying |
446| `"if-tag-changed"` | Pull only if image tag differs from running container |
447| `"never"` | Never pull, use local image only |
448
449## Secrets Backend Options
450
451| Value | Description |
452|-------|-------------|
453| `"pass"` | Unix password manager (recommended for production) |
454| `"sops"` | Mozilla SOPS encrypted files |
455| `"unsafe"` | Plain text files (development only) |
456
457## Log Level Options
458
459| Value | Description |
460|-------|-------------|
461| `"debug"` | Verbose debugging information |
462| `"info"` | General operational information |
463| `"warn"` | Warning conditions |
464| `"error"` | Error conditions only |
465
466## Related
467
468- [Configuration Overview](./index.md)
469- [Authentication](./auth.md)
470- [Telemetry](./telemetry.md)
471- [Network Isolation](./network-isolation.md)
472- [Volumes](./volumes.md)
473- [App Manifest](./apps.md)
474- [Standalone Services](./services.md)
475- [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