Skip to main content

Woodpecker CI's 130MB Control Plane vs a 7GB GitHub Runner: What Your PaaS Build Step Really Costs on a €3.79 Hetzner Box

9 min readDora NodaDora Noda
Share
On this page

A self-hosted Woodpecker CI control plane idles at around 130MB of RAM — roughly 100MB for the server, 30MB for an agent. GitHub's own unit of build capacity, the standard hosted runner, is a 2-core VM with 7GB of RAM. And a team burning 20,000 Actions minutes a month on a Team plan pays on the order of $136 in overage — against a Hetzner CX22 with 2 vCPUs and 4GB of RAM that costs €3.79 a month. Those three numbers are the whole argument for running your PaaS build step in-fleet, and the rest of this post is the receipt: where every megabyte goes, what the same box looks like under GitHub Actions, and the sizing rule that falls out.

One correction up front, because the folk number floating around is wrong. Woodpecker's combined footprint is often quoted as "under 50MB." Upstream's own README puts idle usage at around 100MB for the server and 30MB for the agent, and the current administration docs list 200MB / 1 CPU for the server and 32MB / 1 CPU for the agent as minimal requirements. The under-50MB figure roughly matches a lone agent, not the pair. It hardly matters — 130MB is still a rounding error on any box you'd run builds on — but a post about concrete numbers should start with correct ones.


Where Woodpecker's megabytes actually go

Woodpecker is a community fork of Drone CI: a Go server that schedules pipelines and a set of agents that execute them, with pipelines declared in .woodpecker.yaml and every step run as a container. It speaks Forgejo, Gitea, GitHub, GitLab, and Bitbucket natively, defaults to SQLite, and is the engine behind Codeberg's own "Codeberg CI" — which is about as strong a reference workload as a lightweight CI gets, since Codeberg serves hundreds of thousands of projects off it.

The idle budget for the control plane breaks down like this:

ComponentIdle RAM (upstream figures)Notes
Woodpecker server~100MBGo binary, SQLite by default; 200MB listed as minimal requirement
Woodpecker agent~30MBPer agent; 32MB listed as minimal requirement
Control-plane total~130MBBefore a single pipeline runs

The important row is the one that isn't in that table: the build containers. The moment a pipeline runs, Woodpecker pulls images and executes steps in Docker containers on the agent's host, and those containers cost whatever your build costs — a Go or Rust compile with a warm layer cache, a Node install, a Playwright shard. A realistic range is 300–500MB for a lint-and-unit-test job and 1–2GB at peak for a container image build pushing layers. The control plane never becomes the sizing driver. Whatever CI you choose, the build is what eats the box — which is exactly why the runner comparison has to be done at the node level, not the daemon level.


The other side of the ledger: what GitHub charges for the same builds

GitHub Actions looks free until it isn't. The included quotas are 2,000 minutes a month on the Free plan, 3,000 on Team, and 50,000 on Enterprise — and everything past that is metered per minute. Linux overage on the standard 2-core runner runs roughly $0.006–0.008 a minute. GitHub revised Actions rates effective January 1, 2026, folding in a $0.002-a-minute platform charge, so treat the pricing page as the number of the month — the order of magnitude is what matters here.

Take a concrete high-volume workload: a team crossing roughly 20,000 minutes a month. On a Team plan that is 17,000 overage minutes, or on the order of $100–136 a month in overage alone — metered, uncapped, and growing with every new service, matrix leg, and Playwright shard the team adds. Against that, a Hetzner CX22 — 2 vCPUs, 4GB of RAM, 40GB of disk — costs €3.79 a month, and the next box up, the 4-vCPU/8GB CX32, costs €6.80. The metered bill for one busy month buys roughly three years of the bigger box.

The honest version of this math cuts both ways, and the next section keeps it honest: those included minutes are genuinely free capacity, and a team sitting comfortably inside 3,000 minutes with bursty, parallel-heavy workloads is renting burst parallelism from GitHub's fleet that no single CX22 can match. The crossover is for the team whose usage is high, steady, and predictable — exactly the shape where owning capacity beats renting it.


Head-to-head on the same box

Here is the comparison the title promises, both stacks on one CX22 (2 vCPUs, 4GB of RAM, €3.79 a month), each running a forge plus one concurrent image-build slot. Base figures are approximate idle usage; the build row is peak working set.

ResidentWoodpecker stackSelf-hosted GHA runner stack
OS + container runtime~400MB~400MB
Forge (Forgejo)~150MB~150MB
CI control plane on the box~130MB (server + agent)— (GitHub hosts it; you pay per minute instead)
Runner/agent footprint~30MB (included above)One runner host per runner, provisioned at job scale
One image-build slot, peak~2,048MB~2,048MB (same build, same cost)
Node total~2.7GB of 4GBDoes not fit the reference shape

That last cell needs unpacking, because it is the whole point. GitHub's own reference unit of build capacity — the standard hosted runner — is 2 cores, 7GB of RAM, and 14GB of disk. To self-host an equivalent runner you provision an equivalent unit: on Hetzner that starts at the CX32 class (€6.80 a month) before the OS and the runner agent itself, and each additional concurrent runner wants another unit.

Woodpecker's agent, at ~30MB, is capacity you share; a GHA runner host is capacity you pin. The delta row of this table is therefore not megabytes but architecture: ~130MB of shared control plane versus one 7GB-class host per concurrent runner.

Note what is identical in both columns: the build. A 2GB image build costs 2GB wherever it runs. Switching runners never made builds cheaper — it moves the control plane from GitHub's meter onto a box you own, where it costs €3.79 a month instead of $100+.

Sensitivity: where the single-point comparison breaks

One box and one build size flatter any comparison, so here is the same Woodpecker stack across two build sizes and two concurrency levels (base ~680MB for OS, runtime, forge, and control plane):

Build shape1 slot: node total2 slots: node total
Lint + unit tests (~400MB each)~1.1GB — CX22 comfortable~1.5GB — CX22 fine
Image build, peak (~2GB each)~2.7GB — CX22, ~1.3GB headroom~4.8GB — exceeds CX22 → CX32 (€6.80)

Two conclusions survive the sensitivity check. First, the step-up is driven entirely by build concurrency and build size — the control plane's 130MB never appears in the decision. Second, the worst cell in this table is a €6.80 box, and it still costs less than a single month of the overage bill from the previous section. The sizing rule for a git-push PaaS's build step writes itself: size the box for the build, share the control plane, and let CI be the cheapest resident on the node — because that is the only thing a lightweight runner can promise, and it is enough.


What Woodpecker doesn't give you

The strongest case against switching has three parts, and each is real. First, burst parallelism: GitHub's fleet absorbs fifty PRs landing at once without a queue; a single CX22 absorbs exactly as many builds as it has slots, and the rest wait. If your load is spiky rather than steady, the queue will teach you the price of owned capacity on the worst possible day. Second, the marketplace: thousands of prebuilt Actions versus Woodpecker's smaller plugin catalog — anything exotic becomes a container you write and maintain yourself. Third, the maintenance you inherit: runner updates, image-cache pruning, disk-full-at-2am pages. GitHub's per-minute price bundles an ops team; the €3.79 box does not.

So do not switch when your usage sits inside the included minutes, when builds arrive in bursts that would queue on fixed capacity, or when your pipelines depend on marketplace Actions nobody on your team wants to reimplement. The Forgejo-plus-Woodpecker pairing — the same stack Codeberg runs, and the migration path a visible stream of teams documented through 2026 — wins for steady, high-volume builds on infrastructure you already own, where the meter runs constantly and the queue stays shallow. That is also, not coincidentally, exactly the shape of a git-push PaaS's own build fleet.

Sources

  • Woodpecker CI README and administration docs (idle footprint ~100MB server / ~30MB agent; minimal requirements 200MB server / 32MB agent) — github.com/woodpecker-ci/woodpecker
  • GitHub docs: hosted runner hardware (2-core, 7GB RAM, 14GB SSD) and Actions billing (2,000 / 3,000 / 50,000 included minutes; per-minute overage) — docs.github.com and 2026 pricing changes
  • Hetzner Cloud CX plans (CX22: 2 vCPU, 4GB, €3.79/mo; CX32: 4 vCPU, 8GB, €6.80/mo) — hetzner.com/pressroom/new-cx-plans
  • Codeberg runs Woodpecker CI as "Codeberg CI"; Forgejo dogfoods Woodpecker for PR checks — codeberg.org, Forgejo release notes
  • Migration notes: GitHub Actions to Woodpecker walkthroughs and self-host write-ups — dev.to, robinmetral migration notes

Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own. The build step behind that push has to live somewhere, and the cheapest place for it is a box you already pay for by the month, not a meter you pay by the minute. 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