Skip to content

Getting Started

This guide walks you through installing Compose Farm and setting up your first multi-host deployment.

Prerequisites

Before you begin, ensure you have:

  • uv (recommended) or Python 3.11+
  • SSH key-based authentication to your Docker hosts
  • Docker and Docker Compose installed on all target hosts
  • Shared storage for compose files (NFS, Syncthing, etc.)

Installation

curl -fsSL https://raw.githubusercontent.com/basnijholt/compose-farm/main/bootstrap.sh | sh

This installs uv if needed, then installs compose-farm.

Using uv

If you already have uv installed:

uv tool install compose-farm

Using pip

If you already have Python 3.11+ installed:

pip install compose-farm

Using Docker

docker run --rm \
  -v $SSH_AUTH_SOCK:/ssh-agent -e SSH_AUTH_SOCK=/ssh-agent \
  -v ./compose-farm.yaml:/root/.config/compose-farm/compose-farm.yaml:ro \
  ghcr.io/basnijholt/compose-farm up --all

Verify Installation

cf --version
cf --help

SSH Setup

Compose Farm uses SSH to run commands on remote hosts. You need passwordless SSH access.

Option 1: SSH Agent (default)

If you already have SSH keys loaded in your agent:

# Verify keys are loaded
ssh-add -l

# Test connection
ssh user@192.168.1.10 "docker --version"

For persistent access when running in Docker:

# Generate and distribute key to all hosts
cf ssh setup

# Check status
cf ssh status

This creates ~/.ssh/compose-farm/id_ed25519 and copies the public key to each host.

Shared Storage Setup

Compose files must be accessible at the same path on all hosts. Common approaches:

NFS Mount

# On each Docker host
sudo mount nas:/volume1/compose /opt/compose

# Or add to /etc/fstab
nas:/volume1/compose /opt/compose nfs defaults 0 0

Directory Structure

/opt/compose/           # compose_dir in config
├── plex/
│   └── docker-compose.yml
├── sonarr/
│   └── docker-compose.yml
├── radarr/
│   └── docker-compose.yml
└── jellyfin/
    └── docker-compose.yml

Configuration

Create Config File

Create ~/.config/compose-farm/compose-farm.yaml:

Single host example

# Where compose files are located (one folder per stack)
compose_dir: /opt/stacks

hosts:
  local: localhost

stacks:
  plex: local
  sonarr: local
  radarr: local

Multi-host example

# Where compose files are located (same path on all hosts)
compose_dir: /opt/compose

# Define your Docker hosts
hosts:
  nuc:
    address: 192.168.1.10
    user: docker           # SSH user
  hp:
    address: 192.168.1.11
    # user defaults to current user

# Map stacks to hosts
stacks:
  plex: nuc
  sonarr: nuc
  radarr: hp

Each entry in stacks: maps to a folder under compose_dir that contains a compose file.

For cross-host HTTP routing, add Traefik labels and configure traefik_file (see Traefik Integration).

Validate Configuration

cf check --local

This validates syntax without SSH connections. For full validation:

cf check

First Commands

Check Status

cf ps

Shows all configured stacks and their status.

Start All Stacks

cf up --all

Starts all stacks on their assigned hosts.

Start Specific Stacks

cf up plex sonarr

Apply Configuration

The most powerful command - reconciles reality with your config:

cf apply --dry-run   # Preview changes
cf apply             # Execute changes

This will: 1. Start stacks in config but not running 2. Migrate stacks on wrong host 3. Stop stacks removed from config

Docker Network Setup

If your stacks use an external Docker network:

# Create network on all hosts
cf init-network

# Or specific hosts
cf init-network nuc hp

Default network: mynetwork with subnet 172.20.0.0/16

Example Workflow

1. Add a New Stack

Create the compose file:

# On any host (shared storage)
mkdir -p /opt/compose/prowlarr
cat > /opt/compose/prowlarr/docker-compose.yml << 'EOF'
services:
  prowlarr:
    image: lscr.io/linuxserver/prowlarr:latest
    container_name: prowlarr
    environment:
      - PUID=1000
      - PGID=1000
    volumes:
      - /opt/config/prowlarr:/config
    ports:
      - "9696:9696"
    restart: unless-stopped
EOF

Add to config:

stacks:
  # ... existing stacks
  prowlarr: nuc

Start the stack:

cf up prowlarr

2. Move a Stack to Another Host

Edit compose-farm.yaml:

stacks:
  plex: hp  # Changed from nuc

Apply the change:

cf up plex
# Automatically: down on nuc, up on hp

Or use apply to reconcile everything:

cf apply

3. Update All Stacks

cf update --all
# Runs: pull + build + down + up for each stack

Next Steps