Vvoodu
How it worksManifestStackDocsFAQ
★ Star on GitHub
v0.9.2 · voodu apply, no git push

Self-hosted PaaS.
Commitless deploys.

Voodu is a Heroku-shaped, Kubernetes-honest deploy tool you run on your own boxes. One HCL file. One voodu apply. No git push, no bare repo, no plugin sprawl — apps, ingress with TLS, and stateful services that actually back themselves up.

★ Star on GitHubRead the docs ↗
MIT licensedLinux · macOSGo · Caddy · Docker100% self-hosted
1 filevoodu.hcl is the source of truth
1 commandvoodu apply does build, ship, route, swap
0 git pushestarball over ssh, content-addressed
TLS by defaultCaddy + Let's Encrypt, on-demand wildcards
// the manifest

One file describes the running system.

HCL out-of-the-box. No YAML to coerce, no Compose tricks, no chart-of-charts. Apps, ingress, and stateful services share the same shape — and the same blast radius.

voodu.hclHCL · 22 lines
// Ship a web app with TLS + 3 replicas behind a load balancer.
app "myapp" "web" {
  image    = "ghcr.io/myorg/myapp:latest"
  replicas = 3

  env = {
    PORT     = "8080"
    NODE_ENV = "production"
  }

  health_check = "/healthz"
  host         = "myapp.example.com"

  tls {
    email = "ops@example.com"
  }
}

// HA Redis: primary + sentinel cluster, declared, not orchestrated.
redis "clowk-lp" "redis" {
  replicas = 3
}

redis "clowk-lp" "redis-ha" {
  sentinel {
    monitor = "clowk-lp/redis"
  }
}
Two labels

scope + name, every kind

Every resource is keyed by (scope, name). Scope groups apps, envs or teams; name is unique inside it. The same key flows through diff, apply, and prune.

Out of the box

TLS, health, ingress — no plugins

Add tls{} and Voodu cuts a Let's Encrypt cert via Caddy. Add host and routing reconciles automatically. No Helm, no sidecars, no YAML blast radius.

Stateful, first-class

Postgres, Mongo, Redis declared like apps

HA Redis with a sentinel cluster is six lines. Postgres and Mongo plugins ship backup, replicas, and test-restore — the parts every PaaS leaves to you.

Upsert-only by default

No accidental deletions

apply only creates and updates. Resources missing from the file stay put. Want to clean up? --prune is the explicit opt-in, scoped per (scope, kind)so siblings of other types aren't touched.

// how it works

Laptop talks. Server reconciles.

The CLI streams your build context over SSH. The controller diffs it against embedded etcd, builds, swaps, and reroutes. It's k8s-shaped reconciliation without the k8s-shaped operations bill.

your laptop                                 your server
───────────                                 ───────────
$ voodu apply -f voodu.hcl  ──ssh──▶  voodu-controller
  │                                         │
  │                                         └─ reconcile ingress / services (etcd)
  │  (build mode only: stream tarball)
  └─ tar -czf - <path>     ──ssh──▶  voodu receive-pack
                                              └─ extract → build image
                                                 → swap `current` symlink
                                                 → run post_deploy hooks
                                                 → recreate container
01 — DECLARE

Write the manifest

One HCL file, or many. Apps, ingresses, databases, jobs — pick what you need, ignore the rest.

# voodu.hcl
app "prod" "api" { ... }
ingress "prod" "api" { ... }
02 — DIFF

See the plan first

voodu diff dry-runs the apply: what's new, changed, pruned. Wire --detailed-exitcode in CI to gate deploys.

$ voodu diff -f voodu.hcl
~ deployment/prod/api
  ~ replicas  1 → 3
+ redis/clowk-lp/redis-ha
03 — APPLY

Ship over SSH

Same flags, no surprises. Tarball is content-addressed — identical trees skip the rebuild and just repoint current.

$ voodu apply -f voodu.hcl -r prod-1
✓ apply complete in 11.8s
✓ 3/3 healthy
// cli

A small, k8s-shaped command surface.

Six verbs cover ~95% of day-to-day. Everything else is a plugin discovered from /opt/voodu/plugins.

Bootstrap a host
$voodu remote setup prod-1 ubuntu@host

SSH preflight + install + server-mode setup. Idempotent.

Create an app
$voodu apps create prod

Seeds /opt/voodu/apps/prod with a fresh .env.

Apply a manifest
$voodu apply -f voodu.hcl -r prod-1

Streams context over SSH, reconciles, swaps containers.

Preview drift
$voodu diff -f voodu.hcl --detailed-exitcode

Plan-style output. Exit 2 means changes pending.

Manage env
$voodu config set DATABASE_URL=… -a prod

Out-of-band secrets. Always wins over manifest env blocks.

Install a plugin
$voodu plugins:install thadeu/voodu-postgres

Drops a binary into /opt/voodu/plugins. Voodu wires it up.

// stack

Built on boring, well-loved parts.

Voodu is opinionated where it counts and pluggable where you'd want it to be. Postgres, Mongo, Redis, ingress — independent binaries, not a rewritten universe.

core
core

Go controller

Single static binary, embedded etcd, HTTP API on 127.0.0.1:8686.

core

Caddy ingress

Replaces NGINX. Caddy Admin API, ACME, on-demand wildcard TLS.

core

Docker builds

Bring a Dockerfile or let voodu auto-detect Go, Ruby, Rails, Python, Node.

core

SSH transport

Tarball over SSH. No daemons listening on the public internet.

plugins
plugin

voodu-postgres

Postgres with backup, replica and test-restore. Declared like an app.

plugin

voodu-mongo

MongoDB service with the same reliability primitives.

plugin

voodu-caddy

Reference plugin. Read it to write your own.

plugin

Build your own

Independent binaries discovered from /opt/voodu/plugins. Install via GitHub repo.

// faq

Questions devs actually ask.

Why HCL and not YAML?+
HCL is built for humans declaring infrastructure. Blocks, labels, and typed values map cleanly to kind/scope/name. Voodu is HCL-only — no YAML coercion, no indentation traps.
How is this different from Dokku, Coolify, CapRover?+
Those are excellent — and mostly git-push or click-driven. Voodu is declarative at the layer above: one file describes the system, diff shows the plan, apply reconciles. Stateful services are first-class, not bolted on as plugins-of-plugins.
Is it really commitless?+
Yes. voodu apply tars whatever directory you're in and streams it over SSH. No bare repo, no git push, no commit required. Edit, save, apply.
What about K8s?+
Voodu borrows the shape (declarative, reconciler, source-of-truth) and skips the operations bill (no CNI, no Helm chart, no kube-state-metrics dashboard). One controller, embedded etcd, done.
Does it scale beyond one host?+
Three prod boxes behind an ALB? Add three remotes and loop voodu apply -f voodu.hcl -r $r. Same manifest, different SSH targets. The controller is per-host and stateless about its peers — keep it boring.
How do secrets work?+
voodu config set stores env vars per-app, out-of-band from the manifest. config:set always wins over envblocks, so a runaway apply can't reset a production secret.
License?+
MIT. Self-hosted. No cloud tier, no usage telemetry, no rug pulls planned.

Stop deploying from a Slack thread.

★ Star on GitHub

MIT · v0.9.2 · made by @thadeu