There is a myth that a real cluster is expensive. People hear "cluster" and picture a rack of machines, a managed service with a monthly bill in the tens or hundreds of dollars, and a load balancer charge on top. So they stay on a platform they are outgrowing, or they never start, because the entry ticket looks like 60 to 100 dollars a month before their app has served a single request.

That entry ticket is not real. A single small VPS, the kind you can rent for about 5 to 12 dollars a month, is a genuine cluster the moment you put k3s on it. And Burrow runs on that one small box exactly the way it runs on a big managed cluster: the same commands, the same deploys, the same publish and TLS. Nothing about the workflow gets a "cheap tier" asterisk.

This post walks the whole on ramp. Pick a small VPS, do one SSH bootstrap, and from that point on operate everything from your laptop. We will cover the memory preflight and why it exists, how you get a free load balancer out of the node's own public IP, how you publish an app at a real domain with a certificate, and how the cost stays flat as you pile more apps onto the same box. We will also be honest about what one machine cannot do, and what you do about that when you outgrow it.

What "a cluster" actually means here

Let us clear up the word, because it is doing a lot of scary work in people's heads. A cluster is just one or more machines that run your apps under a scheduler. The scheduler is the part that keeps your app running, restarts it if the process falls over, and rolls a new version out cleanly. That is it. There is no rule that says a cluster needs three machines, or five, or a managed service to babysit it.

k3s is a small, complete Kubernetes distribution that fits comfortably on a single modest server. It gives you a real scheduler and a real API on one box. When Burrow installs onto it, you get the full experience: deploy by image reference, health checks, rolling updates, scaling, publish with TLS. A single node cluster is a real cluster. It is just a small one, and small is exactly right when you are starting out.

A "node," by the way, is just a machine in your cluster. One VPS is one node. When we say you can add nodes later, we mean you can add more machines to the same cluster when you need them. You do not have to think about that on day one.

Step 1: pick a small VPS

Almost any provider works, because all you need is a plain Linux machine you can SSH into and that has a public IP. Hetzner, DigitalOcean, Linode, Vultr, a small instance at any of them is fine. The one number that matters is memory.

Get at least 2GB of RAM. That is the floor, and it is a real floor, not a suggestion. k3s plus the part of Burrow that runs on the cluster plus your own app all need to live in that memory, with headroom to spare. On a 1GB box you can get k3s up, but you are one busy moment away from the machine running out of memory and killing something important, which is a miserable way to learn this lesson. 2GB gives you room. If your app is memory hungry, size up from there, but 2GB is where you start.

You do not need anything else provisioned. No managed load balancer, no managed database, no extra networking. A bare VPS with a public IP and 2GB of RAM is the whole shopping list. This matters for the cost story: the machine is the bill, and there is nothing bolted onto the side of it running up charges.

Step 2: one SSH bootstrap, and only one

This is the single time you touch the box directly. SSH into your new VPS and run the bootstrap:

# on the VPS, over your own SSH session, once
curl -fsSL https://burrow-cloud.dev/bootstrap.sh | sh
burrow cluster bootstrap

The bootstrap installs k3s and the part of Burrow that runs on the cluster, waits for the cluster API to come up, and then prints a join line that looks like this:

Your cluster is ready.

Run this on your laptop to operate it:

  burrow join eyJhbGciOi...token...

Copy that burrow join line, run it on your laptop, and you are done with SSH. From that moment on, every operation runs from your laptop: deploy, status, logs, scale, publish, rollback. You do not SSH back into the box for day to day work. The one bootstrap is the last time you log into the server by hand.

That is the whole point of the design. You do the messy one time setup once, over a channel you already trust (your own SSH key), and then you get a clean laptop driven workflow that looks identical to operating a managed cluster.

The 2GB preflight, and why it stops you

Before the bootstrap turns your machine into a node, it runs a preflight check and shows you a short memory breakdown. If the box has less than 2GB of RAM, it tells you plainly instead of charging ahead:

Preflight: checking this machine can host a cluster.

  total memory ......... 1.9 GB
  k3s needs ~ .......... 512 MB
  burrowd needs ~ ...... 256 MB
  headroom for apps .... the rest

This machine has less memory than recommended (2 GB).
Continue anyway? [y/N]

The check exists because the worst failure mode on a tiny box is silent. Everything installs, everything looks fine, and then a week later the machine runs out of memory under load and the scheduler kills your app to save itself. That is a hard problem to diagnose after the fact. The preflight moves that discovery to the front, before you have anything running, where the fix is simply "pick a slightly bigger box." It also asks you to confirm before it converts the machine, so a bootstrap is never something that happens to a server by accident.

The bootstrap also waits for the cluster API to actually come up before it hands you the join token, so the token it prints is a token that works. You are not handed a credential for a cluster that is still booting.

Step 3: a free load balancer from the node's own IP

Here is where the cost myth usually reasserts itself. On the big managed clouds, the moment you want traffic to reach your app from the internet, you provision a load balancer, and that load balancer is its own line item, often 10 to 20 dollars a month on its own. People assume a cluster requires one. It does not.

Your single node already has a public IP. That IP can serve your app directly, for free, using the load balancer that ships inside k3s (servicelb) or MetalLB if you prefer. Burrow detects these as real load balancer providers and uses them, so when your app needs an address, it gets the node's public IP with no cloud load balancer bill attached. When you publish, Burrow reuses the ingress controller already running in the cluster rather than standing up new paid infrastructure.

The result is that the machine you are already paying for is also your load balancer. There is no second charge for the privilege of being reachable. On a single node this is not a compromise, it is just how the traffic gets in, and it is free.

Step 4: deploy an app

Nothing here is special to the cheap setup. This is the same flow you would run against any cluster, which is exactly the promise. Build your app image, push it to a registry your cluster can pull from, and deploy by reference:

docker build -t ghcr.io/you/web:1.0.0 .
docker push ghcr.io/you/web:1.0.0
burrow app deploy web --image ghcr.io/you/web:1.0.0

Burrow rolls out the workload and reports back:

deployed web as release 35241b6b... (image ghcr.io/you/web:1.0.0, 1 replica, deployed)

Your app is now running on your one node cluster, self healing if the process falls over, ready to roll cleanly the next time you ship. Check that it is healthy the same way you would anywhere:

burrow app status web
burrow app logs web

If a config value or a secret is missing, the logs say so in the last few lines. You set it, redeploy, and it comes up. There is no cheap tier version of this loop. It is the loop.

Step 5: publish at a real domain, with TLS

Right now the app runs inside your cluster. To serve it at a real domain with a certificate, publish it:

burrow app publish web --host app.example.com --port 8080 --tls

That routes app.example.com to your app and requests an HTTPS certificate for it, using the free load balancer and the cluster's existing ingress. Point your domain's DNS at the node's public IP, then watch the chain come up:

burrow app reachability web --wait

The --wait flag polls until the app is actually live, walking the chain link by link: is the route in place, is there an address, has the certificate issued, does DNS resolve. If a link is not ready, it names that link, so "the cert has not issued yet" is a status you can read rather than a mystery. When it comes back green, open https://app.example.com. That is your app, live over HTTPS, on a box that costs you less than a couple of coffees a month.

The part that makes this worth it: the flat ceiling

Now the interesting bit. You have one small VPS, and one app on it. What happens when you deploy a second app? And a third?

You run burrow app deploy again with a different app name. It lands on the same box. It gets served by the same free load balancer. You publish it at its own domain with its own certificate. And your bill does not change, because your bill is the VPS, and the VPS is already paid for. As long as the machine has memory to spare, more apps cost you nothing extra at the platform level.

This is the real shape of the argument, and it is worth being precise about, because the honest version is more convincing than the hype version.

For one genuinely small app, a managed platform as a service usually wins today. As of July 2026, a small app on a PaaS with a free managed database tier can run for around 5 dollars a month, sometimes less, and you do not operate anything at all. If you have exactly one small app and no plans for more, that is a good deal, and you should take it. We are not going to pretend a cluster is cheaper than a 5 dollar PaaS on day one. It is not.

The math changes at the second and third app. On a PaaS, each new app tends to add its own line item, its own database charge, its own bandwidth meter, and the total climbs with every thing you run. On a box you own, the second and third app ride the machine you already have. The cluster has a higher floor (you pay for the whole VPS even when it is nearly idle) but a flat ceiling (many apps at no marginal platform fee). Somewhere around the third app, the box you own gets cheaper than the platform you rent, and it keeps getting relatively cheaper from there.

That crossover is the whole pitch for the developer this on ramp is built for: someone who is going to run several small things, wants to own where they run, and would rather pay for one box than a growing stack of per app charges. If that is you, the cheap VPS setup is not a downgrade you tolerate until you can afford "real" infrastructure. It is the real infrastructure, sized honestly to where you are.

Being honest about one machine

A single node is one machine, and one machine can fail. If that VPS has a bad day, reboots, or your provider has an outage in that region, your apps go down with it, because there is no second node to catch them. This is the genuine tradeoff of the cheap setup, and it would be dishonest to paper over it. A single node cluster has no node failure redundancy: it is one box, and one box is a single point of failure.

For a lot of what the target developer runs, side projects, internal tools, small production apps where a rare few minutes of downtime during a reboot is survivable, that is a completely acceptable tradeoff for the price. For a few things it is not, and you will know which is which. The good news is that the answer when you outgrow one box is not "throw it away and start over on a managed cluster." The answer is: add a node.

Growing past one box, when you are ready

Remember the join token from the bootstrap. Adding a second machine to your cluster is the same move you already made. Stand up another VPS, and join it to the cluster you already have:

# on the new machine, once
burrow join eyJhbGciOi...token...

Now your cluster has two nodes, and the scheduler can spread your apps across both. If one machine fails, the other keeps serving what it can. You scale a busy app across the extra capacity the same one command way as always:

burrow app scale web 3

You did not migrate anything. You did not rebuild your apps, re point your domains, or learn a new workflow. You added a machine to a cluster that was already real, and everything you had kept running. That is the reward for the single node cluster being a genuine cluster from the start rather than a toy that you eventually replace: growth is additive, not a do over.

The small clusters get some care under the hood for exactly this reason. When you add a managed database, the Postgres configuration and its memory limits are tuned to sit comfortably on a small box rather than assuming a large one, and the database wait retries are faster so a small cluster does not leave you staring at a spinner. The intent is that the cheap setup feels solid, not like a stripped version that constantly reminds you it is cheap.

What you actually did

Look back at the arc. You rented a small machine for the price of a couple of coffees. You ran one bootstrap over SSH, and from then on you operated everything from your laptop. You deployed apps by image reference, served them from the node's own public IP for free, and published them at real domains with real certificates. You added a second app and your bill did not move. And you know exactly what you would do the day you outgrow one box, because it is one more burrow join.

No 60 dollar entry ticket. No managed load balancer charge. No platform holding your apps on infrastructure you do not control. Just a machine you own, running a real cluster, operated from your laptop, flat in cost as you grow into it. That is the cheap VPS setup, and for the developer standing up their third app, it is the honest best deal on the table.