Files
compose-farm/docs/configuration.md
Bas Nijholt 1e3b1d71ed Drop CF_LOCAL_HOST; limit web-stack inference to containers (#163)
* config: Add local_host and web_stack options

Allow configuring local_host and web_stack in compose-farm.yaml instead
of requiring environment variables. This makes it easier to deploy the
web UI with just a config file mount.

- local_host: specifies which host is "local" for Glances connectivity
- web_stack: identifies the web UI stack for self-update detection

Environment variables (CF_LOCAL_HOST, CF_WEB_STACK) still work as
fallback for backwards compatibility.

Closes #152

* docs: Clarify glances_stack is used by CLI and web UI

* config: Env vars override config, add docs

- Change precedence: environment variables now override config values
  (follows 12-factor app pattern)
- Document all CF_* environment variables in configuration.md
- Update example-config.yaml to mention env var overrides

* config: Consolidate env vars, prefer config options

- Update docker-compose.yml to comment out CF_WEB_STACK and CF_LOCAL_HOST
  (now prefer setting in compose-farm.yaml)
- Update init-env to comment out CF_LOCAL_HOST (can be set in config)
- Update docker-deployment.md with new "Config option" column
- Simplify troubleshooting to prefer config over env vars

* config: Generate CF_LOCAL_HOST with config alternative note

Instead of commenting out CF_LOCAL_HOST, generate it normally but add
a note in the comment that it can also be set as 'local_host' in config.

* config: Extend local_host to all web UI operations

When running the web UI in a Docker container, is_local() can't detect
which host the container is on due to different network namespaces.

Previously local_host/CF_LOCAL_HOST only affected Glances connectivity.
Now it also affects:
- Container exec/shell (runs locally instead of via SSH)
- File editing (uses local filesystem instead of SSH)

Added is_local_host() helper that checks CF_LOCAL_HOST/config.local_host
first, then falls back to is_local() detection.

* refactor: DRY get_web_stack helper, add tests

- Move get_web_stack to deps.py to avoid duplication in streaming.py
  and actions.py
- Add tests for config.local_host and config.web_stack parsing
- Add tests for is_local_host, get_web_stack, and get_local_host helpers
- Tests verify env var precedence over config values

* glances: rely on CF_WEB_STACK for container mode

Restore docker-compose env defaults and document local_host scope.

* web: ignore local_host outside container

Document container-only behavior and adjust tests.

* web: infer local host from web_stack

Drop local_host config option and update docs/tests.

* Remove CF_LOCAL_HOST override

* refactor: move web_stack helpers to Config class

- Add get_web_stack() and get_local_host_from_web_stack() as Config methods
- Remove duplicate _get_local_host_from_web_stack() from glances.py and deps.py
- Update deps.py get_web_stack() to delegate to Config method
- Add comprehensive tests for the new Config methods

* config: remove web_stack config option

The web_stack config option was redundant since:
- In Docker, CF_WEB_STACK env var is always set
- Outside Docker, the container-specific behavior is disabled anyway

Simplify by only using the CF_WEB_STACK environment variable.

* refactor: remove get_web_stack wrapper from deps

Callers now use config.get_web_stack() directly instead of
going through a pointless wrapper function.

* prompts: add rule to identify pointless wrapper functions
2026-01-10 10:48:35 +01:00

8.1 KiB

icon
icon
lucide/settings

Configuration Reference

Compose Farm uses a YAML configuration file to define hosts and stack assignments.

Config File Location

Compose Farm looks for configuration in this order:

  1. -c / --config flag (if provided)
  2. CF_CONFIG environment variable
  3. ./compose-farm.yaml (current directory)
  4. $XDG_CONFIG_HOME/compose-farm/compose-farm.yaml (defaults to ~/.config)

Use -c / --config to specify a custom path:

cf ps -c /path/to/config.yaml

Or set the environment variable:

export CF_CONFIG=/path/to/config.yaml

Examples

Single host (local-only)

# Required: directory containing compose files
compose_dir: /opt/stacks

# Define local host
hosts:
  local: localhost

# Map stacks to the local host
stacks:
  plex: local
  grafana: local
  nextcloud: local

Multi-host (full example)

# Required: directory containing compose files (same path on all hosts)
compose_dir: /opt/compose

# Optional: auto-regenerate Traefik config
traefik_file: /opt/traefik/dynamic.d/compose-farm.yml
traefik_stack: traefik

# Define Docker hosts
hosts:
  nuc:
    address: 192.168.1.10
    user: docker
  hp:
    address: 192.168.1.11
    user: admin

# Map stacks to hosts
stacks:
  # Single-host stacks
  plex: nuc
  grafana: nuc
  nextcloud: hp

  # Multi-host stacks
  dozzle: all                    # Run on ALL hosts
  node-exporter: [nuc, hp]       # Run on specific hosts

Settings Reference

compose_dir (required)

Directory containing your compose stack folders. Must be the same path on all hosts.

compose_dir: /opt/compose

Directory structure:

/opt/compose/
├── plex/
│   ├── docker-compose.yml    # or compose.yaml
│   └── .env                  # optional environment file
├── grafana/
│   └── docker-compose.yml
└── ...

Supported compose file names (checked in order):

  • compose.yaml
  • compose.yml
  • docker-compose.yml
  • docker-compose.yaml

traefik_file

Path to auto-generated Traefik file-provider config. When set, Compose Farm regenerates this file after up, down, and update commands.

traefik_file: /opt/traefik/dynamic.d/compose-farm.yml

traefik_stack

Stack name running Traefik. Stacks on the same host are skipped in file-provider config (Traefik's docker provider handles them).

traefik_stack: traefik

glances_stack

Stack name running Glances for host resource monitoring. When set, the CLI (cf stats --containers) and web UI display CPU, memory, and container stats for all hosts.

glances_stack: glances

The Glances stack should run on all hosts and expose port 61208. See the README for full setup instructions.

Hosts Configuration

Basic Host

hosts:
  myserver:
    address: 192.168.1.10

With SSH User

hosts:
  myserver:
    address: 192.168.1.10
    user: docker

If user is omitted, the current user is used.

With Custom SSH Port

hosts:
  myserver:
    address: 192.168.1.10
    user: docker
    port: 2222  # SSH port (default: 22)

Localhost

For stacks running on the same machine where you invoke Compose Farm:

hosts:
  local: localhost

No SSH is used for localhost stacks.

Multiple Hosts

hosts:
  nuc:
    address: 192.168.1.10
    user: docker
  hp:
    address: 192.168.1.11
    user: admin
  truenas:
    address: 192.168.1.100
  local: localhost

Stacks Configuration

Single-Host Stack

stacks:
  plex: nuc
  grafana: nuc
  nextcloud: hp

Multi-Host Stack

For stacks that need to run on every host (e.g., log shippers, monitoring agents):

stacks:
  # Run on ALL configured hosts
  dozzle: all
  promtail: all

  # Run on specific hosts
  node-exporter: [nuc, hp, truenas]

Common multi-host stacks:

  • Dozzle - Docker log viewer (needs local socket)
  • Promtail/Alloy - Log shipping (needs local socket)
  • node-exporter - Host metrics (needs /proc, /sys)
  • AutoKuma - Uptime Kuma monitors (needs local socket)

Stack Names

Stack names must match directory names in compose_dir:

compose_dir: /opt/compose
stacks:
  plex: nuc      # expects /opt/compose/plex/docker-compose.yml
  my-app: hp     # expects /opt/compose/my-app/docker-compose.yml

State File

Compose Farm tracks deployment state in compose-farm-state.yaml, stored alongside the config file.

For example, if your config is at ~/.config/compose-farm/compose-farm.yaml, the state file will be at ~/.config/compose-farm/compose-farm-state.yaml.

deployed:
  plex: nuc
  grafana: nuc

This file records which stacks are deployed and on which host.

Don't edit manually. Use cf refresh to sync state with reality.

Environment Variables

In Compose Files

Your compose files can use .env files as usual:

/opt/compose/plex/
├── docker-compose.yml
└── .env

Compose Farm runs docker compose which handles .env automatically.

In Traefik Labels

When generating Traefik config, Compose Farm resolves ${VAR} and ${VAR:-default} from:

  1. The stack's .env file
  2. Current environment

Compose Farm Environment Variables

These environment variables configure Compose Farm itself:

Variable Description
CF_CONFIG Path to config file
CF_WEB_STACK Web UI stack name (Docker only, enables self-update detection and local host inference)

Docker deployment variables (used in docker-compose.yml):

Variable Description Generated by
CF_COMPOSE_DIR Compose files directory cf config init-env
CF_UID / CF_GID User/group ID for containers cf config init-env
CF_HOME / CF_USER Home directory and username cf config init-env
CF_SSH_DIR SSH keys volume mount Manual
CF_XDG_CONFIG Config backup volume mount Manual

Config Commands

Initialize Config

cf config init

Creates a new config file with documented examples.

Validate Config

cf config validate

Checks syntax and schema.

Show Config

cf config show

Displays current config with syntax highlighting.

Edit Config

cf config edit

Opens config in $EDITOR.

Show Config Path

cf config path

Prints the config file location (useful for scripting).

cf config symlink                          # Link to ./compose-farm.yaml
cf config symlink /path/to/my-config.yaml  # Link to specific file

Creates a symlink from the default location (~/.config/compose-farm/compose-farm.yaml) to your config file. Use --force to overwrite an existing symlink.

Validation

Local Validation

Fast validation without SSH:

cf check --local

Checks:

  • Config syntax
  • Stack-to-host mappings
  • Compose file existence

Full Validation

cf check

Additional SSH-based checks:

  • Host connectivity
  • Mount point existence
  • Docker network existence
  • Traefik label validation

Stack-Specific Check

cf check jellyfin

Shows which hosts can run the stack (have required mounts/networks).

Example Configurations

Minimal

compose_dir: /opt/compose

hosts:
  server: 192.168.1.10

stacks:
  myapp: server

Home Lab

compose_dir: /opt/compose

hosts:
  nuc:
    address: 192.168.1.10
    user: docker
  nas:
    address: 192.168.1.100
    user: admin

stacks:
  # Media
  plex: nuc
  jellyfin: nuc
  immich: nuc

  # Infrastructure
  traefik: nuc
  portainer: nuc

  # Monitoring (on all hosts)
  dozzle: all

Production

compose_dir: /opt/compose
traefik_file: /opt/traefik/dynamic.d/cf.yml
traefik_stack: traefik

hosts:
  web-1:
    address: 10.0.1.10
    user: deploy
  web-2:
    address: 10.0.1.11
    user: deploy
  db:
    address: 10.0.1.20
    user: deploy

stacks:
  # Load balanced
  api: [web-1, web-2]

  # Single instance
  postgres: db
  redis: db

  # Infrastructure
  traefik: web-1

  # Monitoring
  promtail: all