Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Repository files navigation

FleetDeck - One command. Code to production.

Install GuideQuick StartOne CommandProfilesServer SetupUsage GuideDocs

CI License: MIT Go Report Card


FleetDeck is a single-binary deployment platform that takes your application from code to production with one command. It detects your stack, provisions your server, deploys with zero downtime, sets up HTTPS, configures CI/CD, monitors health, and handles backups. No Kubernetes. No YAML hell. Just ship.

fleetdeck deploy ./my-saas --server [email protected] --domain myapp.com --profile saas

That one command connects to your server, detects your app (Next.js, Go, Python, whatever), generates a Docker Compose stack with PostgreSQL + Redis + S3 + email, configures Traefik for automatic HTTPS, deploys your containers, and sets up GitHub Actions CI/CD. Done.


The Problem

Every new project is the same 30-minute ritual:

  1. SSH into server, create a Linux user
  2. Generate SSH keys for CI/CD
  3. Write a Dockerfile
  4. Write docker-compose.yml with Traefik labels
  5. Configure .env with database passwords
  6. Create GitHub repo, set deploy secrets
  7. Write a GitHub Actions workflow
  8. Set up DNS records
  9. Configure backups
  10. Pray nothing breaks

Now multiply that by every project you ship. FleetDeck eliminates all of it.

What Makes FleetDeck Different

Unlike Kubernetes (too complex), Coolify/CapRover (opinionated PaaS), or plain Docker scripts (too manual), FleetDeck sits in the sweet spot:

  • Not a PaaS -- you own your server, your configs, your data
  • Not an orchestrator -- no clusters, no service mesh, no learning curve
  • Just automation -- it does exactly what you'd do manually, but in seconds
  • Single binary -- one go build, one file, runs everywhere

Quick Start

Install

git clone https://github.com/Artaeon/fleetdeck.git
cd fleetdeck
make build
sudo make install

Requirements: Linux (Ubuntu 22.04+, Debian 12+). Go 1.23+ for building. Docker and Traefik are installed automatically by server setup.

The One-Command Workflow

Step 1: Provision your server (once):

fleetdeck server setup root@your-server-ip \
  --domain yourdomain.com \
  --email [email protected] \
  --insecure  # TOFU: auto-saves host key on first connect

This installs Docker, Traefik (with automatic Let's Encrypt HTTPS), UFW firewall, fail2ban, swap, and hardens SSH. Idempotent -- safe to re-run.

Step 2: Deploy your app:

fleetdeck deploy ./my-app \
  --server root@your-server-ip \
  --domain myapp.yourdomain.com \
  --profile saas

Step 3: There is no step 3. Your app is live at https://myapp.yourdomain.com.

Already Have a Server?

# Initialize FleetDeck on your existing server
sudo fleetdeck init

# Import your existing Docker Compose projects
sudo fleetdeck discover
sudo fleetdeck discover import --all

# Create a new project
sudo fleetdeck create myapp --domain myapp.com --template node --profile server
sudo fleetdeck start myapp

Smart Detection

FleetDeck analyzes your project and figures out what you need:

$ fleetdeck detect ./my-app

  Application detected!

  Property    Value
  Type        nextjs
  Language    typescript
  Framework   Next.js (App Router)
  Port        3000
  Database    yes
  Redis       yes
  Confidence  95%

  Recommended profile: saas

Supported stacks:

Language Frameworks Detection Method
Node.js Express, Fastify, Koa package.json
TypeScript Next.js, NestJS package.json + app/ dir
Python FastAPI, Django, Flask requirements.txt, Pipfile, pyproject.toml
Go Gin, Echo, Fiber go.mod
Rust Actix Web, Axum, Rocket Cargo.toml
Static HTML/CSS/JS index.html

Detection also identifies database usage (PostgreSQL, MySQL, MariaDB), Redis, Docker configs, and recommends the right deployment profile.


Deployment Profiles

Profiles are pre-built infrastructure stacks. Instead of writing Docker Compose from scratch, pick a profile and FleetDeck generates everything.

fleetdeck profiles           # List all profiles
fleetdeck profile saas       # Inspect a specific profile
Profile What You Get Best For
bare App container + Traefik HTTPS Stateless APIs, microservices
server App + PostgreSQL + Redis Backend APIs, web apps
saas App + PostgreSQL + Redis + S3 (MinIO) + Email (Mailpit) Full SaaS products
static Nginx + CDN headers + gzip + SPA fallback Landing pages, docs, SPAs
worker Worker process + Redis queue + PostgreSQL Background job processors
fullstack Frontend + Backend + PostgreSQL + Redis + S3 Monorepo applications

The saas Profile

Everything you need for a production SaaS, generated in one command:

  • Your app with Traefik routing and automatic HTTPS
  • PostgreSQL with health checks, persistent storage, pg_isready probes
  • Redis with AOF persistence, 512MB memory limit, LRU eviction
  • MinIO (S3-compatible) at s3.yourdomain.com for file uploads
  • Mailpit at mail.yourdomain.com for email testing/SMTP relay
  • Auto-generated .env with cryptographically random passwords

The fullstack Profile

For monorepos with separate frontend and backend:

  • Frontend at yourdomain.com (Next.js, React, etc.)
  • Backend API at api.yourdomain.com
  • Separate Dockerfiles (Dockerfile.frontend, Dockerfile.backend)
  • Shared database, cache, and object storage

Post-Deploy Watchdog & Auto-Rollback

After every zero-downtime deploy, fleetdeck can poll the live domain for a configurable window and automatically roll back if the new revision silently breaks a few minutes after the cutover — the most common production failure mode that health checks alone miss (OOM, upstream latency, slow migration deadlock).

# Watch for 5 minutes, roll back to the pre-deploy snapshot on failure
fleetdeck deploy ./my-app \
  --server prod --domain app.example.com \
  --watch 5m --watch-rollback

# Tune probing
fleetdeck deploy ./my-app \
  --server prod --domain app.example.com \
  --watch 10m --watch-interval 15s --watch-threshold 5 --watch-status 200

With --watch unset (the default), deploy behavior is unchanged. Without --watch-rollback a failed watchdog only warns — you run fleetdeck rollback manually.

Rollback scope (--watch-rollback-mode):

Mode Restores Loses Use for
full (default) config + volumes + DB dumps none (rewinds fully) stateless apps, landing pages
files config only none — DB writes from the watch window survive stateful apps, mealtime-style workloads
# Stateful app: roll the config back, but keep user data written during the watch window
fleetdeck deploy ./mealtime --domain mealtime.com \
  --watch 5m --watch-rollback --watch-rollback-mode=files

Database Migrations

Fleetdeck wraps whatever migration tool your project already uses (npm run migrate, rails db:migrate, prisma migrate deploy, flyway migrate, …). It doesn't invent a migration format — it adds three guarantees on top of docker compose exec:

  1. Snapshot before every run. A pre-migration DB snapshot is taken automatically, so a botched migration is one command away from recovery.
  2. Tracked history. Every migration is recorded in fleetdeck's SQLite DB with command, status, duration, and the snapshot ID.
  3. Single-command rollback. fleetdeck migrate rollback <project> restores the snapshot from the most recent migration.
# Ad-hoc: run a migration, safely
fleetdeck migrate run mealtime --command "npm run migrate"

# Inspect the history — what ran, when, how long, which snapshot
fleetdeck migrate history mealtime

# Restore the pre-migration state of the last migration
fleetdeck migrate rollback mealtime

# Or wire migrations into deploy
fleetdeck deploy ./mealtime --domain mealtime.com \
  --migrate "npm run migrate" \
  --watch 5m --watch-rollback --watch-rollback-mode=files

When --migrate is used with deploy, the pipeline is: snapshot → build → up → migrate → watchdog. A failing migration aborts the deploy before the watchdog runs; the pre-migration snapshot is waiting, and the operator sees the migration output inline.

--migrate is currently supported for local deploys only (where fleetdeck runs on the target server). For remote deploys, SSH to the server and run fleetdeck migrate run there.

Deployment Strategies

fleetdeck deploy ./app --strategy bluegreen --domain app.com
Strategy How It Works Downtime
basic docker compose up -d Brief (~seconds)
bluegreen New containers alongside old, health check, switch traffic Zero
rolling Update services one at a time with --no-deps Zero

Blue/green deployment flow:

  1. Start new containers under a temporary project name
  2. Run health checks against the new containers
  3. If healthy: stop old containers, promote new ones
  4. If unhealthy: remove new containers, old ones keep running

Per-project locking prevents concurrent deployments of the same project.


Server Provisioning

fleetdeck server setup [email protected] \
  --domain example.com \
  --email [email protected] \
  --swap 4
Component What Gets Configured
System apt update/upgrade, curl, git, htop, fail2ban, UTC timezone
Docker Docker Engine + Compose v2 from official Docker repo
Traefik v3 reverse proxy, Let's Encrypt HTTPS, HTTP-to-HTTPS redirect
Firewall UFW: SSH (22), HTTP (80), HTTPS (443) only
Swap Configurable swap file (default 2GB)
SSH Password auth disabled, root login disabled

Every step is idempotent -- run it again after six months and it just verifies everything is still configured correctly.

SSH Security: Uses Trust On First Use (TOFU) -- the host key is verified against ~/.ssh/known_hosts. On first connection with --insecure, the key is automatically saved for future verification. SSH keys are auto-discovered by checking ~/.ssh/config, then common key names (id_ed25519, id_ecdsa, id_rsa), then scanning ~/.ssh/ for any private keys -- the --key flag is only needed to override the default.


DNS Management

# Auto-configure root + wildcard A records
fleetdeck dns setup example.com 143.198.1.1 --provider cloudflare --token cf_xxx

# List all records
fleetdeck dns list example.com --token cf_xxx

Creates example.com and *.example.com A records pointing to your server. Supports multi-level TLDs (.co.uk, .com.au, etc.) correctly.


Environment Management

fleetdeck env create myapp staging --domain staging.myapp.com
fleetdeck env create myapp preview --domain preview.myapp.com --branch feature/redesign
fleetdeck env promote myapp staging production

Each environment gets its own Docker Compose stack, domain, and configuration. Promotion copies config and images from one environment to another.


Health Monitoring

Run the monitor as a systemd service so alerts survive reboots and process crashes:

sudo cp packaging/systemd/fleetdeck-monitor.service /etc/systemd/system/
sudo systemctl enable --now fleetdeck-monitor
journalctl -u fleetdeck-monitor -f

The shipped unit runs fleetdeck monitor start --all, which watches every registered project. Put provider webhooks in /etc/fleetdeck/fleetdeck.env (mode 0600) and systemctl restart fleetdeck-monitor to pick them up. See packaging/systemd/README.md for the full setup.

# Continuous monitoring with Slack alerts
fleetdeck monitor start myapp --interval 30s --slack https://hooks.slack.com/xxx

# One-off health check (great for CI/CD)
fleetdeck monitor check myapp
  • Alerts fire on state transitions only (healthy -> unhealthy, recovery) -- no alert fatigue
  • Configurable failure threshold (default: 3 consecutive failures before alerting)
  • State persists to disk -- survives process restarts
  • Providers: Webhook (JSON POST), Slack (formatted messages), Email (SMTP)

Backup & Disaster Recovery

# Full backup (config + database dumps + volume archives)
fleetdeck backup create myapp

# List backups
fleetdeck backup list myapp

# Restore (auto-snapshots current state first)
fleetdeck backup restore myapp <backup-id>

# Quick rollback to latest snapshot
fleetdeck rollback myapp --latest

# Schedule daily backups
fleetdeck schedule enable myapp

# Push a backup to off-server storage (S3, B2, R2, GCS, SFTP, ...)
fleetdeck backup push myapp

Automatic snapshots before every stop, restart, destroy, and restore. You can always go back, even after a restore.

What gets backed up: docker-compose.yml, .env, Dockerfile, PostgreSQL dumps (pg_dump), MySQL dumps (mysqldump), Docker volume archives, SHA256 manifest.

Retention: configurable max count, max age (days), max total size (GB). The most recent backup of each type is never deleted.

Off-server backup (rclone driver): add a [backup.remote] block to your config.toml and fleetdeck backup push will mirror backups to any of rclone's ~50 backends without requiring an object-store SDK:

[backup.remote]
driver    = "rclone"        # currently the only driver
target    = "b2:my-fleet-backups"  # any rclone remote:path
auto_push = true            # optional — push automatically on backup create

Configure the rclone remote once with rclone config on the server. With auto_push = true, every backup is mirrored off-server synchronously; without it, operators run fleetdeck backup push (manually or via cron) to sync on their own schedule.


Web Dashboard & API

fleetdeck dashboard --addr :8420

Browser-based project management: real-time server stats, project grid, start/stop/restart controls, live log viewer, backup browser, deployment history, and GitHub webhook integration.

Full REST API at /api/projects, /api/status, /api/audit, /api/webhook/github.


How to Use FleetDeck

Your First Deploy (5 minutes)

Prerequisites: A VPS (Hetzner, DigitalOcean, Linode -- $5/mo works), a domain, and your app code.

# 1. Build FleetDeck
git clone https://github.com/Artaeon/fleetdeck.git && cd fleetdeck
make build && sudo make install

# 2. Provision your server
fleetdeck server setup root@YOUR_SERVER_IP \
  --domain yourdomain.com \
  --email [email protected] \
  --insecure

# 3. Set up DNS (auto if you have Cloudflare)
fleetdeck dns setup yourdomain.com YOUR_SERVER_IP \
  --provider cloudflare --token YOUR_CF_TOKEN

# 4. Deploy your app
cd /path/to/your/app
fleetdeck deploy . \
  --server root@YOUR_SERVER_IP \
  --domain app.yourdomain.com \
  --profile saas

# Your app is live at https://app.yourdomain.com

Day-to-Day Workflow

# Push code -> GitHub Actions auto-deploys
git push origin main

# Check project status
fleetdeck list
fleetdeck info myapp
fleetdeck logs myapp -f

# Deploy a new project
fleetdeck deploy ./new-project --server root@server --domain new.yourdomain.com

# Create a staging environment
fleetdeck env create myapp staging

# Quick update without CI/CD
fleetdeck update myapp --server prod
fleetdeck update myapp --server prod --service app  # single service

# Monitor health
fleetdeck monitor start myapp --slack https://hooks.slack.com/xxx

# Backup before risky changes
fleetdeck backup create myapp
# ... make changes ...
fleetdeck rollback myapp --latest  # oops, revert

Updating Live Applications

For apps that are already deployed, fleetdeck update provides a lightweight alternative to full redeployment -- no CI/CD pipeline needed. It syncs your local files to the server, auto-detects Dockerfile or Compose changes, and rebuilds only when necessary.

# Sync files and rebuild only if Dockerfile/compose changed
fleetdeck update myapp --server root@server

# Force a full rebuild (e.g. after dependency changes)
fleetdeck update myapp --server root@server --rebuild --no-cache

# Update a single service in a multi-container stack
fleetdeck update myapp --server root@server --service app

# Pull latest images without rebuilding
fleetdeck update myapp --server root@server --pull

# Just restart containers (no file sync)
fleetdeck update myapp --server root@server --restart-only

# Run hooks before/after deployment
fleetdeck update myapp --server root@server \
  --pre-deploy "npm run migrate" \
  --post-deploy "npm run seed"

Managing Multiple Projects

FleetDeck is built for running 5-50 projects on a single server:

$ fleetdeck list

NAME         DOMAIN                  STATUS    TEMPLATE  PROFILE
myapp        myapp.com               running   nextjs    saas
api          api.company.com         running   go        server
blog         blog.company.com        running   static    static
worker       -                       running   node      worker
staging      staging.myapp.com       stopped   nextjs    saas

Each project gets its own Linux user, SSH keys, Docker network, and backup schedule. Complete isolation.


Operational Runbook

Concrete recipes for the scenarios you'll actually hit in production. Each entry assumes fleetdeck is installed on the server and you're running these commands there (either directly via SSH or inside a CI job that SSHes in).

Recipe 1 — A migration broke production

Symptom: fleetdeck migrate run or deploy --migrate reported failure; the DB is in an intermediate state.

# 1. See what ran
fleetdeck migrate history mealtime

# 2. Roll back the DB to the pre-migration snapshot
fleetdeck migrate rollback mealtime

# 3. Confirm the app is serving the old schema + old code
curl -I https://mealtime.com

The pre-migration snapshot was taken before the migration command even started, so restore brings back both the DB and the config files. You're left running the previous release; re-deploy to roll forward once the migration is fixed.

Recipe 2 — A deploy silently broke things after cutover

Symptom: the deploy succeeded, containers came up healthy, but 10 minutes in the app started throwing 5xx.

# If you deployed with --watch --watch-rollback, nothing to do —
# the watchdog already restored the pre-deploy snapshot and the
# domain is back on the previous release.

# If you didn't opt into auto-rollback:
fleetdeck rollback mealtime --latest

For next time: always deploy mealtime with --watch 5m --watch-rollback --watch-rollback-mode=files so user writes from the watch window survive.

Recipe 3 — The VPS is gone, restore from offsite backup

Symptom: DigitalOcean/Hetzner/whoever lost the disk. You have [backup.remote] configured and backups have been mirrored to B2 / R2 / S3.

# On a fresh server:
fleetdeck server setup root@new-vps --domain example.com --email [email protected]

# Pull the offsite copy of the most recent backup (using rclone directly —
# fleetdeck intentionally leaves this step manual so you confirm the
# source before writing to disk)
rclone copy b2:my-fleet-backups/<backup-id> /opt/fleetdeck/backups/mealtime/<backup-id>

# Rehydrate the project record (the SQLite DB is gone, so fleetdeck
# doesn't know about this backup yet)
fleetdeck create mealtime --domain mealtime.com --profile server --import-backup /opt/fleetdeck/backups/mealtime/<backup-id>

# Or, if `create --import-backup` isn't wired yet, restore manually:
fleetdeck backup restore mealtime <backup-id>

Before you need this: test it once end-to-end on a throwaway VPS. A backup you haven't restored is a hope, not a backup.

Recipe 4 — Rotate the Cloudflare API token (or other secret)

# Update the env file that systemd reads
sudo $EDITOR /etc/fleetdeck/fleetdeck.env
# edit FLEETDECK_DNS_TOKEN=...

# Restart the daemons so they pick up the new value
sudo systemctl restart fleetdeck-monitor

# Active CLI sessions keep their old env; restart your shell or
# re-export the var before running 'fleetdeck dns ...'

Environment-file changes do NOT propagate to already-running processes.

Recipe 5 — Add a new domain to an existing project

# Update the project's docker compose labels (Traefik Host rule)
# Then re-deploy — Traefik picks up the new host and requests the cert
fleetdeck deploy ./mealtime --domain new.mealtime.com --watch 5m

If DNS isn't pointed yet, Let's Encrypt will reject the certificate request. Point DNS first, then deploy.

Recipe 6 — Set up a dead-man's switch for backups

A broken backup schedule is a silent failure. The safest pattern is a cron that runs an audit and pings an uptime monitor only if the audit passes — if the ping doesn't arrive, the monitor alerts.

# /etc/cron.d/fleetdeck-backup-audit
*/30 * * * * fleetdeck  fleetdeck backup audit --max-age 48h --quiet \
                         && curl -fsS https://hc-ping.com/<your-uuid> >/dev/null

If any project has no backup or its most recent backup is older than --max-age, audit exits non-zero, the && curl never runs, and healthchecks.io (or equivalent) fires an alert. Add a second monitor for the ping endpoint itself.

Recipe 7 — "Is my backup actually restorable?"

# Run the verify command — checks all SHA256 checksums and gzip integrity
fleetdeck backup verify mealtime <backup-id>

# For real confidence, do a restore on a throwaway project:
fleetdeck create mealtime-restore-test --domain scratch.example.com --profile server
fleetdeck backup restore mealtime-restore-test <backup-id>

Do this at least once per quarter. Verified backups are the only kind that count.

Configuration at a glance

Env var Purpose
FLEETDECK_ENCRYPTION_KEY AES key passphrase for encrypted secrets column
FLEETDECK_API_TOKEN Bearer token for the dashboard / HTTP API
FLEETDECK_WEBHOOK_SECRET HMAC secret for GitHub push webhooks
FLEETDECK_DNS_TOKEN Cloudflare API token
FLEETDECK_MONITORING_SLACK / FLEETDECK_MONITORING_WEBHOOK Alert destinations
FLEETDECK_TRUST_PROXY_IPS Comma-separated list of proxy IPs whose X-Forwarded-For is honored for rate limiting
FLEETDECK_SSH_PASSPHRASE Passphrase for an encrypted SSH key used by deploy --server
FLEETDECK_BASE_PATH Override /opt/fleetdeck (e.g. for local/dev use)

All are also settable in /etc/fleetdeck/config.toml. Env vars win when both are set.

Deployment checklist for a new production project

Don't skip items. Each one has saved someone's weekend at least once.

  • fleetdeck server setup on a fresh VPS (idempotent if re-run)
  • [backup.remote] configured with auto_push = true and a tested rclone remote
  • fleetdeck backup audit --max-age 48h wired into cron + an uptime monitor (dead man's switch for broken schedules)
  • Systemd unit fleetdeck-monitor.service enabled (journalctl -u fleetdeck-monitor -f shows probes)
  • External uptime monitor (Uptime Kuma, Pingdom) configured — fleetdeck's own monitor can't catch "the VPS is dead"
  • FLEETDECK_ENCRYPTION_KEY at least 16 chars of random material (openssl rand -hex 32)
  • First deploy uses --watch 5m --watch-rollback (use --watch-rollback-mode=files for stateful apps)
  • Backup restore rehearsed on a throwaway project — verify, don't hope
  • v0.1.0 (or whatever release) pinned — don't upgrade the binary the same week you deploy

Production hardening reference

Concern What fleetdeck does by default How to tune
Deploy concurrency Caps parallel deploys at 3 so a coordinated org push doesn't OOM the box [server] max_concurrent_deploys = 10 in config.toml
Webhook retry storms Dedupes GitHub redeliveries by X-GitHub-Delivery for 30 min No knob — size chosen to outlast GitHub's retry window
Stuck subprocess Every git pull, docker compose build/up/exec runs with a per-step timeout Timeouts live at the top of internal/server/webhook.go
Graceful shutdown Shutdown() cancels shutdownCtx, drains in-flight async deploys, then closes DB Caller's context deadline caps the wait
Rate-limit bypass X-Forwarded-For only honored when peer is in FLEETDECK_TRUST_PROXY_IPS Set to 127.0.0.1,::1 behind a local reverse proxy
Secret permissions .env, .pem, .key, .p12, .pfx, .jks forced to 0600 on upload regardless of source mode Source list in internal/remote/transfer.go
Audit log exposure Log file created 0640, directory 0750 — not world-readable N/A; tighten with filesystem ACLs if needed
Weak encryption key FLEETDECK_ENCRYPTION_KEY under 16 chars rejected at startup Error message points at openssl rand -hex 32
Config typos Invalid strategy/profile/dns.provider values rejected at Load Sentinel values documented in the config reference

Documentation

Complete Command Reference

Command Description
Deploy & Update
fleetdeck deploy [dir] One-command deploy (local or remote via SSH)
fleetdeck update <name> Lightweight update for live apps (sync, rebuild if needed)
fleetdeck detect [dir] Auto-detect app type and recommend profile
fleetdeck profiles List all deployment profiles
fleetdeck profile <name> Inspect a profile (add --compose for template)
Server
fleetdeck server setup <user@host> Provision a fresh server
fleetdeck init Initialize FleetDeck locally
fleetdeck upgrade Self-update to latest release
Projects
fleetdeck create <name> Create project (--profile, --template, --domain)
fleetdeck start / stop / restart <name> Lifecycle management
fleetdeck destroy <name> Remove project (with optional data retention)
fleetdeck list / info / logs / status Information and monitoring
DNS
fleetdeck dns setup <domain> <ip> Auto-configure A + wildcard records
fleetdeck dns list / delete Record management
Environments
fleetdeck env create / list / promote / delete Multi-environment management
Monitoring
fleetdeck monitor start <name> Continuous health monitoring
fleetdeck monitor check <name> Single health check (exits non-zero if unhealthy)
Backup
fleetdeck backup create / list / restore Full backup and restore
fleetdeck backup push <name> Mirror backup to the rclone remote configured under [backup.remote]
fleetdeck backup audit --max-age 48h Dead-man's-switch: exit non-zero if any project has stale or missing backups
fleetdeck rollback <name> Quick rollback to any snapshot
fleetdeck snapshot <name> Quick snapshot
fleetdeck schedule enable / disable / list Scheduled backups via systemd
Migrations
fleetdeck migrate run <name> --command "..." Snapshot-then-run: tracked app-level migration
fleetdeck migrate history <name> List past migrations with status, duration, snapshot ID
fleetdeck migrate rollback <name> Restore the snapshot from the most recent migration
Retention
fleetdeck prune deployments --keep 50 Trim old deployment rows from the SQLite database
CI/CD
fleetdeck setup-cd <name> Register project for auto-deploy from GitHub
Volumes
fleetdeck volumes list List Docker volumes for a project
fleetdeck volumes rm Remove Docker volumes
Discovery
fleetdeck discover Scan server for existing Docker Compose projects
fleetdeck discover import Import discovered projects
fleetdeck sync Reconcile database with actual system state

Configuration

# /etc/fleetdeck/config.toml

[server]
base_path = "/opt/fleetdeck"
domain = "fleet.yourdomain.com"
encryption_key = "your-strong-passphrase"
api_token = "dashboard-auth-token"
webhook_secret = "github-webhook-secret"

[traefik]
network = "traefik_default"
entrypoint = "websecure"
cert_resolver = "letsencrypt"

[github]
default_org = "your-github-org"

[defaults]
template = "node"
postgres_version = "15-alpine"

[deploy]
strategy = "basic"              # basic, bluegreen, rolling
default_profile = "server"
timeout = "5m"

[monitoring]
enabled = false
interval = "30s"
timeout = "10s"
failure_threshold = 3

[dns]
provider = "cloudflare"

[backup]
base_path = "/opt/fleetdeck/backups"
max_manual_backups = 10
max_snapshots = 20
max_age_days = 30
max_total_size_gb = 5
auto_snapshot = true

[audit]
enabled = true
log_path = "/var/log/fleetdeck/audit.log"

Sensitive values can be set via environment variables: FLEETDECK_API_TOKEN, FLEETDECK_WEBHOOK_SECRET, FLEETDECK_ENCRYPTION_KEY, FLEETDECK_DNS_TOKEN, FLEETDECK_MONITORING_SLACK.

Security

Layer Implementation
Process isolation Per-project Linux users with minimal privileges
SSH Ed25519 keys, TOFU host verification, restricted to docker compose only
Secrets AES-256-GCM at rest, PBKDF2 key derivation (100K iterations)
Webhooks HMAC-SHA256 signature verification
API Bearer token auth, per-IP rate limiting (10 req/s)
Network Per-project Docker networks, Traefik TLS termination
HTTP CSP, X-Frame-Options, X-Content-Type-Options, Referrer-Policy
Firewall UFW: SSH + HTTP + HTTPS only
Input validation Shell injection prevention, path traversal protection
Deployment Per-project file locking prevents concurrent deploys
Audit Structured JSON logs for every operation

Development

make build          # Build binary
make test           # Run all tests
make test-race      # Run with race detection
make test-cover     # Generate coverage report
make vet            # Run go vet
make lint           # Run golangci-lint
make release        # Build release binaries (amd64 + arm64)

Test Coverage

900+ test functions across 60+ test files. All tests pass. Zero race conditions.

Package Coverage Tests
detect 99.1% 78
profiles 95.1% 54
bootstrap 93.9% 56
config 90.7% 26
environments 88.7% 51
dns 85.7% 40
monitor 82.1% 56
project 73.2% 39
deploy 32.6% 39
remote 9.0% 36

Deploy and remote have lower unit test coverage because they execute docker compose and SSH commands that require real infrastructure. Integration tests in CI run these against real Docker and SSH containers.

CI Pipeline

Every push runs: build, vet, race-detected tests, coverage report, Docker integration tests, and SSH integration tests. See .github/workflows/ci.yml.


Roadmap

  • Smart app detection (Node, Python, Go, Rust, static)
  • 6 deployment profiles (bare, server, saas, static, worker, fullstack)
  • One-command remote deployment via SSH
  • Server provisioning (Docker, Traefik, firewall, SSL)
  • Zero-downtime deployments (blue/green, rolling)
  • TOFU SSH host key verification
  • Per-project deployment locking
  • Health monitoring with Slack/webhook/email alerts + state persistence
  • DNS management with multi-level TLD support (Cloudflare)
  • Environment management (staging/production/preview)
  • Web dashboard with REST API
  • Backup, snapshot, and rollback system
  • Secret encryption (AES-256-GCM)
  • Audit logging with rotation
  • GitHub Actions CI with integration tests
  • Lightweight update command for live applications
  • SSH key auto-discovery from ~/.ssh/config
  • CI/CD setup with branch-based deployments
  • Hetzner and DigitalOcean DNS providers
  • Resource monitoring (CPU, RAM per project via cgroups)
  • Prometheus metrics endpoint
  • Plugin system for custom hooks
  • Multi-server support

Contributing

See CONTRIBUTING.md for development setup, code style, and pull request guidelines.

Security

See SECURITY.md for the security model and vulnerability reporting.

License

MIT


Built by Artaeon

About

FleetDeck is a single-binary CLI that automates the entire workflow of deploying Docker Compose projects on a server with Traefik. It replaces the manual repetition of creating users, generating keys, configuring Docker Compose with Traefik labels, setting up GitHub Actions CI/CD, and managing secrets — turning it all into one command.

Topics

Resources

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages