Skip to main content

22 Months, a $250 Bounty, and a Maintainer's No: What Coolify's Kubernetes Standoff Reveals About Multi-Machine Support

11 min readDora NodaDora Noda
Share
On this page

Twenty-two months. A $250 community bounty. Forty-six reactions. And one maintainer reply that ended the debate: Kubernetes support is not coming to Coolify — version 5 will ship a custom orchestration layer instead, in the maintainer's words, "like Swarm but better." Then a community contributor spent eight weeks proving the "impossible" part wrong by building working native Kubernetes deployments anyway.

That sequence — sustained demand, a principled refusal, and a volunteer proving feasibility from the outside — is the clearest public case study we have of what multi-machine support actually costs a single-box PaaS. Not the sticker price. The architectural price: the day your platform's core assumptions about "a server" stop being true, and every status check, deploy path, and UI flow built on those assumptions has to be re-thought. Here is the standoff in dated detail, why the maintainers' no was rational even though the community was right, and what each self-hosted PaaS concretely offers when you outgrow one machine.

The timeline: from feature request to working fork-energy in 22 months

DateEvent
Jun 2024Issue #2390, "Full Kubernetes support with autoscale," is opened. The ask is specific: run Coolify-managed workloads (apps, WordPress, databases) on Kubernetes, not run Coolify itself on K8s.
2024–2026A $250 bounty is posted on the issue via Algora, and reactions accumulate to 46 (36 hearts, 10 watchers at last count). For context, the older issue #45 asking for Kubernetes integration dates back to 2021 — the demand is really five years old.
Mar 14, 2026Contributor drtobbyas (8 years in DevOps, K8s specialization) comments offering to help build it, then asks the team directly on Discord. Core maintainer Peak replies: v5 will use "our own custom solution... that integrates directly with Docker Compose and uses Docker in the background, as it is more flexible and tightly integrated into Coolify, like Swarm but better."
Apr 14, 2026EP1 of a public investigation series: "They Said Kubernetes Isn't Coming to Coolify. I'm Going to Find Out If That's True." Its key observation: the maintainers made a product decision ("we will build X instead of Y"), not a technical claim ("Y cannot be built").
Apr 22, 2026EP2 maps Coolify's deploy pipeline and finds the SSH-native engine is "surprisingly cluster-friendly" — the architecture isn't locked to Docker, it just lacks a translation layer.
May 11, 2026EP3: native Kubernetes deployment is working. The proof of concept bootstraps a K3s cluster from the dashboard (or links an existing cluster) and deploys a Docker image as K8s Deployments, Services, and Traefik Ingress rules.

Two things about that $250 bounty are worth sitting with. First, it sat unclaimed through the entire 22 months — not because nobody wanted the feature, but because a bounty pays for a patch and this was never a patch-sized job. Second, the amount that finally "moved" the issue wasn't money at all: it was a volunteer deciding the question deserved an empirical answer. Bounties measure demand. They don't buy architecture.

The community's pro-Kubernetes case, fairly stated, was never "Kubernetes is trendy." It came down to four concrete gaps:

  • Autoscaling. Coolify's multi-server story spreads deployments across machines but doesn't scale them up and down against load. Issue #2390's title literally ends with "with autoscale."
  • Self-healing scheduling. If a node dies, somebody (or some script) must notice and reschedule. Kubernetes does this by default; a fleet of SSH-managed boxes does not.
  • Clusters teams already own. Shops running K8s elsewhere wanted Coolify as the developer-facing deploy layer on top of infrastructure they had — not a second, parallel fleet to babysit.
  • Adoption blocker. Multiple commenters said K8s support was the single feature gating their adoption. For them this wasn't a nice-to-have; it was the evaluation criterion.

The maintainers read all of that and still said no. That decision deserves a serious hearing, because it was probably correct on its own terms.

Why the maintainers said no: the cost is architectural, not political

Coolify's core is SSH-native and Docker-Compose-shaped. It connects to servers over SSH, writes Compose files, and shells out to Docker. Every deploy path, health check, log tail, and status pill in the UI assumes the unit of compute is a Docker daemon that answers synchronously: the container is running or it isn't, right now, on this host.

Kubernetes breaks that assumption at the foundation. Scheduling is eventually consistent — you create a Deployment and the pods may not exist for seconds while images pull and the scheduler places them. And the community proof of concept hit exactly this wall, which makes it Exhibit A for the maintainers' position rather than against it.

The EP3 author describes the failure mode precisely: run the deploy synchronously and the long K8s API wait holds the PHP process hostage, locking up the Coolify UI. Flip it to an async background job and the UI stays snappy — but Coolify's Application Status Checker instantly polls the K8s API, finds zero pods (they're still pulling images), and flags a perfectly healthy deployment as "Exited" or "Failed." The fix was a two-minute grace window: if the checker polls within two minutes of an update and finds zero pods, hold the status at "Starting" until the API confirms healthy pods.

Read that as an architect and the scope of "add Kubernetes support" snaps into focus. It's not one translation script. It's:

  • A second deploy engine (Compose-over-SSH and manifests-against-an-API) maintained in parallel, doubling the matrix of deployment types × targets for every future feature.
  • A second mental model of state (synchronous Docker truth vs. eventually-consistent cluster truth) threaded through status checks, rollbacks, log streaming, and every UI component that renders "is it up?"
  • A second support surface — CNI quirks, storage classes, RBAC, cluster upgrades — for a team whose entire value proposition is "simpler than Kubernetes."

And the payoff accrues mostly to users who have already outgrown Coolify's core persona: the team with one server (or a few) that wants Heroku ergonomics without learning orchestration. Saying yes would have meant taxing the simple path to subsidize the complex one. "Like Swarm but better" — a custom layer that keeps the Compose-shaped mental model while spreading work across machines — is the maintainers betting they can serve machine #2 and #3 without importing machine #50's complexity. Whether that bet pays off is an open question. That it was a coherent bet is not.

What "multi-server" concretely means in each tool today

Strip away the marketing and the three most-deployed single-box PaaSes answer "I need a second machine" three different ways:

CoolifyDokployCapRover
Container modelDocker + Compose over SSHDocker Swarm + Traefik (Swarm initialized even on one node)Docker Swarm + Nginx
Multi-server topologyMultiple standalone servers from one dashboard; shared Docker registry; Traefik instance per serverSwarm cluster: manager on the Dokploy host, workers join with docker swarm joinSwarm cluster across joined nodes
Cross-node schedulingNo — you pick which server a deployment lands onYes — Swarm schedules services across the clusterYes, via Swarm
Clustering maturitySwarm mode labeled experimentalFirst-class, no experimental flag; v0.29 added non-root multi-server SSHFirst-class (Swarm is the whole model)
Machine lifecycleBring your own server, register it over SSHBring your own server, join it to the SwarmBring your own server, join it to the Swarm

The honest one-line summary: Dokploy and CapRover will use your extra machines as a cluster; Coolify will manage your extra machines as individuals. Neither answer provisions a machine for you. Every row in that table starts with a server you created, hardened, and networked yourself — the platform takes over only after SSH works.

What concretely breaks at machine #2

This is the real cost the title promises, itemized. When a team that adopted a single-box tool for its first app needs a second machine, here is the bill that comes due — regardless of which tool they picked:

  1. No declarative machine lifecycle. There is no manifest that says "this fleet is three machines of this shape" that the platform reconciles. Adding capacity is a ticket: provision a VM, install Docker, harden it, register it. Removing capacity is the same ticket in reverse, with extra fear. The fleet's shape exists in somebody's head and a wiki page.
  2. No fleet-wide provisioning. The platform manages containers on machines, not machines themselves. OS upgrades, Docker version skew across nodes, firewall rules, and disk-full scenarios are your automation's problem — and most teams arriving at machine #2 have no automation, because machine #1 never needed any.
  3. Networking becomes a DIY project. Coolify's per-server Traefik instances need something in front of them to be one service; community guides recommend anything from DNS round-robin (no health checking — a dead server still receives traffic) to a hand-rolled load balancer. Swarm-based tools get overlay networking and routing mesh for free, which is genuinely better — but you're still the one who joined the nodes, opened the Swarm ports, and secured the join tokens.
  4. State has no story. Databases and volumes live wherever they landed. Failover for a stateful workload across machines is not a button in any of these dashboards; it's a runbook you write yourself, usually at 2 a.m. for the first time.
  5. Drift has no detector. Nothing continuously verifies that machine #2 still matches machine #1's configuration six months later. The fleet converges toward snowflakes at exactly the rate your discipline decays.

None of this is a criticism of these tools. Every item on that list is out of scope by design for software that optimizes for "push to one server in five minutes." The cost appears only at the transition — and the transition always arrives disguised as a small request ("can we just add one more box for staging?") that turns out to be an architecture change.

The other bet: declare the machines, reconcile the drift

There is a model that answers machine #2 before it's asked: treat machines as declarative API objects, the same way Kubernetes treats pods. That's Cluster API's whole thesis — a MachineDeployment says "three nodes of this shape," controllers provision them against your infrastructure provider, health checks replace the sick ones, and drift between declared and actual state is something the system repairs rather than something you discover.

The contrast with the table above is sharp. In the single-box world, the platform starts where SSH starts, and everything below SSH is yours. In the Cluster-API world, the platform starts at the machine: node images, provisioning, upgrades, and replacement are API operations with desired-state semantics. That doesn't make it simpler — nobody sane calls running a management cluster "simple" — but it moves the complexity to day one, when you're choosing it deliberately, instead of smuggling it into the day you add machine #2, when you're choosing it under pressure.

This is the bet bex is built on: that declarative multi-machine was worth building in from day one rather than bolted on after outgrowing a single-server design. Push a git repo, get a running HTTPS service — on machines the platform itself provisions and reconciles, whether that's one node or fifty.

What to watch next

Three open threads will decide how this story ends. First, Coolify's v5 custom orchestration: if "like Swarm but better" ships a genuinely smooth second-machine experience inside the Compose mental model, the maintainers' no becomes one of the best product calls in self-hosted PaaS history. Second, the community Kubernetes work: a maintained fork or plugin with native K8s deploys would split the ecosystem into "simple Coolify" and "cluster Coolify," and ecosystem splits have a way of becoming permanent. Third, the Swarm question underneath both: Dokploy and CapRover's clustering story rests on an orchestrator whose mindshare shrinks every year, maintained but no longer where the industry's energy goes.

The deeper lesson survives whatever happens to any one project. Multi-machine support is not a feature you add; it's an architecture you either start with or migrate to. The $250 bounty didn't fail because $250 was too little. It failed because no bounty can buy a different foundation — and foundations are chosen on day one, whether you meant to choose one or not.

Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own. Star the repo on GitHub or deploy your first app today.

Related articles

Run this on infrastructure you own

bex is the open-source, AI-native Render alternative — push a git repo and get a running HTTPS service on your own machines.

Get started with bex