Docker production management CLI + MCP server
fleet
Docker production management CLI + MCP server
Manages Docker Compose applications on a single server with systemd orchestration, nginx configuration, encrypted secrets, Git/GitHub workflows, health monitoring, and Telegram alerts.
Architecture
fleet CLI (TypeScript/Node.js)
├── Commands CLI interface (fleet <command>)
├── MCP Server Claude Code integration (fleet mcp)
├── Registry App inventory (data/registry.json)
├── Secrets Vault age-encrypted secrets (vault/*.age)
└── Templates systemd, nginx, gitignore generators
fleet-bot (Go)
└── Telegram bot that runs Claude Code sessions for remote management
How it works
Each Docker Compose app is registered in fleet's registry with its compose path, service name, domains, port, and container names. Fleet generates a systemd service unit for each app so they start on boot in the correct order (databases first, then dependents). Secrets are encrypted at rest using age and decrypted to a tmpfs at /run/fleet-secrets/ on boot via a systemd oneshot service.
Requirements
Install
From npm
npm install -g @matthesketh/fleet
From source
git clone https://github.com/wrxck/fleet.git
cd fleet
npm install
npm run build
sudo npm link
Install as Claude Code MCP server
sudo fleet install-mcp
This writes the MCP server config to ~/.claude.json so all Claude Code sessions can use fleet tools. Alternatively, add manually:
{
"mcpServers": {
"fleet": {
"command": "fleet",
"args": ["mcp"]
}
}
}
Usage
Fleet requires root for all commands except mcp and install-mcp.
fleet <command> [options]
App lifecycle
fleet deploy <app-dir> # Register, build, and start (full pipeline)
fleet add <app-dir> # Register an existing app without deploying
fleet remove <app> # Stop, disable, and deregister
fleet init # Auto-discover all existing apps on the server
deploy is the primary command -- it registers the app if needed, runs docker compose build, and starts/restarts the systemd service.
Service control
fleet start <app> # Start via systemctl
fleet stop <app> # Stop via systemctl
fleet restart <app> # Restart via systemctl
fleet logs <app> [-f] # Container logs (follow mode with -f)
Monitoring
fleet status # Dashboard: all apps, systemd state, containers, health
fleet list [--json] # List registered apps
fleet health [app] # Health checks: systemd + container + HTTP
fleet watchdog # Check all services, send Telegram alert on failure
watchdog is designed to run on a cron schedule. It checks systemd unit status, container state, and HTTP health endpoints, then sends a Telegram alert if anything is unhealthy. Configure Telegram credentials at /etc/fleet/telegram.json:
{
"botToken": "123456:ABC-DEF...",
"chatId": "-100..."
}
Nginx management
fleet nginx add <domain> --port [--type proxy|spa|nextjs]
fleet nginx remove <domain>
fleet nginx list
Generates an nginx server block, writes it to /etc/nginx/sites-available/, symlinks to sites-enabled/, tests the config, and reloads nginx. Supports three config types:
- proxy -- reverse proxy to a backend port (default)
- spa -- static SPA with
try_filesfallback toindex.html - nextjs -- Next.js-specific proxy with static asset handling
Secrets management
Fleet uses age encryption for secrets at rest. Each app's secrets (.env files or secret directories) are encrypted as .age files in the vault/ directory. On boot, a systemd oneshot service decrypts everything to /run/fleet-secrets/ (tmpfs -- never touches disk).
fleet secrets init # Create age keypair, install unseal service
fleet secrets import <app> [path] # Import .env or secrets dir into vault
fleet secrets export <app> # Print decrypted .env to stdout
fleet
Tools (1)
fleetManages Docker Compose applications, systemd services, Nginx configurations, and encrypted secrets.Configuration
{"mcpServers": {"fleet": {"command": "fleet", "args": ["mcp"]}}}