
September 12, 2026
11 min read
By Kokil Thapa | Last reviewed: September 2026
Your team needs automated builds, but SaaS CI bills climb fast and shared runners feel slow. Woodpecker CI: Lightweight Self-Hosted CI fills that gap. It runs on a single VPS, speaks Drone-style YAML, and executes each step in an isolated Docker container. If you already ship Laravel apps with GitLab CI pipelines for Laravel, Woodpecker gives you the same mental model on hardware you control. This guide covers install, a real PHP pipeline, security, and how it stacks up against heavier options.
.woodpecker.yml—no per-minute SaaS fees.What Is Woodpecker CI: Lightweight Self-Hosted CI?
Woodpecker is a continuous integration server that listens for Git webhooks and runs pipeline steps inside containers. The project continued development after Drone's community edition stalled. The architecture stays deliberately small: one server process, one or more agents, and a database.
In practice, that means you can replace a bloated Jenkins install with a ~200 MB Docker stack on Ubuntu 22 or 24. I've maintained sister legal-tech sites on a shared EC2 box using GitLab CI and Deployer 7. Woodpecker fits the same profile when you want CI on the same machine without GitLab's full footprint.
Core components break down like this:
- Server — Web UI, REST API, OAuth with your Git host, and webhook receiver.
- Agent — Pulls jobs from the server and starts Docker containers for each step.
- Database — SQLite for a single-node lab; PostgreSQL for production.
- Pipeline file —
.woodpecker.ymlat the repo root, checked into Git.
Woodpecker does not replace your Git host. It complements it, much like the patterns in our self-hosted CI runners setup and security guide. You keep code on GitHub or Gitea. Woodpecker only builds and tests it.
How Do You Install Woodpecker CI on Ubuntu with Docker?
A minimal production stack needs Docker Engine, Docker Compose, and two containers: server and agent. Budget roughly Rs 1,500–3,000/month (~USD 11–22) for a 2 vCPU VPS with 4 GB RAM. That handles small teams running PHP and Node builds comfortably.
Step 1: Prepare the host
Start on Ubuntu 22.04 or 24.04. Install Docker, enable UFW, and open ports 80 and 443 only. If you manage servers for Nepal clients, the same hardening applies as in Linux system administration work: fail2ban, automatic security updates, and non-root deploy users.
- Install Docker Engine and the Compose plugin from the official Docker repository.
- Create a dedicated system user, e.g.
woodpecker, and add it to thedockergroup. - Point a DNS A record at your server, e.g.
ci.example.com. - Issue TLS with Certbot or Caddy in front of the Woodpecker port.
Step 2: Create docker-compose.yml
Save this under /opt/woodpecker/docker-compose.yml. Adjust image tags to the current release on the Woodpecker installation docs.
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}
restart: always
woodpecker-agent:
image: woodpeckerci/woodpecker-agent:v3
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
- WOODPECKER_SERVER=woodpecker-server:9000
- WOODPECKER_AGENT_SECRET=${WOODPECKER_AGENT_SECRET}
- WOODPECKER_MAX_PROCS=2
restart: always
depends_on:
- woodpecker-server
volumes:
woodpecker-server-data: Place secrets in /opt/woodpecker/.env. Never commit that file. Generate WOODPECKER_AGENT_SECRET with openssl rand -hex 32. Register an OAuth app on GitHub with callback URL https://ci.example.com/authorize.
Step 3: Start and verify
cd /opt/woodpecker
docker compose up -d
docker compose logs -f woodpecker-server Open the UI, log in via GitHub, and activate a test repository. Push a commit. You should see a pipeline queued within seconds. If the agent never picks up jobs, check that WOODPECKER_AGENT_SECRET matches on both services and that the agent can reach the server on port 9000 internally.
For Gitea or Forgejo, swap GitHub variables for WOODPECKER_GITEA_* equivalents. The agent model matches what you'd expect from Drone CI getting started—because Woodpecker forked from Drone CE.
How Do You Write a Woodpecker CI Pipeline for Laravel?
On production Laravel 12 or 13 apps, a sensible pipeline runs Composer install, static analysis, Pest or PHPUnit tests, and optionally deploys via SSH. PHP 8.3 is the minimum for Laravel 13; Laravel 12 needs PHP 8.2 or higher. Pin the image tag so builds stay reproducible.
Add .woodpecker.yml to your repo root:
when:
- event: [push, pull_request]
branch: [main, develop]
steps:
- name: backend-tests
image: composer:2.10
environment:
APP_ENV: testing
DB_CONNECTION: sqlite
DB_DATABASE: ":memory:"
commands:
- composer install --no-interaction --prefer-dist
- cp .env.example .env
- php artisan key:generate
- php artisan test
- name: frontend-build
image: node:26-alpine
commands:
- npm ci
- npm run build
when:
- event: push
branch: main
- name: deploy-production
image: alpine:3.20
environment:
SSH_KEY:
from_secret: deploy_ssh_key
DEPLOY_HOST:
from_secret: deploy_host
commands:
- apk add --no-cache openssh-client
- install -m 600 -D /dev/null ~/.ssh/id_ed25519
- echo "$SSH_KEY" > ~/.ssh/id_ed25519
- ssh -o StrictHostKeyChecking=no deploy@$DEPLOY_HOST "cd /var/www/app && dep deploy production"
when:
- event: push
branch: main Store deploy_ssh_key and deploy_host in the Woodpecker UI under repository secrets. Follow the same discipline as CI/CD secrets management best practices: never echo secrets in logs, rotate keys quarterly, and scope deploy keys to one host.
Optimise Laravel builds
Three changes cut pipeline time on real projects:
- Cache Composer's
vendor/directory with Woodpecker'sbackendvolume plugin or a bind mount on the agent. - Run migrations in a dedicated step only on deploy branches, as covered in database migrations in CI/CD pipelines.
- Split Pest suites and run them in parallel when test count exceeds a few hundred—see Laravel testing with Pest in CI/CD.
On booking platforms like Adventure Third Pole Trek, CI must pass before Deployer swaps the release symlink. Woodpecker's deploy step can call the same dep deploy command your GitLab pipeline uses today. Swap the YAML syntax; keep the server-side flow.
Validate YAML locally before pushing. A malformed step name wastes five minutes of queue time and blocks your team. Use the JSON formatter or a YAML linter in a pre-commit hook if your editor lacks schema validation.
How Does Woodpecker CI Compare to GitLab CI, Drone, and Jenkins?
Pick Woodpecker when you want container-native pipelines without running an entire GitLab instance. Pick GitLab CI when you already host GitLab and want integrated registry, issues, and merge requests in one product.
| Criteria | Woodpecker CI | GitLab CI | Drone CE | Jenkins |
|---|---|---|---|---|
| Resource footprint | Low — 2 containers | High — full GitLab stack | Low — same model | Medium–high — JVM + plugins |
| Pipeline syntax | YAML, Docker steps | YAML, Docker/Kubernetes | YAML, Docker steps | Jenkinsfile (Groovy) |
| Active maintenance (2026) | Yes — active fork | Yes — vendor-backed | Stalled CE lineage | Yes — plugin ecosystem |
| Best fit | Small teams, own VPS | All-in-one DevOps | Legacy Drone users | Enterprise plugin needs |
| Laravel PHP support | Excellent via Docker images | Excellent | Excellent | Good with config |
| Cost on 4 GB VPS | ~Rs 2,000/mo hosting only | Needs 8 GB+ for comfort | Same as Woodpecker | Varies by plugin load |
For a broader SaaS versus self-hosted lens, read GitHub Actions vs GitLab CI comparison. Woodpecker sits closest to the self-hosted column but with less ceremony than Jenkins.
Buildkite follows a similar agent model but uses a proprietary server. See Buildkite scalable CI with your own agents if you need elastic scaling across many machines. Woodpecker stays simpler when one or two agents cover your workload.
How Do You Secure and Operate Woodpecker CI in Production?
Self-hosted CI is part of your attack surface. A compromised pipeline can exfiltrate secrets, push malicious images, or pivot into production SSH keys. Treat the CI host like a production server.
Harden the server
- Disable
WOODPECKER_OPENafter initial setup so random users cannot register. - Restrict OAuth to your organisation's GitHub org or Gitea team.
- Run the agent on a dedicated host if pipelines execute untrusted fork PRs.
- Keep Docker updated; agents mount
/var/run/docker.sock, which equals root access. - Enable audit logging and ship logs to a central store.
Scan repos for leaked tokens before they reach CI. Pair Woodpecker with guidance from secrets scanning in Git and CI with Gitleaks. Add coverage thresholds using patterns from code coverage gates in CI once tests are stable.
Cache and registry
Pulling composer:2.10 and node:26-alpine on every build wastes bandwidth on Nepali VPS links. Configure a local registry mirror or follow self-host a Docker registry so agents pull from LAN speed. Combine with build caching to speed up CI builds for Composer and npm directories.
Backups and upgrades
Back up the Woodpecker data volume nightly. SQLite files live under /var/lib/woodpecker/. For PostgreSQL, use pg_dump cron jobs—the same approach I use on shared EC2 infrastructure for sister sites like Notary Kathmandu.
Upgrade by pinning a new image tag, running docker compose pull, and restarting. Read release notes on the Woodpecker GitHub releases page before jumping major versions. Roll back by reverting the tag if pipelines break.
For blue-green or zero-downtime deploys after CI passes, wire your pipeline into the flow described in CI/CD blue-green deployment explained. Woodpecker only gates the deploy; Deployer or your shell script still performs the swap.
Ongoing ops belong in a support contract or your runbook. If you prefer someone else patches the server and rotates secrets, see support and maintenance services or domain registration and hosting for the full stack.
Key Takeaways
- Woodpecker CI runs as two Docker containers—server plus agent—on a modest VPS with Drone-compatible YAML pipelines.
- Connect GitHub or Gitea via OAuth, store secrets in the UI, and keep
WOODPECKER_OPEN=falsein production. - Laravel 12/13 pipelines need pinned PHP, Composer 2.10, and Node 26 LTS images with cached
vendor/andnode_modules/. - Choose Woodpecker over GitLab CI when you already have a Git host and want minimal ops overhead.
- Mounting the Docker socket on agents is convenient but dangerous—isolate untrusted fork builds on a separate agent host.
- Back up the server data volume and test rollback before upgrading Woodpecker image tags.
People Also Ask
Is Woodpecker CI free to self-host?
Yes. Woodpecker is open source under the Apache 2.0 licence. You pay only for VPS hosting, typically Rs 1,500–3,000/month (~USD 11–22) for a capable build server. There is no per-seat or per-minute SaaS fee.
Can Woodpecker CI replace GitLab CI entirely?
It replaces the CI portion, not GitLab itself. You still need a Git host for repositories, merge requests, and code review. Teams that already run Gitea or GitHub get the biggest win because Woodpecker adds pipelines without a second heavy platform.
Does Woodpecker support monorepos and matrix builds?
Yes. Use matrix: blocks to run the same step across PHP 8.3 and 8.4, or filter pipelines with path: rules so only changed apps rebuild. Parallel steps run as separate containers on the agent until WOODPECKER_MAX_PROCS limits concurrency.
What happens to Drone CI pipelines when migrating to Woodpecker?
Most .drone.yml files convert with minor edits—rename the file to .woodpecker.yml and adjust plugin image namespaces from plugins/ to woodpeckerci/ where needed. Step syntax, secrets, and when conditions largely carry over.
Run Woodpecker CI on Your Own Metal
Woodpecker CI: Lightweight Self-Hosted CI earns its place when you want predictable builds, full data control, and a pipeline file in Git—without maintaining Jenkins plugins or a full GitLab stack. Start with one agent, a Laravel test pipeline, and strict secrets hygiene. Scale agents horizontally when queue times grow.
If you want help standing up CI on Ubuntu, wiring Deployer deploys, or migrating from GitLab CI, contact us or explore web development services. For related reading, browse integration testing in CI pipelines, build verification and quality gates, and the full CI/CD blog archive. You can also review how we ship production apps in the portfolio or learn more about my background with Laravel deployments since 2010.
Frequently Asked Questions
0 Comments
Leave a comment
Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

