In my Homelab environment, I used Woodpecker-CI to quickly be able to run some CI/CD jobs.

Here’s my docker-compose.yml in charge of deploying it.

I use two distinct DNS records:

  • woodpecker-ci.mydomain.tld which is a A record pointing to the local IP of my Traefik server (192.168.0.x).
  • woodpecker-ci-wh.mydomain.tld which is a CNAME record pointing to my Cloudflare Tunnel instance.
services:
  woodpecker-server:
    image: woodpeckerci/woodpecker-server:v3
    #ports:
    #  - 8000:8000
    volumes:
      - /opt/woodpecker/server/data:/var/lib/woodpecker/
    environment:
      - WOODPECKER_OPEN=false # You might need to set this to true the first time to log in using Github
      - WOODPECKER_HOST=https://woodpecker-ci.mydomain.tld
      - WOODPECKER_GITHUB=true
      - WOODPECKER_GITHUB_CLIENT=GITHUB_CLIENT_ID_HERE
      - WOODPECKER_GITHUB_SECRET=GITHUB_CLIENT_SECRET_HERE
      - WOODPECKER_AGENT_SECRET=YOU_AGENT_SECRET_HERE
      - WOODPECKER_ADMIN=YOUR_GITHUB_USERNAME_HERE
      - WOODPECKER_EXPERT_WEBHOOK_HOST=https://woodpecker-ci-wh.mydomain.tld
    restart: always
    networks: # Optional
      - apps
    labels: # If you don't use traefik, you can comment all the labels and uncomment the `ports` section.
      - "traefik.enable=true"
      - "traefik.http.services.woodpecker-server.loadbalancer.server.port=8000"
      - "traefik.http.routers.woodpecker-server.rule=Host(`woodpecker-ci.mydomain.tld`)"

  woodpecker-agent:
    image: woodpeckerci/woodpecker-agent:v3
    command: agent
    restart: always
    depends_on:
      - woodpecker-server
    volumes:
      - /opt/woodpecker/agent/config:/etc/woodpecker
      - /var/run/docker.sock:/var/run/docker.sock
      # Extra volumes can be added to suit your needs
    environment:
      - WOODPECKER_SERVER=woodpecker-server:9000
      - WOODPECKER_AGENT_SECRET=YOU_AGENT_SECRET_HERE
    networks: # Optional
      - apps

  cloudflared-woodpecker-ci-wh:
    image: cloudflare/cloudflared:latest
    restart: always
    depends_on:
      - woodpecker-server
    command: tunnel --no-autoupdate run --token YOUR_CLOUDFLARED_TOKEN_HERE
    networks: # Optional
      - apps

networks: # Optional
  apps:
    name: apps
    external: true

Things you need to replace:

  1. YOU_AGENT_SECRET_HERE by a new secret, you can use the command pwgen 64 1 to get a random string. Replace it in both woodpecker-server and woodpecker-agent enviroment.
  2. GITHUB_CLIENT_ID_HERE & GITHUB_CLIENT_SECRET_HERE with the client ID and secret of your Github OAuth application.
  3. YOUR_GITHUB_USERNAME_HERE by… well… your Github username.
  4. YOUR_CLOUDFLARED_TOKEN_HERE by the token provided by Cloudflare Tunnels for cloudflared.

Here’s also a summary of my Cloudflare Tunnel config:

Cloudflared Tunnel Config

Make sure to only route the /api/hook endpoint; the service URL should be http://woodpecker-server:8000.