Configuration Reference

June 3, 2026 ยท View on GitHub

GARM is configured via a single TOML file, typically at /etc/garm/config.toml. This reference covers every section.

Minimal configuration

[default]
enable_webhook_management = true

[logging]
enable_log_streamer = true
log_format = "text"
log_level = "info"
log_source = false

[metrics]
enable = true
disable_auth = false

[jwt_auth]
secret = "<random-string-32-chars-or-more>"
time_to_live = "8760h"

[apiserver]
  bind = "0.0.0.0"
  port = 9997
  use_tls = false
  [apiserver.webui]
    enable = true

[database]
  backend = "sqlite3"
  passphrase = "<random-32-char-string>"
  [database.sqlite3]
    db_file = "/etc/garm/garm.db"

[default]

OptionDefaultDescription
enable_webhook_managementfalseAllow GARM to install/manage webhooks automatically
debug_serverfalseEnable the Go pprof profiling server on 127.0.0.1:9997

When debug_server is enabled, you can profile GARM using:

go tool pprof http://127.0.0.1:9997/debug/pprof/profile?seconds=120

Important

The profiling command will block for the duration of the profile (e.g. 120 seconds). Most reverse proxies timeout after ~60 seconds, so always profile by connecting directly to GARM on localhost. It's advisable to exclude the debug server URLs from your reverse proxy entirely. Deprecated: callback_url, metadata_url, log_file, enable_log_streamer -- these are now managed via garm-cli controller update or the [logging] section.

[logging]

OptionDefaultDescription
log_file(stdout)Path to log file. Omit to log to stdout.
enable_log_streamerfalseEnable live log streaming via WebSocket (garm-cli debug-log)
log_format"text""text" or "json". Use JSON for log aggregation (Loki, ELK).
log_level"info""debug", "info", "warn", or "error"
log_sourcefalseInclude source file/line in log output

Log rotation: GARM auto-rotates at 500 MB or 28 days, whichever comes first. Send SIGHUP to manually rotate. If running under systemd, add the following to your unit file:

[Service]
ExecReload=/bin/kill -HUP $MAINPID

Then rotate with systemctl reload garm.

[database]

OptionDefaultDescription
debugfalseLog all database queries
backend"sqlite3"Database backend: "sqlite3" or "postgresql"
passphrase(required)32-character string used to encrypt secrets at rest (AES-256). Protects webhook secrets, tokens, and private keys stored in the database.

[database.sqlite3]

OptionDefaultDescription
db_file(required)Path to the SQLite database file

[database.postgresql]

OptionDefaultDescription
username(required)PostgreSQL user
password(required)PostgreSQL password
hostname(required)Host or IP of the PostgreSQL server
port5432Port the server listens on
database(required)Database name
sslmode"prefer"SSL mode: disable, allow, prefer, require, verify-ca, or verify-full
max_open_conns25Maximum number of open connections in the pool
max_idle_conns5Maximum number of idle connections in the pool
conn_max_lifetime_mins30Maximum connection lifetime in minutes
conn_max_idle_time_secs300Maximum time a connection may sit idle before being closed, in seconds
[database]
  backend    = "postgresql"
  passphrase = "<random-32-char-string>"
  [database.postgresql]
    username = "garm"
    password = "<password>"
    hostname = "localhost"
    port     = 5432
    database = "garm"
    sslmode  = "prefer"

Reclaiming storage from deleted file objects

File object content can be large. Both backends reclaim the underlying storage automatically, but the mechanics differ.

SQLite. Blob content is stored in a separate database file (auto-vacuum is enabled in the connection string). GARM runs PRAGMA incremental_vacuum against both the main and objects databases every 24 hours, so freed pages are returned to the filesystem without operator intervention.

PostgreSQL. Blob content is stored in PostgreSQL Large Objects (pg_largeobject). When a file object is deleted, GARM calls lo_unlink inline in the same transaction, and PostgreSQL's autovacuum reclaims the underlying storage.

If lo_unlink fails during deletion (for example because of a transient connection error), GARM logs the orphaned OID at error level. To recover such orphans, run the vacuumlo utility (shipped with PostgreSQL):

vacuumlo -U garm -W garm

[[provider]]

Providers are external executables that GARM calls to create and manage runner instances. You can define multiple providers.

[[provider]]
  name = "lxd_local"
  provider_type = "external"
  description = "Local LXD installation"
  [provider.external]
    provider_executable = "/opt/garm/providers.d/garm-provider-lxd"
    config_file = "/etc/garm/garm-provider-lxd.toml"
    environment_variables = ["AWS_"]
OptionDescription
nameUnique name for this provider
provider_typeAlways "external"
descriptionHuman-readable description
provider_executableAbsolute path to the provider binary
config_filePath to the provider's own config file
environment_variablesList of env var names or prefixes to pass to the provider (e.g., ["AWS_"] passes all AWS_* vars)

[metrics]

OptionDefaultDescription
enablefalseEnable the /metrics Prometheus endpoint
disable_authfalseDisable JWT authentication on the metrics endpoint
period"60s"How often internal metrics are recalculated

To generate a metrics token for Prometheus:

garm-cli metrics-token create

See Monitoring and Debugging for Prometheus configuration.

[jwt_auth]

OptionDefaultDescription
secret(required)Secret used to sign JWT tokens. Use a long, random string.
time_to_live"24h"How long admin tokens are valid. Minimum 24h.

This TTL applies only to tokens you get when logging into the API (and metrics tokens). Tokens issued to runner instances have a TTL based on the pool's bootstrap timeout plus the GARM polling interval -- they are not affected by this setting.

Changing the secret invalidates all existing tokens.

[apiserver]

OptionDefaultDescription
bind"0.0.0.0"IP address to bind to
port9997Port to listen on
use_tlsfalseEnable TLS on the API server
cors_origins[]Allowed CORS origins. ["*"] allows all.

[apiserver.tls]

OptionDescription
certificatePath to x509 certificate (or full chain bundle)
keyPath to the private key

Important

If your certificate is signed by an intermediary CA, the certificate file must contain the entire chain (your certificate concatenated with the CA bundle). Without the full chain, clients may fail to validate the connection.

While GARM supports TLS natively, using a reverse proxy (e.g. nginx) for TLS termination is recommended for most production setups.

[apiserver.webui]

OptionDefaultDescription
enabletrueEnable the Web UI at /ui/

Available providers

ProviderRepository
Akamai/Linodeflatcar/garm-provider-linode (experimental)
Amazon EC2cloudbase/garm-provider-aws
Azurecloudbase/garm-provider-azure
CloudStacknexthop-ai/garm-provider-cloudstack
GCPcloudbase/garm-provider-gcp
Incuscloudbase/garm-provider-incus
Kubernetesmercedes-benz/garm-provider-k8s
LXDcloudbase/garm-provider-lxd
OpenStackcloudbase/garm-provider-openstack
Oracle OCIcloudbase/garm-provider-oci

Each provider has its own configuration file and documentation. Refer to the provider's repository for setup instructions and available extra_specs options.