Getting Started¶
Deploy ComposeFlux and manage Docker Compose stacks via GitOps.
Prerequisites¶
- Docker with Compose v2+
- Git repository with Compose stacks
- Secrets management: local Age encrypted files (
*.age) or a remote provider (Bitwarden / Infisical) - SSH key for Git access (store in secrets manager or mount as volume)
Environment Variables¶
Required¶
| Variable | Description |
|---|---|
GIT_REPO_URL |
Git repository SSH URL (e.g., git@github.com:user/repo.git) |
STACK_PATH |
Path to stacks directory in repo (relative to repo root) |
Optional - Local Age Encrypted Secrets¶
| Variable | Description | Default |
|---|---|---|
AGE_PASSPHRASE |
Passphrase used to decrypt *.age secret files in Git repositories |
"" |
When unset, local secrets are disabled and ComposeFlux does not scan for *.age files.
See the Age Encrypted Secrets Setup Guide for full details on encrypting and layering secrets.
Optional - Remote Secrets Provider¶
Configure either Bitwarden or Infisical credentials. ComposeFlux selects the provider from the configured credentials. Local and remote secrets can be enabled together, but only one provider may be configured in each category.
Bitwarden:
| Variable | Description | Default |
|---|---|---|
BITWARDEN_ACCESS_TOKEN |
Machine account access token | |
BITWARDEN_ORGANIZATION_ID |
Organization ID | |
BITWARDEN_PROJECT_ID |
Project ID | |
BITWARDEN_API_URL |
Bitwarden API URL | https://vault.bitwarden.com/api |
BITWARDEN_IDENTITY_URL |
Bitwarden Identity URL | https://vault.bitwarden.com/identity |
Infisical:
| Variable | Description | Default |
|---|---|---|
INFISICAL_CLIENT_ID |
Universal Auth client ID | |
INFISICAL_CLIENT_SECRET |
Universal Auth client secret | |
INFISICAL_ENVIRONMENT |
Environment slug (e.g., prod) |
|
INFISICAL_PROJECT_ID |
Project ID | |
INFISICAL_SITE_URL |
Infisical site URL | https://app.infisical.com |
INFISICAL_SECRET_PATH |
Secret path in Infisical project. Supports comma-separated paths (e.g., /generic,/apps/prod). If the same secret exists in multiple paths, the last path's value takes precedence. |
/ |
Optional¶
| Variable | Description | Default |
|---|---|---|
GIT_DEPLOY_KEY_SECRET_REF |
Deploy key secret reference (name or ID) in secrets manager (See Deploy Key Secret Reference) | |
GIT_SSH_KEY_PATH |
SSH key path inside container | /.ssh/composeflux_id_rsa |
GIT_CLONE_PATH |
Local clone directory | /opt/compose-stack |
GIT_INTERVAL |
Git sync interval | 5m |
HEALTH_RECONCILE_INTERVAL |
Interval for proactive stack health reconciliation. ComposeFlux redeploys any stack with a non-running container (unless it is a completed init container). Set to e.g. 5m to enable. |
disabled |
IMAGE_UPDATE_SCHEDULE |
Cron expression for Docker image update checks, e.g. 0 3 * * *. Empty = disabled. |
"" |
GIT_BRANCH |
Git branch to track | main |
CONFIG_FILE |
Stack config file name (see Stack Configuration) | stack.yml |
LOG_LEVEL |
Log level (debug/info/warn/error) |
info |
LOG_FORMAT |
Log format (console/json) |
console |
LOG_ADD_SOURCE |
Add source location to logs | false |
REMOVE_ORPHANS |
Remove orphan containers during deploy | true |
PRUNE_INTERVAL |
Interval for periodic Docker resource pruning (images, volumes, build cache). Only runs when all managed stacks are healthy. Set to 0 to disable. |
24h |
Warning
When PRUNE_INTERVAL is set, pruning removes dangling (untagged) images, unused volumes, and build cache. Containers and networks are not pruned. Pruning requires every discovered source stack to be present and healthy in Docker and none to have composeflux.health.suspend=true in its loaded Git Compose project.
GIT_INTERVAL must be greater than zero. Health and prune intervals must be nonnegative; 0 disables those optional
loops. A nonempty IMAGE_UPDATE_SCHEDULE must be a valid cron expression. Invalid values fail startup before clients
are initialized.
Commands¶
ComposeFlux supports two commands:
Usage: composeflux <command> [flags]
A GitOps continuous deployment tool for Docker Compose.
Flags:
-h, --help Show context-sensitive help.
--log-format="console" Set the output format of the logs. Must be "console" or "json" ($LOG_FORMAT).
--log-level=INFO Set the log level. Must be "DEBUG", "INFO", "WARN" or "ERROR" ($LOG_LEVEL).
--log-add-source Whether to add source file and line number to log records ($LOG_ADD_SOURCE).
--version Print version information and exit
Commands:
run Run ComposeFlux in daemon mode (continuous reconciliation)
sync Perform a one-shot sync and deploy
Run "composeflux <command> --help" for more information on a command.
run- Daemon mode with continuous reconciliation (default). Performs an initial sync at startup, then checks the Git repository for changes at configured intervals (default: 5 minutes). An error returned by the initial sync exits the process. Errors during later reconciliation are logged without stopping the daemon.sync- One-shot sync and deploy. Performs an immediate sync and force-reconciles all managed stacks. Useful when you update secrets in your secrets manager without making Git changes. See Change Detection.
# Daemon mode (initial sync at startup, then checks Git every 5 minutes)
composeflux run
# One-shot mode - manually trigger sync
composeflux sync
Important: The run daemon fetches secrets and deploys changes only when Git updates are detected or when a stack is unhealthy/missing. If you update secrets in your secrets manager without making Git changes, run composeflux sync manually to apply updated secrets. See
Change Detection.
Deploy ComposeFlux¶
1. Set up Secrets:
2. Configure Git Access:
- GitHub Deploy Keys Setup - Recommended for secure read-only access
3. Create .env file:
# Required - Common
GIT_REPO_URL=git@github.com:user/stacks-repo.git
STACK_PATH=stacks
# Option A: Local Age Encrypted Secrets
AGE_PASSPHRASE=your-secure-passphrase
# Option B: Remote Bitwarden Secrets
# GIT_DEPLOY_KEY_SECRET_REF=aaaaaaa-bbbbb-bbbb-cccc-ddddd
# BITWARDEN_ACCESS_TOKEN=your-access-token
# BITWARDEN_ORGANIZATION_ID=your-org-id
# BITWARDEN_PROJECT_ID=your-project-id
# Option C: Remote Infisical Secrets
# GIT_DEPLOY_KEY_SECRET_REF=SSH_PRIVATE_KEY
# INFISICAL_CLIENT_ID=your-client-id
# INFISICAL_CLIENT_SECRET=your-client-secret
# INFISICAL_ENVIRONMENT=prod
# INFISICAL_PROJECT_ID=your-project-id
4. Create compose.yml:
services:
composeflux:
image: ghcr.io/veerendra2/composeflux:latest
container_name: composeflux
restart: unless-stopped
environment:
# Git Configuration
GIT_REPO_URL: ${GIT_REPO_URL}
STACK_PATH: ${STACK_PATH}
# GIT_INTERVAL: 5m # Sync interval
# GIT_BRANCH: main
# Local Age Encrypted Secrets
AGE_PASSPHRASE: ${AGE_PASSPHRASE}
# Remote Secrets - Bitwarden
# GIT_DEPLOY_KEY_SECRET_REF: ${GIT_DEPLOY_KEY_SECRET_REF}
# BITWARDEN_ACCESS_TOKEN: ${BITWARDEN_ACCESS_TOKEN}
# BITWARDEN_ORGANIZATION_ID: ${BITWARDEN_ORGANIZATION_ID}
# BITWARDEN_PROJECT_ID: ${BITWARDEN_PROJECT_ID}
# Remote Secrets - Infisical
# GIT_DEPLOY_KEY_SECRET_REF: ${GIT_DEPLOY_KEY_SECRET_REF}
# INFISICAL_CLIENT_ID: ${INFISICAL_CLIENT_ID}
# INFISICAL_CLIENT_SECRET: ${INFISICAL_CLIENT_SECRET}
# INFISICAL_ENVIRONMENT: ${INFISICAL_ENVIRONMENT}
# INFISICAL_PROJECT_ID: ${INFISICAL_PROJECT_ID}
# INFISICAL_SITE_URL: https://app.infisical.com
# Reconciliation & Pruning
# HEALTH_RECONCILE_INTERVAL: 5m # Proactive health check interval (disabled by default)
# PRUNE_INTERVAL: 24h # Periodic Docker resource prune interval (24h default, 0 to disable)
# Logging
# LOG_LEVEL: info
# LOG_FORMAT: console # console or json
volumes:
- /var/run/docker.sock:/var/run/docker.sock
# Optional: Custom SSH known_hosts
# - ./ssh_known_hosts:/etc/ssh/ssh_known_hosts:ro
# Optional: Mount local SSH key instead of fetching from secrets manager
# - ~/.ssh/id_rsa:/.ssh/composeflux_id_rsa:ro
Mount SSH Key¶
If you prefer to mount your SSH key directly instead of storing it in the secrets manager:
- Leave the Bitwarden and Infisical credentials unset
- Mount your SSH key to the container at the
GIT_SSH_KEY_PATHlocation (default:/.ssh/composeflux_id_rsa)
Deploy Key Secret Reference¶
ComposeFlux can fetch your SSH deploy key from the secrets manager during startup, so it can clone private repositories without mounting a local key.
How GIT_DEPLOY_KEY_SECRET_REF works:
- Requires either complete Bitwarden or Infisical credentials
- When set to a value (e.g.,
SSH_PRIVATE_KEYor a Bitwarden secret ID), ComposeFlux fetches that secret from your secrets manager - Bitwarden: Uses it as the secret ID to fetch (see Bitwarden Add Secrets)
- Infisical: Uses it as the secret key name to fetch
- The fetched content must be your SSH private key
- When left empty (default), skips fetch and uses mounted key at
GIT_SSH_KEY_PATH
Example:
environment:
GIT_DEPLOY_KEY_SECRET_REF: "" # Disable fetch from secrets manager
# GIT_SSH_KEY_PATH: /.ssh/composeflux_id_rsa # Optional: custom path
volumes:
- ~/.ssh/id_rsa:/.ssh/composeflux_id_rsa:ro
5. Start ComposeFlux:
# Default: Run in daemon mode (continuous reconciliation)
docker compose up -d
docker compose logs -f
Verify Deployment¶
# Check logs
docker compose logs -f
# List managed stacks (should show containers with composeflux label)
docker ps --filter "label=composeflux.managed=true"
# List all compose projects
docker compose ls