One server is a Jokku.
Two is a cluster.

Jokku runs your apps on servers you own, with Dokku's commands and its git push. Every instance boots in its own Firecracker microVM, and when you want another server, it joins with one command. From then on your apps spread across all of them — and move by themselves when one dies.

Free and open source · No account, no paid tier · Ubuntu or Debian with KVM

shop web 3/3·3/3 up·14:02:00
# three servers, one cluster: shop (three web, one worker), its cache and its Postgres
$
server-1control
ready
shop web.1cache web.1
server-2worker
ready
shop web.2postgres-shopdb postgres.1
server-3worker
ready
shop web.3shop worker.1
shop web=3

Pull the plug on server-2, drain one, or add a server and scale up.

A cluster you can be unkind to. Every line it prints is a line Jokku prints; the # lines are narration.

Free. All of it.

No paid tier, no cluster edition, no account. Clusters, backups, edges and databases ship in the same single binary as everything else, and the source is on GitHub.

Dokku's commands, kept as-is.

The same command names, argument order and -----> output. If you have a Dokku box, you already know how to use this — and your laptop still needs nothing but git and ssh.

A microVM for every instance.

Each instance boots in its own Firecracker VM, with its own kernel — what AWS built to run Lambda. Restarting or updating Jokku leaves every one of them running.

The cluster

A second server is one command.

There is no multi-server mode, and nothing to configure for one. A cluster is the same Jokku with more servers in it. Ask the first for a join command, paste what it prints into a fresh box, and that box is in: on an encrypted WireGuard mesh, taking traffic, and running apps.

The first server is the control node. It keeps the cluster's state and takes your pushes. If it goes down, the others keep serving what they have; you just can't deploy until it's back — or until restore-cluster rebuilds it from its hourly backup.

# on server-1
$ jokku cluster:join-command
=====> Run this on the new server (works once, until 15:02 UTC):
curl -fsSL …/install.sh | sudo JOKKU_VERSION=v0.8.17 sh -s -- --join 203.0.113.10:7443 --token JOKKU1…
# on server-2, a fresh box
$ curl -fsSL …/install.sh | sudo … --join 203.0.113.10:7443 --token JOKKU1…
# a minute later, back on server-1
$ jokku nodes:list
NAME ROLE STATUS ADDRESS MESH IP CPUS MEMORY INSTANCES VERSION
server-1 control ready 203.0.113.10 10.210.1.1 8 16g 3 v0.8.17
server-2 worker ready 203.0.113.11 10.210.2.1 8 16g 2 v0.8.17

Apps spread themselves out

A new instance goes to the server with memory free that runs the fewest of that process, so ps:scale myapp web=3 on three servers puts one on each.

Every server takes traffic

Caddy is built into every node and knows every app's domains, so DNS can point at as many of them as you like.

Apps find each other by name

cache.internal reaches the cache app from any app, on whichever server it is on today, over the WireGuard mesh.

Maintenance without downtime

nodes:drain starts a copy of each instance elsewhere, waits for it to pass checks, then stops the original.

Disks move with their apps

A volume is copied while its app keeps running, then a short pause for the last writes. A database never moves without its data.

One update for all of them

sudo jokku update on the control node updates itself, then every other server, one at a time, while your apps keep serving.

When a server dies

Nobody gets paged. Things just move.

A database never moves without its disk: one with a volume waits for its server, unless the volume is backed up — then it comes back somewhere else from the latest backup. A server that was only cut off stops those apps itself first, so two copies of a database never both think they're the real one.

  1. +0s

    A server goes quiet

    Power, network, a kernel panic — it stops reporting in.

  2. +30s

    Marked down

    Every proxy stops sending it requests. Until then, a request that can't reach it retries on another instance.

  3. +1m 30s

    Its apps start elsewhere

    A minute's grace so a reboot doesn't shuffle anything, then its instances boot on the others.

  4. +5m

    Its databases come back

    Backed-up volumes are restored onto another server from their latest backup, and their apps start there.

jokku top

Watch every request land.

jokku top is the whole cluster, live, in your terminal. Press 6 and every request flies across its app's lane — green, cyan for a redirect, yellow for a 4xx, red for a 5xx — and lands on the instance and server that answered. A slow one crawls, trailing amber. A failure bursts where it lands.

Tour jokku top
ssh -t jokku@server-1 top
jokku top  ·  control server-1  ·  v0.8.17  ·  4/4 nodes  ·  3 apps  ·  7/7 instances healthy  ·  updated 1s ago
1 Overview2 Nodes3 Apps4 Instances5 Events6 Traffic7 Backups8 Databases9 Firewall
26.4 req/s·p50 5.2ms  p95 22ms·0.4% errors·18204 total
last hour p50 4.9ms  p95 21ms  97k requests   ·   last 24h p50 4.6ms  p95 24ms  2.3M requests
req/sp95
api2 ●●15.0/s▶web.1@server-1 ▮▮▮▮▮▮ 7.6/sweb.2@server-2 ▮▮▮▮▮▮ 7.4/s
blog1 ●2.4/s▶web.1@server-3 ▮▮▮▮▮▮ 2.4/s
shop4 ●●●●9.0/s▶web.1@server-1 ▮▮▮▮▮▮ 3.1/sweb.2@server-2 ▮▮▮▮▮▮ 3.0/s+1 more
web3 ●●●
worker1 ●
requests by node  edge1 22.4/s  ·  server-1 1.4/s  ·  server-2 1.3/s  ·  server-3 1.3/s
Recent requests
1-9/tab views  p pause  c clear  f effects  ? help  q quit

Drawn the way the real one draws it, from internal/tui/traffic.go; the requests are made up in your browser.

Edges

Serve the internet from home, with every port closed.

An edge is a small public server — the cheapest VPS will do — that takes your domains' traffic and carries it home over the WireGuard mesh. Your servers dial out to it, so the router stays shut.

It's part of the cluster, so it already knows every app's domains and certificates: domains:add and letsencrypt:enable are the whole job, with nothing to set up anywhere else. Things Jokku doesn't even run, like Home Assistant or a NAS, become apps with external:create.

$ jokku edge:add root@203.0.113.7 # installs it over ssh
$ jokku external:create ha http://192.168.1.50:8123
$ jokku domains:add ha ha.example.com
$ jokku letsencrypt:enable ha
$ jokku http-auth:enable ha --password # a login in front
the internet
shop.example.com
ha.example.com
198.51.100.23 GET /.env
https
edge1203.0.113.7
a $5 VPS · no KVM, no apps
certificatesroutesloginsfirewall
✖ 198.51.100.23 banned for 1h
it never reaches home
WireGuard
↑← home dials out
homerouter: 0 ports open
server-1control
shop web.1api web.1
server-2worker
shop web.2api web.2
server-3worker
shop web.3blog web.1
→ hahttp://192.168.1.50:8123Home Assistant, via server-1

The smallest server will do

An edge needs no KVM and runs no apps. It wants TCP 80 and 443 and UDP 443 and 51820 open, and that's all. Add a second in another region and point DNS at both.

It reaches only what it routes

Over the mesh it gets your servers' web proxies, your apps' web ports, what you route to it and the API it fetches its routes from. Not ssh, not other machines on your network, and never an app's code or your backups.

Scanners stop there

The firewall runs in the first proxy a visitor reaches, so a bot hunting for /.env is banned at the edge and its requests never travel up your home connection.

Edges and home labs

Getting started

From a bare server to HTTPS in four commands.

Bring a fresh Ubuntu or Debian server with KVM — bare metal, or a VM with nested virtualization on. The installer does the rest, and the SSH keys you logged in with can deploy straight away.

  1. 01

    Install

    $ curl -fsSL …/install.sh | sudo sh

    Your SSH keys can deploy straight away.

  2. 02

    Push

    $ git push jokku main

    Your Dockerfile, built and booted, with a URL.

  3. 03

    Add a domain

    $ jokku domains:add myapp myapp.com

    Point DNS at any server you have.

  4. 04

    Turn on HTTPS

    $ jokku letsencrypt:enable myapp

    Issued, renewed and redirected for you.

Coming from Dokku

If you know Dokku, you already know Jokku.

Dokku got the important part right: a git push and a dozen commands, the right size for one person with a lot of small apps. What it can't do is use more than one server — every Dokku box is an island, with its own apps and its own idea of what's running.

Jokku keeps the commands and drops the island. What changes is where your apps run, and how many servers they can use.

Areadokkujokku
ServersOneAs many as you add
Runs apps inContainersFirecracker microVMs
A server diesSo do its appsThey start on the others
storage:mountA host directoryA disk that moves with its app
Databasespostgres:* pluginsdb:postgres:*, built in
Behind NATOpen your portsAn edge your servers dial

Also in the box

Everything a platform does, on hardware you control.

Even at home, behind a router with every port closed. All of it is in the one free binary, and all of it works the same on one server or ten.

Zero-downtime deploys

New instances take traffic once they pass checks. A failed deploy is rejected and the old one keeps serving.

Dockerfiles, compose, images

Build a Dockerfile, deploy a whole compose file, or run any image from a registry.

Postgres, MySQL and Redis

One command each, linked to your app with a URL, on a volume of their own.

Backups that restore themselves

Every 15 minutes, incremental and encrypted, to any S3-compatible bucket.

Apps that sleep

ps:set myapp sleep-after 15m stops an idle app's microVMs. The next request wakes it, held at the proxy while it boots.

A login in front of anything

A shared password, or users with authenticator codes, before any app. Nothing to change in it.

A firewall, on by default

Scanners hunting for /.env and /wp-login.php get banned for an hour, with nothing to set up.

Logs and a shell, anywhere

Follow every instance and every request in one stream, or open a shell inside a running microVM with jokku enter.

The full tour is on jokku.dev

Free, and the source comes with it.

Run this on a fresh server with ports 80 and 443 free. Then run jokku cluster:join-command on it when you want the next one.

$curl -fsSL https://raw.githubusercontent.com/wes/jokku/main/install.sh | sudo sh

185 installs and updatesacross 33 releases since 7 October 2026

Jokku is young and moving fast. The Firecracker jailer isn't on yet, so treat apps on one server as trusting each other, as you would on Dokku — and check what works today before you move anything important.