Skip to content

Configuration

This page covers installation-level configuration: controller config, agent config, web environment variables, and age key setup.

Service definitions live in composia-meta.yaml. See Service Guide for that file.

Config file shape

The controller and agent use the same YAML file format. A file may contain either section or both:

controller:
  # controller settings

agent:
  # agent settings

At least one of controller or agent must be present.

When the same config file contains both sections, the local agent is treated as the built-in node:

  • agent.node_id must be main.
  • controller.nodes must include an entry with id: main.
  • controller.repo_dir and agent.repo_dir must not be the same path.

Full config template

This template shows every supported installation-level key. It is a shape reference, not a copy-paste default. Remove sections you do not use, remove empty list items, and use either inline values or _file values for each secret-like field.

config.yaml
controller:
  listen_addr: ":7001"
  repo_dir: "/data/repo-controller"
  state_dir: "/data/state-controller"
  log_dir: "/data/logs"

  access_tokens:
    - name: "web"
      token: "REPLACE_WITH_WEB_ACCESS_TOKEN"
      token_file: ""
      enabled: true
      comment: "Web UI access token"

  nodes:
    - id: "main"
      display_name: "Main"
      enabled: true
      public_ipv4: ""
      public_ipv6: ""
      token: "REPLACE_WITH_MAIN_AGENT_TOKEN"
      token_file: ""

  git:
    remote_url: ""
    branch: "main"
    pull_interval: ""
    author_name: "Composia"
    author_email: "composia@example.com"
    auth:
      username: ""
      token: ""
      token_file: ""

  backup:
    default_schedule: ""

  updates:
    default_check_schedule: ""
    auto_apply: false
    backup_before_update: true
    digest_pin: false
    semver:
      default_allow:
        - patch
        - minor
    forge_auth:
      github:
        url: "https://github.com"
        token: ""
        token_file: ""
        api_url: "https://api.github.com"
      gitlab:
        url: "https://gitlab.com"
        token: ""
        token_file: ""
        api_url: "https://gitlab.com/api/v4"
      forgejo:
        url: "https://forgejo.example.com"
        token: ""
        token_file: ""
        api_url: ""

  auto_deploy:
    infra: false
    services: false

  dns:
    cloudflare:
      api_token: ""
      api_token_file: ""
      zones: []
    alidns:
      access_key_id: ""
      access_key_id_file: ""
      access_key_secret: ""
      access_key_secret_file: ""
      security_token: ""
      security_token_file: ""
      region_id: ""
      zones: []
    dnspod:
      secret_id: ""
      secret_id_file: ""
      secret_key: ""
      secret_key_file: ""
      session_token: ""
      session_token_file: ""
      region: ""
      zones: []
    route53:
      access_key_id: ""
      access_key_id_file: ""
      secret_access_key: ""
      secret_access_key_file: ""
      session_token: ""
      session_token_file: ""
      region: ""
      profile: ""
      hosted_zone_id: ""
      zones: []
    huaweicloud:
      access_key_id: ""
      access_key_id_file: ""
      secret_access_key: ""
      secret_access_key_file: ""
      region_id: ""
      zones: []

  rustic:
    main_nodes:
      - "main"
    maintenance:
      forget_schedule: ""
      prune_schedule: ""

  secrets:
    provider: age
    identity_file: "/app/configs/age-identity.key"
    recipient_file: ""
    armor: true

  notifications:
    alertmanager:
      enabled: true
      listen_path: "/api/v1/alerts"
    smtp:
      enabled: false
      host: ""
      port: 587
      encryption: starttls
      username: ""
      password: ""
      password_file: ""
      from: ""
      to: []
      on: []
      task_sources: []
    telegram:
      enabled: false
      bot_token: ""
      bot_token_file: ""
      chat_id: ""
      on: []
      task_sources: []

agent:
  controller_addr: "http://controller:7001"
  controller_grpc: false
  controller_headers:
    - name: ""
      value: ""
      value_file: ""
  node_id: "main"
  token: "REPLACE_WITH_MAIN_AGENT_TOKEN"
  token_file: ""
  repo_dir: "/data/repo-agent"
  state_dir: "/data/state-agent"
  caddy:
    generated_dir: ""

Do not keep empty list items such as controller_headers with an empty name. They are shown only to document the supported object shape.

The web access token and main agent token must be different.

Age key setup

controller.secrets is optional. Configure it only if you use Composia-managed encrypted secrets.

When controller.secrets is configured, identity_file is required. recipient_file is optional. If it is omitted, Composia derives the recipient from the private key.

Generate a private key:

age-keygen -o age-identity.key

Optional recipient file:

age-keygen -y age-identity.key > age-recipients.txt

Use the private key in config:

secrets:
  provider: age
  identity_file: "/app/configs/age-identity.key"

Or use both files:

secrets:
  provider: age
  identity_file: "/app/configs/age-identity.key"
  recipient_file: "/app/configs/age-recipients.txt"

armor is optional and defaults to true.

Controller config reference

Required keys

KeyTypeDescription
listen_addrstringController listen address, for example ":7001" or "127.0.0.1:7001".
repo_dirstringDesired-state Git repository path.
state_dirstringController state path.
log_dirstringTask log directory.
nodes[]objectConfigured agent nodes. The key must be present, even if empty.

Optional top-level keys

KeyTypeDescription
access_tokens[]objectAPI tokens for web UI, CLI, and external clients.
backupobjectGlobal backup defaults.
gitobjectDesired-state repository remote sync.
notificationsobjectAlertmanager, SMTP, and Telegram notifications.
dnsobjectDNS provider credentials.
rusticobjectRustic maintenance settings.
secretsobjectAge encryption settings.
updatesobjectImage update defaults and forge API auth.
auto_deployobjectGlobal auto-deploy toggles.

nodes[]

KeyTypeRequiredDescription
idstringYesUnique node ID.
display_namestringNoName shown in UI.
enabledboolNoDisable a node without removing it.
public_ipv4stringNoPublic IPv4 used by DNS workflows.
public_ipv6stringNoPublic IPv6 used by DNS workflows.
tokenstringYes*Agent auth token.
token_filestringNoRead the token from a file.

*Use either token or token_file, not both.

access_tokens[]

KeyTypeRequiredDescription
namestringYesToken name.
tokenstringYes*Token value.
token_filestringNoRead the token from a file.
enabledboolNoDisable a token without removing it.
commentstringNoAdministrative note.

Access tokens must not duplicate node tokens or other access tokens.

git

KeyTypeRequiredDescription
remote_urlstringNoGit remote URL.
branchstringNoBranch to sync.
pull_intervalstringCond.Required when remote_url is set.
author_namestringNoCommit author name for controller writes.
author_emailstringNoCommit author email.
auth.usernamestringNoGit username.
auth.tokenstringNoGit token.
auth.token_filestringNoRead Git token from a file.

secrets

This whole section is optional. If the section is present, these rules apply:

KeyTypeRequiredDescription
providerstringYesMust be age.
identity_filestringYesAge private key path.
recipient_filestringNoAge recipient file path. If omitted, recipient is derived from identity_file.
armorboolNoASCII armor encrypted output. Defaults to true.

backup

KeyTypeDescription
default_schedulestringDefault cron schedule for service backups.

updates

KeyTypeDescription
default_check_schedulestringDefault cron schedule for image update checks.
auto_applyboolApply updates automatically by default.
backup_before_updateboolBack up data before applying updates.
digest_pinboolPin images by digest.
semver.default_allow[]stringAllowed semver bump levels: patch, minor, major.
forge_auth.githubobject or []objectGitHub API auth.
forge_auth.gitlabobject or []objectGitLab API auth.
forge_auth.forgejoobject or []objectForgejo API auth.

Each forge auth entry supports:

KeyTypeDescription
urlstringForge base URL.
tokenstringAPI token.
token_filestringRead API token from a file.
api_urlstringAPI URL override.

auto_deploy

KeyTypeDescription
infraboolAuto-deploy infrastructure services after Git changes.
servicesboolAuto-deploy regular services after Git changes.

dns

Provider keyCredential keysCommon keys
cloudflareapi_token, api_token_filezones
alidnsaccess_key_id, access_key_id_file, access_key_secret, access_key_secret_file, security_token, security_token_file, region_idzones
dnspodsecret_id, secret_id_file, secret_key, secret_key_file, session_token, session_token_file, regionzones
route53access_key_id, access_key_id_file, secret_access_key, secret_access_key_file, session_token, session_token_file, region, profile, hosted_zone_idzones
huaweicloudaccess_key_id, access_key_id_file, secret_access_key, secret_access_key_file, region_idzones

rustic

KeyTypeDescription
main_nodes[]stringNode IDs that run Rustic operations. Each must reference controller.nodes.
maintenance.forget_schedulestringCron schedule for rustic forget.
maintenance.prune_schedulestringCron schedule for rustic prune.

notifications.alertmanager

KeyTypeDescription
enabledboolEnabled by default when section exists.
listen_pathstringWebhook path. Defaults to /api/v1/alerts. Must start with /.

notifications.smtp

KeyTypeRequired when enabledDescription
enabledboolNoEnabled by default when section exists.
hoststringYesSMTP host.
portintYesSMTP port, 1 to 65535.
encryptionstringNonone, starttls, or ssl_tls. Defaults to starttls.
usernamestringNoSMTP username.
passwordstringNoSMTP password.
password_filestringNoRead password from a file.
fromstringYesSender address.
to[]stringYesRecipient list.
on[]stringNoNotification event filters.
task_sources[]stringNoTask source filters: web, cli, others, schedule, system, auto_deploy.

notifications.telegram

KeyTypeRequired when enabledDescription
enabledboolNoEnabled by default when section exists.
bot_tokenstringYes*Telegram bot token.
bot_token_filestringNoRead bot token from a file.
chat_idstringYesTarget chat ID.
on[]stringNoNotification event filters.
task_sources[]stringNoTask source filters.

Agent config reference

KeyTypeRequiredDescription
controller_addrstringYesController URL reachable from the agent.
controller_grpcboolNoUse gRPC instead of Connect over HTTP.
controller_headers[]objectNoExtra HTTP headers sent to the controller.
node_idstringYesThis agent’s node ID. Must match controller.nodes[].id.
tokenstringYes*Node token matching the controller config.
token_filestringNoRead node token from a file.
repo_dirstringYesAgent service repository path.
state_dirstringYesAgent state directory.
caddyobjectNoAgent-side Caddy settings.

*Use either token or token_file, not both.

controller_headers[]

KeyTypeRequiredDescription
namestringYesHTTP header name. Header names are deduplicated case-insensitively.
valuestringYes*Header value.
value_filestringNoRead header value from a file.

caddy

KeyTypeDescription
generated_dirstringGenerated Caddy config directory. Defaults to <state_dir>/caddy/generated.

Web environment variables

The web server reads environment variables. In Docker Compose these are set through .env.

VariableRequiredDescription
WEB_CONTROLLER_ADDRYesController address from the web server process. In Docker Compose: http://controller:7001.
WEB_BROWSER_CONTROLLER_ADDRYesController address from the browser.
WEB_CONTROLLER_ACCESS_TOKENYesController access token. Must match controller.access_tokens[].token.
WEB_CONTROLLER_HEADERSNoJSON object of extra headers sent by the web server when calling the controller.
WEB_LOGIN_USERNAMEYesWeb login username.
WEB_LOGIN_PASSWORD_HASHYesArgon2 password hash.
WEB_SESSION_SECRETYesRandom session signing secret.
ORIGINDeployment-dependentPublic origin of the web server.
HOSTNoHost bind address.
PORTNoWeb server port.

Inline values and _file values

Many secret-like fields support both inline values and file references. Examples:

  • token / token_file
  • password / password_file
  • api_token / api_token_file
  • value / value_file

Use one form only. If both are set, startup fails.

Last updated on • Renovate Bot