No-downtime app deployment on bare metal. One binary. No containers. No bullshit.
Buy a server. Install Vela. Deploy your apps from your laptop over SSH. That's it.
No Docker. No Kubernetes. No YAML-driven orbital complexity. No $500/month for an app that nobody uses yet.
# On your server
vela serve
# From your laptop
vela deploy ./target/release/my-appVela uploads your binary (or BEAM release), starts it on a fresh port, runs a health check, swaps the proxy, and drains the old instance. Zero downtime. Under a minute.
┌─────────────────────────────────────────────┐
│ Your server │
│ │
│ Vela daemon │
│ ├── Reverse proxy (:80/:443, auto-TLS) │
│ ├── Process manager (start, health, swap) │
│ └── IPC socket (/var/vela/vela.sock) │
│ │
│ Apps │
│ ├── next.ai → :10001 │
│ └── giga.app → :10002 │
└─────────────────────────────────────────────┘
┌─────────────────────────────────────────────┐
│ Your laptop │
│ │
│ vela deploy → scp + ssh → server │
└─────────────────────────────────────────────┘
- One binary — same
velaruns on server and laptop - Embedded proxy — hyper-based reverse proxy with auto-TLS via Let's Encrypt (with auto-renewal)
- SSH is the control plane — no tokens, no API keys, no custom auth
- SQLite-aware — persistent data directories survive deploys; sequential strategy avoids write contention
- Rust and Elixir — deploy compiled binaries or BEAM releases
curl -fsSL https://raw.githubusercontent.com/raskell-io/vela/main/install.sh | bashBinaries are available for Linux (amd64, arm64) and macOS (amd64, arm64).
# Install vela on your server
curl -fsSL https://raw.githubusercontent.com/raskell-io/vela/main/install.sh | bash
# Create config
mkdir -p /etc/vela
cat > /etc/vela/server.toml <<'EOF'
data_dir = "/var/vela"
[proxy]
http_port = 80
https_port = 443
[tls]
acme_email = "you@example.com"
staging = true # Use staging first, switch to false once verified
EOF
# Install systemd service and start
vela setup
sudo systemctl enable --now velacd my-app
vela init --name my-app --domain my-app.example.com
# Edit Vela.toml → set deploy.server = "root@your-server-ip"cargo build --release
vela deploy ./target/release/my-appMIX_ENV=prod mix release
vela deploy ./_build/prod/rel/my_appSee docs/elixir-phoenix.md for the full guide.
[app]
name = "my-app"
domain = "my-app.example.com"
[deploy]
server = "root@your-server.example.com"
type = "binary" # or "beam" for Elixir
binary = "my-app"
health = "/health"
strategy = "blue-green" # or "sequential" for SQLite apps
pre_start = "bin/migrate" # runs before app starts; failure aborts deploy
post_deploy = "bin/notify" # runs after traffic swap; failure is logged only
[env]
DATABASE_PATH = "${data_dir}/my-app.db"
SECRET_KEY_BASE = "${secret:SECRET_KEY_BASE}"
[services.postgres]
version = "17"
databases = ["my_app_prod"]
# [services.nats]
# jetstream = true
# [build]
# remote = true
# command = "cargo build --release"| Command | Description |
|---|---|
vela serve |
Start the server daemon (Linux) |
vela setup |
Generate and install systemd service |
vela init |
Generate a Vela.toml |
vela deploy <artifact> |
Deploy an app |
vela status [--json] |
Show running apps (with live health, PID, uptime) |
vela logs <app> [-f] |
Tail app logs |
vela rollback [<app>] |
Roll back to previous release |
vela secret set <app> KEY=VALUE |
Set a secret |
vela secret list <app> |
List secret keys |
vela secret remove <app> KEY |
Remove a secret |
vela backup |
Trigger a manual backup |
vela apps |
List apps (server-side) |
Blue-green (default) — New instance starts alongside old. After health check passes, traffic swaps and old instance drains. True zero downtime.
Sequential — Old instance stops, new instance starts. Sub-second blip. Use for SQLite apps to avoid write contention during the overlap window.
- Listen on
$PORT— Vela assigns a random port (10000-20000). Your app must read thePORTenv var and bind to it. - Respond on your health path — If you set
health = "/health", return HTTP 200 within 30 seconds of startup. - Handle
SIGTERM— Vela sends SIGTERM for graceful shutdown, then SIGKILL after a timeout. - Use
$VELA_DATA_DIRfor persistent files — databases, uploads, anything that survives deploys.
- Getting Started — first install and deploy walkthrough
- Production Checklist — pre-flight checks, troubleshooting, ACME staging workflow
- Configuration — Vela.toml and server.toml reference
- Deploy Lifecycle — what happens during a deploy
- Architecture — system design, services, and internals
- Elixir/Phoenix Guide — deploying BEAM releases with services and remote builds
- Cloudflare Integration — using Cloudflare with Vela
All core functionality is built, tested, and working:
-
Single binary (server + client)
-
SSH-based deploy pipeline (tarball upload → extract → health check → swap)
-
Reverse proxy with domain-based routing (hyper)
-
Auto-TLS via Let's Encrypt (ACME HTTP-01 with SNI-based cert resolution)
-
Static TLS support (Cloudflare Origin Certs, custom certs)
-
Blue-green and sequential deploy strategies
-
Process manager with port allocation and graceful shutdown (SIGTERM → SIGKILL)
-
IPC daemon architecture (Unix socket for deploy coordination)
-
Filesystem-backed state (no database dependency)
-
Secret management (per-app, file-backed, mode 0600)
-
Environment variable substitution (
${data_dir},${secret:KEY}) -
Rollback to previous release
-
App restore on daemon restart
-
Log capture and streaming (
vela logs -f) -
Release sandbox (read-only release directories)
-
Elixir/Phoenix BEAM release support
-
systemd service generation with hardening (
vela setup) -
CI/CD pipeline with multi-platform release builds
-
Install script (auto-detects platform)
-
Process supervision with auto-restart on crash
-
Manifest env vars persisted across daemon restarts
-
Deploy hooks (
pre_startandpost_deploy) -
HTTP → HTTPS redirect (with ACME challenge passthrough)
-
ACME certificate auto-renewal (checks daily, renews at 30 days before expiry)
-
Service dependencies: Postgres lifecycle management (install, provision, DATABASE_URL injection)
-
Service dependencies: NATS lifecycle management (download, supervise, NATS_URL injection)
-
Service dependencies framework (ServiceManager with per-service state persistence)
-
Scheduled backups (app data, secrets, pg_dump — local or S3)
-
Remote build support (git archive upload, build on server)
-
Machine-readable status (
vela status --jsonwith live health probes, PID, uptime)
Coming next:
- Process isolation (Linux namespaces, cgroups v2)
- Resource limits (memory, CPU weight)
# Requires Rust 1.93+
cargo install --path .MIT