Woodpecker CI
Lightweight CI/CD engine: the server receives webhooks from your Git forge (Gitea, Forgejo, GitHub, GitLab, Bitbucket) and agents run every pipeline step in its own container. Fits a team that already hosts its code and wants simple YAML pipelines on its own hardware.
Resources by load level
What the app itself needs at each level, next to what we recommend for a server that runs only this app.
| Level | What it means | App requirements | Recommended |
|---|---|---|---|
| LightEstimate | Up to 5 users and 10 repos, about 20 pipelines a day, one workflow at a time (WOODPECKER_MAX_WORKFLOWS=1, the default) running lint and unit tests; SQLite. | 1.25 vCPU · 4.95 GiB RAM · 14.3 GiB disk | 1.62 vCPU · 7.44 GiB RAM · 25.875 GiB disk |
| MediumEstimate | Up to 20 users and 50 repos, about 100 pipelines a day, 2 parallel workflows on one agent (MAX_WORKFLOWS=2) that compile code and build Docker images; SQLite. | 4.5 vCPU · 15.5 GiB RAM · 31.4 GiB disk | 5.52 vCPU · 20.1 GiB RAM · 45.54 GiB disk |
| HeavyEstimate | Up to 50 users and 200 repos, about 400 pipelines a day, 4 parallel workflows on one agent with full builds and integration tests; SQLite (PostgreSQL is advised, not sized). | 9 vCPU · 31 GiB RAM · 72.4 GiB disk | 10.92 vCPU · 38.7 GiB RAM · 92.69 GiB disk |
Recommended = app requirements + system baseline + safety headroom, under sizing policy 2026.10.0. Options stay at their defaults. “Estimate” means the sources give no number for that case, so it is worked out from them by the method stated under Components. How the numbers are built
Ready-to-run files
Support level Official install
No Compose template from ANAROQ: install it the official way.
Why: The agent starts every pipeline step on the host's Docker daemon, so the official Compose mounts /var/run/docker.sock: root-equivalent access that the Generator never writes and the Analyzer flags as AQ-VOL-001 (high). It also needs an OAuth app on your forge and a shared WOODPECKER_AGENT_SECRET. Give it a server or VM of its own: pipelines run repository code with host Docker access and no resource limits by default.
Components
What each component needs at each load level, before baseline and headroom.
| Component | Light | Medium | Heavy | Sources |
|---|---|---|---|---|
| Woodpecker server (web UI, API, webhooks, scheduler) (app) | 0.25 / 0.25 / 1.1 | 0.5 / 0.5 / 5.1 | 1 / 1 / 20.1 | [2][3][12][20][27] |
| Woodpecker agent with its pipeline containers (Docker backend) (worker) | 1 / 4.7 / 13.2 | 4 / 15 / 26.3 | 8 / 30 / 52.3 | [4][5][12][19][22][24][26][27] |
How the estimates are worked out
- Woodpecker server (web UI, API, webhooks, scheduler) · Light: No load figure upstream; the README gives about 100 MB RAM when idle (0.093 GiB). ×2.5 for webhooks, the web UI, live log streaming of one running workflow and the SQLite cache → 0.25 GiB and a quarter core. Disk: image 21,255,672 B compressed (0.020 GiB) + 61,089,280 B unpacked (0.057 GiB), both kept by the containerd store = 0.077 GiB. 0.077 + 1 GiB of database (users, repos and pipeline logs, which are stored in the database by default) → 1.1.
- Woodpecker server (web UI, API, webhooks, scheduler) · Medium: Light ×2: twice the parallel workflows streaming logs, more webhook events and UI users, and a larger SQLite file in cache → 0.5 GiB and half a core. Disk: image 21,255,672 B compressed (0.020 GiB) + 61,089,280 B unpacked (0.057 GiB), both kept by the containerd store = 0.077 GiB. 0.077 + 5 GiB of database, mostly pipeline logs → 5.1.
- Woodpecker server (web UI, API, webhooks, scheduler) · Heavy: Medium ×2 for 4 parallel log streams, about 400 pipelines a day and up to 50 users → 1 GiB and one core; SQLite serializes writes, which is why upstream advises PostgreSQL or MariaDB for larger instances. Disk: image 21,255,672 B compressed (0.020 GiB) + 61,089,280 B unpacked (0.057 GiB), both kept by the containerd store = 0.077 GiB. 0.077 + 20 GiB of database → 20.1.
- Woodpecker agent with its pipeline containers (Docker backend) · Light: Step containers run on the agent host and their size depends on your pipelines; Woodpecker publishes no figure. Budget for 1 workflow (MAX_WORKFLOWS=1) sized like GitHub's ubuntu-slim runner for light jobs: 1 CPU, 5 GB RAM (4.657 GiB), 14 GB SSD (13.039 GiB). RAM 4.657 + 0.028 for the idle agent (30 MB) → 4.7. Images: agent 17,174,205 B compressed + 62,571,008 B unpacked = 0.074 GiB, plus plugin-git 2.10.1 (the default clone step of every workflow) 0.070 GiB = 0.144 GiB. Disk 0.144 + 13.039 → 13.2.
- Woodpecker agent with its pipeline containers (Docker backend) · Medium: 2 workflows at once, each sized like GitHub's standard Linux runner for private repos (2 CPU, 8 GB RAM = 7.451 GiB, 14 GB SSD = 13.039 GiB), since compiling and image builds need a full runner. vCPU 2 × 2 = 4. RAM 2 × 7.451 + 0.028 (idle agent) = 14.93 → 15. Images: agent 17,174,205 B compressed + 62,571,008 B unpacked = 0.074 GiB, plus plugin-git 2.10.1 (the default clone step of every workflow) 0.070 GiB = 0.144 GiB. Disk 0.144 + 2 × 13.039 → 26.3.
- Woodpecker agent with its pipeline containers (Docker backend) · Heavy: 4 workflows at once (MAX_WORKFLOWS=4), each a GitHub standard Linux runner for private repos (2 CPU, 7.451 GiB RAM, 13.039 GiB SSD). vCPU 4 × 2 = 8. RAM 4 × 7.451 + 0.028 (idle agent) = 29.832 → 30. Images: agent 17,174,205 B compressed + 62,571,008 B unpacked = 0.074 GiB, plus plugin-git 2.10.1 (the default clone step of every workflow) 0.070 GiB = 0.144 GiB. Disk 0.144 + 4 × 13.039 → 52.3. More parallel work is better spread over more agents.
Ports
Public ports are meant to be reached from outside the stack, usually through a reverse proxy; internal ones stay on the stack's own network.
| Component | Port | Exposure | Purpose | Sources |
|---|---|---|---|---|
| Woodpecker server (web UI, API, webhooks, scheduler) | 8000/tcp | Public, through a proxy | Web UI, API and forge webhooks (HTTP); serve through an HTTPS reverse proxy | [1][3][21] |
| Woodpecker server (web UI, API, webhooks, scheduler) | 9000/tcp | Internal only | gRPC for agents; plain text by default, put TLS in front (h2c proxy) before remote agents use it | [1][3][4] |
| Woodpecker agent with its pipeline containers (Docker backend) | 3000/tcp | Internal only | Agent health endpoint (/healthz) used by the image's HEALTHCHECK | [4][18][23] |
User and permissions (UID/GID)
The user each container's process runs as, and the paths it writes to. A bind mount for one of these paths must be writable by that UID:GID.
| Component | UID:GID | User | Starts as root | Writes to | Sources |
|---|---|---|---|---|---|
| Woodpecker server (web UI, API, webhooks, scheduler) | 1000:1000 | woodpecker | No | /var/lib/woodpecker | [10][14][16][21] |
| Woodpecker agent with its pipeline containers (Docker backend) | 0:0 | root | No | /etc/woodpecker | [10][15][16][23] |
- Woodpecker server (web UI, API, webhooks, scheduler): Since 3.0 the server image runs as woodpecker (1000:1000) and ships /var/lib/woodpecker owned by it, so a named volume works; a bind mount from 2.x needs chown -R 1000:1000.
- Woodpecker agent with its pipeline containers (Docker backend): The agent image sets no USER and stays rootful on purpose: with the Docker backend it must use the mounted Docker socket. /etc/woodpecker holds agent.conf with the ID the server assigned.
Storage growth
How much each component's data grows per month at each load level, on top of the disk in the profile. A value marked Assumption is ANAROQ's stated assumption, not a figure from the sources; the notes say what it rests on.
| Component | Light | Medium | Heavy | Sources |
|---|---|---|---|---|
| Woodpecker server (web UI, API, webhooks, scheduler)Assumption | 0.117 | 0.586 | 2.344 | [3] |
| Woodpecker agent with its pipeline containers (Docker backend)Assumption | 1.953 | 4.883 | 9.766 | [5] |
What the growth figures rest on
- Woodpecker server (web UI, API, webhooks, scheduler): Pipeline logs go into the database by default (WOODPECKER_LOG_STORE=database) and Woodpecker never archives or deletes old data. Assumed 0.2 MiB of logs per pipeline × 20 pipelines a day × 30 days; no source states a log size.
- Woodpecker server (web UI, API, webhooks, scheduler): Pipeline logs go into the database by default (WOODPECKER_LOG_STORE=database) and Woodpecker never archives or deletes old data. Assumed 0.2 MiB of logs per pipeline × 100 pipelines a day × 30 days; no source states a log size.
- Woodpecker server (web UI, API, webhooks, scheduler): Pipeline logs go into the database by default (WOODPECKER_LOG_STORE=database) and Woodpecker never archives or deletes old data. Assumed 0.2 MiB of logs per pipeline × 400 pipelines a day × 30 days; no source states a log size.
- Woodpecker agent with its pipeline containers (Docker backend): The agent never removes the step images it pulls; cleanup is left to the host. Assumed 10 new image versions a month × 200 MiB, until a cron job runs docker image prune and removes dangling wp_* volumes.
- Woodpecker agent with its pipeline containers (Docker backend): The agent never removes the step images it pulls; cleanup is left to the host. Assumed 25 new image versions a month × 200 MiB, until a cron job runs docker image prune and removes dangling wp_* volumes.
- Woodpecker agent with its pipeline containers (Docker backend): The agent never removes the step images it pulls; cleanup is left to the host. Assumed 50 new image versions a month × 200 MiB, until a cron job runs docker image prune and removes dangling wp_* volumes.
Upgrade and rollback
How to move to a new version safely, and how to go back if it fails.
Back up first
Stop the server and copy the whole /var/lib/woodpecker volume (woodpecker.sqlite); the image has no shell or sqlite3. With PostgreSQL or MariaDB, take a dump with the database's own tools. [1][3][14]
Upgrade steps
- Read the Migrations page and the changelog of every release you skip, then take the backup below. [10][11]
- Set the same new vX.Y.Z tag on the server and on every agent, then docker compose pull and docker compose up -d. Since 3.18 the server rejects agents with an incompatible gRPC version, so upgrade them together. [2][11]
- The server migrates its database on start; a large log table can make that slow (for example the log deduplication of 3.18). Wait until the container is healthy and the agents show as connected under Settings > Agents. [3][11][17]
- From 1.x go to 2.x first: 3.0 accepts upgrades from 2.x only. After 2.x → 3.x, press Repair all in the admin settings to renew webhook tokens and move pipelines to the 3.x syntax. [10][11]
Roll back
Stop server and agents, restore the backup taken before the upgrade, pin the previous tag on all of them and run docker compose up -d. [3]DerivedUpstream documents no downgrade. The server upgrades the database automatically on start, so an older binary on a migrated database is not safe; restoring the pre-upgrade backup is.
Known breaking changes
- In 3.18.0: The server rejects agents with an incompatible gRPC protocol version. WOODPECKER_GRPC_VERIFY became WOODPECKER_GRPC_SKIP_VERIFY with the meaning inverted (true now skips verification), and GitLab groups in WOODPECKER_ORGS are matched by full path. [3][10][11]
- In 3.0.0: No latest tag; images run as UID 1000 (chown bind mounts); no plugin is privileged by default, so docker-buildx must be listed in WOODPECKER_PLUGINS_PRIVILEGED; webhooks need Repair all; native Let's Encrypt was dropped; only upgrades from 2.x. [10][11]
- In 3.0.0: Pipeline syntax: secrets: is gone (use environment with from_secret), environment must be a map, cron uses standard 5-field syntax, and pipelines from forks wait for approval by default. [10][11]
Limits
- The agent figures include the pipeline containers, budgeted from GitHub's runner sizes; your real need depends on what the pipelines build. Docker backend limits are off by default (WOODPECKER_BACKEND_DOCKER_LIMIT_MEM and _CPU_QUOTA = 0), so one heavy build can take the whole host. [4][5][26]
- Woodpecker has no accounts of its own: users log in through a forge (GitHub, Gitea, Forgejo, GitLab or Bitbucket) with an OAuth app you register there. Only one forge can be set from the environment; several forges are experimental. [3][7]
- With Gitea from this catalog: create an OAuth app in Gitea with the callback https://<woodpecker-host>/authorize, set WOODPECKER_GITEA=true, _URL, _CLIENT and _SECRET, and on the same host attach the agent to Gitea's network (WOODPECKER_BACKEND_DOCKER_NETWORK) and allow local webhooks in Gitea. [6]
- One agent runs one workflow at a time by default (WOODPECKER_MAX_WORKFLOWS=1); raise it or add agents for parallel work. SQLite is the default; for larger instances upstream advises PostgreSQL or MariaDB, which you must create yourself and which is not sized here. [2][3][4]
- The Docker backend needs a Linux agent host. The server and agent images are built for amd64, arm64 and other Linux architectures. [9]
Security
- The agent mounts /var/run/docker.sock to start step containers. That is root-equivalent access to the host, exactly what the ANAROQ Analyzer flags as AQ-VOL-001 (high); here it is required. Run the agent on a dedicated server or VM and build only repositories you trust. [1][10]
- Registration is closed by default, but the official Compose example sets WOODPECKER_OPEN=true. Keep it false (or limit it with WOODPECKER_ORGS) and name your admins in WOODPECKER_ADMIN. [1][3]
- Mark a repo as trusted only when needed: trusted pipelines get escalated capabilities such as volume mounts. Leave WOODPECKER_PLUGINS_PRIVILEGED empty (the 3.x default) or list exact image tags, and keep approval for pull requests from forks. [3][8][10]
- WOODPECKER_AGENT_SECRET is shared by server and agents; create it with openssl rand -hex 32. gRPC on port 9000 has no TLS by default: keep it internal, or put TLS in front before agents connect over the internet. [1][3][4]
- By default any repo admin can register an agent for their repos. If you keep instance-wide secrets, set WOODPECKER_DISABLE_USER_AGENT_REGISTRATION=true so nobody can attach a rogue agent to read them. [3]
Backup
- Back up /var/lib/woodpecker: woodpecker.sqlite holds users, repos, secrets and pipeline logs, and Woodpecker makes no backups itself. Copy it with the server stopped, or use sqlite3 .backup on the host; the image has no sqlite3. [1][3][14]
- With PostgreSQL or MariaDB, back up with the database's own tools. Keep the .env values (WOODPECKER_AGENT_SECRET, the forge OAuth client and secret) with the backup; the agent's /etc/woodpecker only holds its ID and pipeline workspaces are temporary. [1][3][4]
Latest release
- This profile was checked against
Woodpecker CI 3.19.0
This profile was checked against the newest release.
- Checked on
- 14 Oct 2026
- State
- Checked within the last 90 days
- Where releases are published
- GitHub Releases
Checked 2026-10-14: 3.19.0 (2026-10-07) is the newest release in the changelog and on Docker Hub; the docs mark 3.18.x and 3.17.x as no longer maintained.
Version
- Profile status
- Published
- Checked against release
- Woodpecker CI 3.19.0
- Profile version
- 1.0.0
- Figures verified
- 14 Oct 2026
- Catalog release
- 2026.10.10
- Sizing policy
- 2026.10.0
- Compose file
- Not available yet
Project and alternatives
- Official site
- woodpecker-ci.org
- Source code
- github.com/woodpecker-ci/woodpecker
Sources
- Woodpecker docs 3.19.x: Docker Compose installation (server and agent, /var/run/docker.sock on the agent, shared WOODPECKER_AGENT_SECRET, example with WOODPECKER_OPEN=true) (Official docs · read 14 Oct 2026)
- Woodpecker docs 3.19.x: General (server and agent roles, SQLite default, Postgres or MariaDB for larger instances, no latest tag; version menu marks 3.18.x, 3.17.x unmaintained) (Official docs · read 14 Oct 2026)
- Woodpecker docs 3.19.x: Server configuration (WOODPECKER_OPEN default false, ADMIN, ORGS, PLUGINS_PRIVILEGED, LOG_STORE=database, no data archival and no backups, ports 8000 and 9000) (Official docs · read 14 Oct 2026)
- Woodpecker docs 3.19.x: Agent configuration (WOODPECKER_MAX_WORKFLOWS default 1, agent.conf in /etc/woodpecker, healthcheck on :3000, gRPC without TLS by default) (Official docs · read 14 Oct 2026)
- Woodpecker docs 3.19.x: Docker backend (one container per step, images never removed by the agent, memory and CPU limits default 0 = unlimited) (Official docs · read 14 Oct 2026)
- Woodpecker docs 3.19.x: Gitea forge (WOODPECKER_GITEA*, OAuth app with callback /authorize, shared Docker network, webhook ALLOWED_HOST_LIST) (Official docs · read 14 Oct 2026)
- Woodpecker docs 3.19.x: Forges overview (GitHub, Gitea, Forgejo, GitLab, Bitbucket; one forge from the environment, multiple forges experimental) (Official docs · read 14 Oct 2026)
- Woodpecker docs 3.19.x: Project settings (approval for forks by default, trusted repos get escalated capabilities such as volume mounts, set by server admins only) (Official docs · read 14 Oct 2026)
- Woodpecker docs 3.19.x: Supported platforms (server images for linux amd64/arm64 and more; Docker backend needs a Linux agent host) (Official docs · read 14 Oct 2026)
- Woodpecker Migrations (3.0.0: secrets via from_secret, no latest tag, UID 1000 images with a rootful agent, no default privileged plugins, Repair all webhooks) (Official docs · read 14 Oct 2026)
- CHANGELOG.md at v3.19.0 (3.19.0 released 2026-10-07; 3.18.0 rejects agents with an incompatible gRPC version; 3.0.0 requires an upgrade from 2.x) (Release notes · read 14 Oct 2026)
- README.md at v3.19.0 (around 100 MB RAM for the server and 30 MB for the agent when idle; SQLite by default; Codeberg as a public instance) (Official repository · read 14 Oct 2026)
- LICENSE at v3.19.0: Apache License 2.0 (Official repository · read 14 Oct 2026)
- docker/Dockerfile.server.multiarch.rootless at v3.19.0 (scratch image, USER woodpecker 1000:1000, /var/lib/woodpecker, HEALTHCHECK woodpecker-server ping) (Official repository · read 14 Oct 2026)
- docker/Dockerfile.agent.multiarch at v3.19.0 (scratch image without USER, so root; EXPOSE 3000; HEALTHCHECK woodpecker-agent ping) (Official repository · read 14 Oct 2026)
- .woodpecker/docker.yaml at v3.19.0 (release tags vX.Y.Z of woodpecker-server use the rootless Dockerfile, woodpecker-agent the rootful one) (Official repository · read 14 Oct 2026)
- cmd/server/health.go at v3.19.0 (ping requests /api/healthz on WOODPECKER_SERVER_ADDR, default :8000) (Official repository · read 14 Oct 2026)
- cmd/agent/core/health.go at v3.19.0 (ping requests /healthz on WOODPECKER_HEALTHCHECK_ADDR, default :3000) (Official repository · read 14 Oct 2026)
- shared/constant/constant.go at v3.19.0 (default clone plugin docker.io/woodpeckerci/plugin-git:2.10.1) (Official repository · read 14 Oct 2026)
- Docker Hub woodpeckerci/woodpecker-server:v3.19.0 (linux/amd64): 21,255,672 B compressed; 2 layers decompressed and counted: 61,089,280 B (Measurement · read 14 Oct 2026)
- Registry config of woodpecker-server:v3.19.0 (linux/amd64): User woodpecker, ExposedPorts 80, 443, 8000, 9000, no Volumes, Healthcheck CMD woodpecker-server ping (Measurement · read 14 Oct 2026)
- Docker Hub woodpeckerci/woodpecker-agent:v3.19.0 (linux/amd64): 17,174,205 B compressed; 2 layers decompressed and counted: 62,571,008 B (Measurement · read 14 Oct 2026)
- Registry config of woodpecker-agent:v3.19.0 (linux/amd64): no User (root), ExposedPorts 3000, no Volumes, Healthcheck CMD woodpecker-agent ping (Measurement · read 14 Oct 2026)
- Docker Hub woodpeckerci/plugin-git:2.10.1 (linux/amd64): 22,717,662 B compressed; 3 layers decompressed and counted: 52,921,856 B (Measurement · read 14 Oct 2026)
- Docker Hub tags of woodpeckerci/woodpecker-server (v3.19.0 newest release on 2026-10-14, pushed 2026-10-07; next-* tags are builds of the main branch) (Official repository · read 14 Oct 2026)
- GitHub Docs: GitHub-hosted runners reference (ubuntu-slim 1 CPU, 5 GB RAM, 14 GB SSD; standard Linux runner for private repos 2 CPU, 8 GB RAM, 14 GB SSD) (Official docs · read 14 Oct 2026)
- Docker: containerd image store is the default on fresh Engine 29+ installs and keeps images compressed and uncompressed (Official docs · read 14 Oct 2026)