Woodpecker CI, with no SaaS anywhere in the path

Server and agents on one small machine in Prague or Covilha, wired to your own forge - the version of CI where nothing about the pipeline leaves infrastructure you can name.

Tier III Certified ISO 9001 ISO/IEC 27001 ISO 14001 GDPR Compliant

Who it is for

A team that self-hosts everything else already

The forge is yours, the registry is yours, the deploy target is yours - and CI is the one hop that still leaves the building, which is exactly the hop that holds the source.

A Drone installation that stopped moving

Woodpecker is the fork that kept going and stayed Apache-2.0. The migration is small; the question is what to run it on.

A small team that wants CI to be boring

Two containers, a YAML file per repository, no control plane to learn and no per-minute counter to watch. It only needs somewhere to live.

What this shape gives you

  • Server and agents as two containers on one host, which is small enough that CI stops being an infrastructure project.
  • Any forge Woodpecker supports - GitHub, GitLab, Gitea, Forgejo or Bitbucket - including one you host yourself on the same network.
  • Agents added as separate hosts later, all authenticating to the same server, when one machine stops being enough.
  • Apache-2.0 throughout, so nothing in the pipeline depends on a vendor deciding to keep a free tier.
  • A static IPv4 from AS204057, so the forge webhook and the deploy target both have one address to trust.
  • Local NVMe for the workspace and the Docker layer cache, warm between pipelines.

Sized by what the pipeline actually does

Woodpecker itself is light: the server is a small Go process with an embedded database until you point it at Postgres, and the agent is a supervisor that starts containers. What consumes the host is the build, exactly as with any other runner - so size the machine from the heaviest job, and give the disk room for the layer cache that makes the second pipeline fast. The entry size below runs server and agent together comfortably for a small team. The one honest caveat: a flat monthly host costs the same on a week nobody pushes, where hosted CI minutes cost nothing.

A first runner
15.00
per month

Order Now
server and one agent together
2 vCPU
4 GB RAM
64 GB NVMe
1 static IPv4
1 weekly backup included
A team runner
19.96
per month

Order Now
server plus a couple of parallel workflows
4 vCPU
8 GB RAM
120 GB NVMe
1 static IPv4
1 weekly backup included
A busy pool
39.90
per month

Order Now
a dedicated agent host beside the server
8 vCPU
16 GB RAM
240 GB NVMe
1 static IPv4
1 weekly backup included

How to install Woodpecker CI with Docker Compose

Server and agent on one host, wired to GitHub in this example. Swap the forge block for the Gitea, Forgejo, GitLab or Bitbucket variables if your forge is one of those.

  1. Install Docker and Compose

    sudo apt install docker.io docker-compose-v2
    sudo systemctl enable --now docker

    Both containers and every pipeline step run on this daemon, so this is the only dependency the host needs.

  2. Register an OAuth application on your forge

    # GitHub: Settings -> Developer settings -> OAuth Apps -> New OAuth App
    # Homepage URL:     https://ci.example.com
    # Authorization callback: https://ci.example.com/authorize

    Woodpecker signs users in through the forge and reads repositories with that grant, so the client id and secret it hands back are what the server needs. Every supported forge has an equivalent form.

  3. Generate the shared agent secret

    openssl rand -hex 32

    The server and the agents authenticate to each other with this string, and Woodpecker documentation names this exact command for producing it. Keep it out of the compose file - put it in an .env file beside it.

  4. Write the compose file

    services:
      woodpecker-server:
        image: woodpeckerci/woodpecker-server:v3
        ports:
          - 8000:8000
        volumes:
          - woodpecker-server-data:/var/lib/woodpecker/
        environment:
          - WOODPECKER_OPEN=true
          - WOODPECKER_HOST=${WOODPECKER_HOST}
          - WOODPECKER_GITHUB=true
          - WOODPECKER_GITHUB_CLIENT=${WOODPECKER_GITHUB_CLIENT}
          - WOODPECKER_GITHUB_SECRET=${WOODPECKER_GITHUB_SECRET}
          - WOODPECKER_AGENT_SECRET=${WOODPECKER_AGENT_SECRET}
      woodpecker-agent:
        image: woodpeckerci/woodpecker-agent:v3
        command: agent
        restart: always
        depends_on:
          - woodpecker-server
        volumes:
          - woodpecker-agent-config:/etc/woodpecker
          - /var/run/docker.sock:/var/run/docker.sock
        environment:
          - WOODPECKER_SERVER=woodpecker-server:9000
          - WOODPECKER_AGENT_SECRET=${WOODPECKER_AGENT_SECRET}
    volumes:
      woodpecker-server-data:
      woodpecker-agent-config:

    This is the upstream example. WOODPECKER_HOST is the public URL users and webhooks reach, port 8000 is the web interface and 9000 is the gRPC port agents connect on. WOODPECKER_OPEN=true lets anyone with a forge account sign in - turn it off once your team is registered.

  5. Start it

    docker compose up -d
    docker compose logs -f woodpecker-agent

    The agent connects to the server with the shared secret and registers itself on first contact. If it loops on an authentication error, the two secrets do not match - most often because the .env file was not picked up.

  6. Add a pipeline

    when:
      - event: push
    
    steps:
      - name: smoke
        image: alpine:latest
        commands:
          - cat /etc/os-release
          - echo "built on $CI_MACHINE"

    Commit that as .woodpecker.yaml, enable the repository in the web interface so the webhook is created, and push. Each step is a container, which is why the agent needs the Docker socket.

Checked against the official documentation on 2026-08-15 — read the source

What we are not

  • We are not the Woodpecker project. Woodpecker CI is an independent Apache-2.0 project and nothing here is endorsed by it. We sell the machine it runs on.
  • We do not host your forge on this page. Gitea, Forgejo or a self-managed GitLab beside it is a straightforward second server, but it is a different size and a different quote.
  • We do not write your pipelines. The YAML is yours; the host, the network and the address are ours.
  • Woodpecker is not managed for you by default. You run the two containers, or you add our administration service and we keep them updated and backed up.
  • Mounting the Docker socket into the agent gives pipeline steps a great deal of power over the host. That is how this design works, and it is a reason to keep the agent on a machine that does nothing else.

The parts teams discover late

  • WOODPECKER_AGENT_SECRET has two modes. The same value on the server and every agent is a system token; a per-agent token comes from registering the agent in the interface first, which is what you want once more than one team can reach the host.
  • Every sensitive variable also has a _FILE form, so the secret can be read from a mounted file instead of sitting in the compose file or the environment.
  • The embedded database is fine to start and is still the thing to move first. Point the server at Postgres before the installation matters to anybody.
  • WOODPECKER_OPEN=true means any account on the connected forge can sign in. It is convenient on day one and wrong by day thirty.
  • The agent needs the Docker socket because every step is a container, which effectively grants the pipeline root on that host. Keep the agent host boring and separate.
  • WOODPECKER_HOST must be the URL the forge can actually reach, not the internal one - the webhook is created against it, and a private address there produces pipelines that never trigger.

Hosted CI minutes versus a runner of your own

Provider-hosted CI minutesA runner on DCXV
What you pay forEvery minute every job runs, for as long as the project existsA flat monthly host, whatever the pipeline does that month
A build that gets slowerCosts more every month it stays slowCosts nothing more - the machine is already paid for
Docker layer cacheCold on each job unless you upload and download it yourselfWarm on local NVMe, between jobs and between days
ConcurrencyA plan tier you upgradeA number you set in your own configuration file
Where the checkout landsA shared fleet, often in a region you cannot pinOne machine in Prague or Covilha, under a Cyprus contract
Outbound addressA large shared range that nothing can allowlistOne static IPv4 from AS204057, yours to allowlist
What the machine can holdWhatever the runner image happens to ship withAny toolchain, licence or fixture set you install once

How this gets going on your host

1

Say what the pipeline does

The heaviest job you run today, how many you want running at once, and whether it builds container images. That is enough to size a host without guessing.

2

We hand over the machine

Prague or Covilha, root access and a static IPv4, in under ten minutes. Bring your own image if the runner is already baked into one.

3

Follow the walkthrough on this page

It is the vendor sequence, taken from their current documentation rather than from a blog post, and it takes a few minutes on a clean host.

4

Snapshot it, then add the second one

Take a snapshot once the first pipeline is green, so the next machine is a restore instead of a rebuild. A pool grows by adding hosts, not by making one enormous.

Why choose us

  • Tier III certified facilities, 99.982% facility SLA
  • Own network, AS204057, IPv4 and IPv6 dual-stack
  • 24/7/365 support with ~10 minute average response
  • Cyprus company, EU jurisdiction, GDPR-native since 2007

FAQ

- What is Woodpecker CI?

A lightweight Apache-2.0 CI engine, forked from Drone, that runs as a server plus one or more agents. Each pipeline step is a container, pipelines are a YAML file in the repository, and it signs users in through your forge. It supports GitHub, GitLab, Gitea, Forgejo and Bitbucket, including instances you host yourself

- How do I install Woodpecker CI?

Docker Compose is the documented route: one woodpecker-server container exposing port 8000 and one woodpecker-agent container with the Docker socket mounted, sharing a secret generated with openssl rand -hex 32, plus your forge OAuth client id and secret. The upstream compose file and the surrounding steps are on this page

- What is WOODPECKER_AGENT_SECRET and how do I generate it?

It is the shared secret the server and agents authenticate with, and Woodpecker documentation names openssl rand -hex 32 for producing it. Setting the same value everywhere makes it a system token; registering an agent in the interface first gives that agent its own token instead, which is what you want once more than one team can reach the host. Every sensitive variable also has a _FILE form so the value can be read from a mounted file

- What size server does Woodpecker need?

The software itself is light - the server is a small Go process with an embedded database until you point it at Postgres, and the agent is a supervisor that starts containers. What consumes the machine is the build. 2 vCPU, 4 GB and 64 GB of NVMe runs server and agent together for a small team; move to a dedicated agent host once pipelines start queueing

- Why does the agent need the Docker socket?

Because every pipeline step is a container the agent starts on the host daemon. That effectively gives pipeline steps root on that machine, which is the design rather than a misconfiguration - and it is the reason to keep the agent on a host that does nothing else, which is cheap to do when a second machine costs EUR 15 a month

- My pipelines never trigger. What is wrong?

Nine times in ten it is WOODPECKER_HOST. That value is the public URL the forge uses when it creates the webhook, so an internal address there produces an installation that looks healthy and never receives a push. The other common one is WOODPECKER_OPEN=true, which is not a trigger problem but does mean anyone with an account on your forge can sign in - convenient on day one, wrong by day thirty

If you require assistance or have additional questions, please contact the managers or write to the support team at support@dcxv.com

Ready to get started?

Monthly billing, no setup fee, no lock-in

Cloud servers from €15/mo