iron
A CLI that deploys Docker Compose apps to bare-metal servers with automatic HTTPS, DNS, and zero-downtime updates.
Features
- Single config file — define servers, apps, routing, and sidecars in
fleet.toml - Docker Compose — generates compose files and deploys via SSH
- Caddy reverse proxy — automatic HTTPS with generated per-app config fragments
- Cloudflare DNS — creates and manages A records automatically
- Zero-downtime deploys — rolling updates via docker-rollout, or stop-and-replace for stateful services
- Server bootstrapping — provisions new machines with Ansible (Docker, firewall, fail2ban, hardening)
- Auto-deploy — optional WUD (What's Up Docker) integration watches for new images and triggers deploys
- Sidecar services — attach databases, caches, or any container alongside your app
- Direct TCP — expose non-HTTP services (game servers, databases) with port mappings
- Secrets management — env vars live in
fleet.env.toml(gitignored), deployed as.envfiles
Installation
This installs two binaries — flow and iron — which are identical. Use whichever you prefer.
To build from source:
Prerequisites
- SSH agent with key for target servers
- Cloudflare API token and GHCR token —
flow loginwill guide you through setup - Python/pip (only for
flow server add— Ansible is auto-installed if missing)
Quick Start
# Initialize a new fleet.toml (prompts for tokens)
# Or add/update tokens separately
# Add a server (creates DNS record, bootstraps via Ansible)
# Add an app with routing
# Add a worker (no routing needed)
# Add a game server with direct TCP
# Add sidecar services
# Deploy
Commands
How It Works
flow deploy <app>
1. Parse fleet.toml + fleet.env.toml
2. Generate docker-compose.yml and .env
3. SSH to target server
4. Upload files to /opt/flow/<app>/
5. Pull images, rolling deploy (or recreate)
6. Generate Caddy config fragment, reload Caddy
7. Ensure Cloudflare DNS A record
Configuration
fleet.toml is the single source of truth for your infrastructure. fleet.env.toml (gitignored) holds all environment variables and secrets.
[]
= "example.com"
= "your-zone-id"
[]
= "164.90.130.5"
[]
= "ghcr.io/org/site:latest"
= ["srv-1"]
= 3000
[]
= ["example.com", "www.example.com"]
= "/health"
[[]]
= "postgres"
= "postgres:17"
= ["pgdata:/var/lib/postgresql/data"]
= "pg_isready -U app"
License
MIT