You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
labnotes/_source/_posts/2026-04-18-drone-to-woodpec...

4.8 KiB

layout title date tags
post Migrating from Drone CI to Woodpecker CI 2026-04-18
ci
devops
drone
woodpecker
gitea
docker

Woodpecker CI is a community fork of Drone CI, created when Drone changed its licensing model around 2021 and moved features behind a paid enterprise tier. Woodpecker continues as a fully open-source (Apache 2.0) project with active development, while Drone itself has been largely absorbed into Harness CI and is in maintenance mode.

If you're running Drone with Gitea, Woodpecker is a natural migration target — it has strong Gitea integration and an actively maintained codebase. Here is what the migration actually involves, based on a real setup using Docker Compose and Traefik.

Docker Compose

The server and runner/agent images change, and there are several environment variable renames. Woodpecker also uses different ports: the web UI runs on 8000 (not 80), and the agent communicates with the server over gRPC on port 9000.

  woodpecker:
    image: woodpeckerci/woodpecker-server:latest
    container_name: woodpecker
    restart: unless-stopped
    environment:
      - WOODPECKER_HOST=https://drone.example.org   # full URL including scheme
      - WOODPECKER_GITEA=true
      - WOODPECKER_GITEA_URL=https://gitea.example.org
      - WOODPECKER_CRON_DISABLED=true
    env_file:
      - ./woodpecker.env
    volumes:
      - woodpecker:/var/lib/woodpecker   # different path from Drone's /data
    networks:
      - services
      - woodpecker
    labels:
      traefik.enable: "true"
      traefik.http.services.woodpecker.loadbalancer.server.port: 8000  # not 80!

  woodpecker-agent:
    image: woodpeckerci/woodpecker-agent:latest
    restart: unless-stopped
    environment:
      - WOODPECKER_SERVER=woodpecker:9000   # gRPC port, not HTTP
      - WOODPECKER_GRPC_SECURE=false
    env_file:
      - ./woodpecker.env
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    networks:
      - woodpecker

Make sure both the server and agent containers are on the same Docker network. If the agent can resolve the server's hostname but port 9000 is refused, it is likely a startup ordering issue — simply restarting the agent container after the server is fully up will fix it.

Environment Variables

Your drone.env secrets need to be renamed in a new woodpecker.env file:

drone.env woodpecker.env
DRONE_GITEA_CLIENT_ID WOODPECKER_GITEA_CLIENT
DRONE_GITEA_CLIENT_SECRET WOODPECKER_GITEA_SECRET
DRONE_RPC_SECRET WOODPECKER_AGENT_SECRET
DRONE_COOKIE_SECRET WOODPECKER_SECRET

Note that WOODPECKER_AGENT_SECRET (RPC) and WOODPECKER_SECRET (cookie signing) are separate variables — do not conflate them.

You also need to set WOODPECKER_ADMIN to your Gitea username, otherwise Woodpecker will not allow you to register or access the admin panel:

WOODPECKER_ADMIN=yourusername

You will also need to create a new OAuth application in Gitea pointing at your Woodpecker URL, since the callback URL changes.

Pipeline Files

You must rename .drone.yml to .woodpecker.yml. Despite what the documentation suggests, Woodpecker (at least on the next tag) does not fall back to .drone.yml — it will silently ignore it, and pushes will not trigger any pipelines.

The pipeline syntax is largely compatible. Steps, images, commands, secrets, and when conditions mostly work as-is. A few things to check:

Move trigger to the pipeline level. In Drone it was sometimes written under individual steps; in Woodpecker it must be a top-level key.

Drone plugins still work. They are just Docker images, so plugins like drillster/drone-rsync are fully compatible.

DRONE_* environment variables become CI_*. If your pipeline scripts reference injected variables like DRONE_COMMIT, these are renamed in Woodpecker (e.g. CI_COMMIT_SHA).

What Does Not Migrate

Woodpecker does not import Drone's database. This means:

  • Build history is lost — you start with a clean slate
  • Secrets must be re-entered via the Woodpecker UI for each repository
  • Repos must be re-activated in Woodpecker

If retaining build history matters, you can keep the old Drone instance running read-only alongside Woodpecker temporarily, since they can coexist on different hostnames.

Summary

For a straightforward Drone + Gitea + Docker Compose setup, the migration is low effort. The main steps are:

  1. Update docker-compose.yml with the new images and port numbers
  2. Rename secrets in your env file and set WOODPECKER_ADMIN
  3. Create a new OAuth app in Gitea
  4. Rename .drone.yml to .woodpecker.yml in each repository
  5. Move any pipeline-level trigger blocks to the top level
  6. Re-activate repos and re-enter secrets in the Woodpecker UI