MAATRIX / Блог / Как установить и настроить Woodpecker CI на VPS

Как установить и настроить Woodpecker CI на VPS

MAATRIX

Drone CI когда-то был одним из самых приятных self-hosted CI/CD решений — пока новые версии не ушли под коммерческую лицензию. Часть комьюнити форкнула последнюю свободную версию и продолжила развивать её как полностью open-source проект под именем Woodpecker CI. Ниже — рабочая установка на чистый VPS: от Docker до первого зелёного пайплайна.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Что такое Woodpecker CI и чем он отличается от Drone

Woodpecker — прямой форк Drone CI, сделанный сообществом после того, как Drone перешёл на Business Source License и часть функциональности закрыл для платной версии. Woodpecker остаётся под Apache 2.0 целиком, включая то, что в Drone стало платным (например, несколько параллельных пайплайнов и продвинутые условия запуска).

Архитектурно это тот же принцип, что и у Drone:

  • server — веб-интерфейс, хранит конфигурацию, принимает вебхуки от git-провайдера и раздаёт задания агентам;
  • agent — воркер, который реально выполняет шаги пайплайна как отдельные Docker-контейнеры;
  • база данных — SQLite из коробки для теста, Postgres или MySQL для боевой нагрузки.

Конфиг пайплайна — YAML-файл .woodpecker.yml в корне репозитория, синтаксис близок к тому, что был у Drone (шаги = сервисы = Docker-образы), но не идентичен один в один — при миграции со старых .drone.yml сверяйтесь с актуальной документацией конкретной версии, которую ставите, потому что формат между релизами Woodpecker местами менялся.

Из коробки поддерживаются GitHub, GitLab, Bitbucket, Gitea и Forgejo как источники репозиториев — это удобно, если у вас уже поднят свой Gitea на том же VPS: получаете полностью автономный стек git + CI без внешних сервисов.

Требования к серверу и подготовка

Для сервера Woodpecker плюс один агент с запасом хватает скромной конфигурации:

РесурсМинимумКомфортно
CPU1 vCPU2 vCPU
RAM1 ГБ2-4 ГБ
Диск20 ГБ SSD40+ ГБ SSD
ОСUbuntu 24.04 / Debian 12

Оперативной памяти нужно больше, если пайплайны собирают тяжёлые образы (Node, Java, Rust) — каждый параллельный шаг это отдельный контейнер, и они едят RAM сверх самого Woodpecker. Если планируете 3-4 одновременные сборки, закладывайте от 4 ГБ.

Перед установкой обновите систему и заведите отдельного пользователя без root:

apt update && apt -y upgrade
adduser deploy
usermod -aG sudo deploy

Дальше работаем от deploy, root оставляем для экстренных случаев.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Установка Docker и Docker Compose

Woodpecker поставляется официальными Docker-образами, отдельно ставить бинарники не нужно. Если Docker ещё не стоит — разверните его с нуля, шаги для Ubuntu 24.04 расписаны в отдельной статье про установку Docker на VPS. Коротко:

curl -fsSL https://get.docker.com | sh
usermod -aG docker deploy

Перелогиньтесь, чтобы группа docker применилась, и проверьте:

docker --version
docker compose version

Начиная с актуальных версий Docker плагин compose встроен в сам docker (команда docker compose, без дефиса) — отдельно docker-compose ставить не нужно.

OAuth-приложение и docker-compose для Woodpecker

Server и agent общаются между собой по gRPC через общий секрет, а с git-провайдером сервер общается через OAuth-приложение. Разберём на примере Gitea (для GitHub, GitLab процесс аналогичный, только переменные окружения называются WOODPECKER_GITHUB_* / WOODPECKER_GITLAB_*).

В Gitea зайдите в Settings → Applications → OAuth2 Applications и создайте приложение:

  • Application Name: Woodpecker CI
  • Redirect URI: https://ci.example.com/authorize

Gitea выдаст Client ID и Client Secret — сохраните их, они понадобятся в переменных окружения.

Сгенерируйте общий секрет для связи server-agent:

openssl rand -hex 32

Создайте каталог проекта и docker-compose.yml:

mkdir -p /opt/woodpecker && cd /opt/woodpecker
services:
  woodpecker-server:
    image: woodpeckerci/woodpecker-server:latest
    restart: unless-stopped
    ports:
      - "127.0.0.1:8000:8000"
    volumes:
      - woodpecker-server-data:/var/lib/woodpecker
    environment:
      - WOODPECKER_OPEN=false
      - WOODPECKER_HOST=https://ci.example.com
      - WOODPECKER_ADMIN=your_gitea_username
      - WOODPECKER_AGENT_SECRET=${WOODPECKER_AGENT_SECRET}
      - WOODPECKER_GITEA=true
      - WOODPECKER_GITEA_URL=https://git.example.com
      - WOODPECKER_GITEA_CLIENT=${GITEA_CLIENT_ID}
      - WOODPECKER_GITEA_SECRET=${GITEA_CLIENT_SECRET}

  woodpecker-agent:
    image: woodpeckerci/woodpecker-agent:latest
    restart: unless-stopped
    command: agent
    depends_on:
      - woodpecker-server
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - WOODPECKER_SERVER=woodpecker-server:9000
      - WOODPECKER_AGENT_SECRET=${WOODPECKER_AGENT_SECRET}
      - WOODPECKER_BACKEND=docker
      - WOODPECKER_MAX_WORKFLOWS=2

volumes:
  woodpecker-server-data:

Рядом положите .env с реальными значениями (в git его не кладите):

WOODPECKER_AGENT_SECRET=вставьте_сгенерированный_секрет
GITEA_CLIENT_ID=вставьте_client_id
GITEA_CLIENT_SECRET=вставьте_client_secret

WOODPECKER_ADMIN делает указанного пользователя администратором интерфейса — без этого после первого входа некому будет разрешать репозитории другим. WOODPECKER_OPEN=false запрещает регистрацию произвольных пользователей — оставляйте true только если Woodpecker закрыт за VPN и вы точно знаете, кто до него достучится.

Обратите внимание: агент монтирует /var/run/docker.sock — это значит, что контейнеры сборки получают доступ к Docker-демону хоста наравне с самим Woodpecker. Для чужого, недоверенного кода (публичные форки в PR) это небезопасно — там нужна отдельная изоляция (rootless-раннер или отдельная VM под сборки), но для внутренних приватных репозиториев такой setup — стандартная практика.

Поднимаем:

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

Reverse-proxy и HTTPS

Server слушает 127.0.0.1:8000 — наружу его напрямую не публикуем, ставим перед ним reverse-proxy с автоматическим SSL. Быстрее всего это делает Caddy — конфиг из статьи про Caddy с авто-SSL на VPS сокращённо выглядит так:

ci.example.com {
    reverse_proxy 127.0.0.1:8000
}

Caddy сам выпустит и продлит сертификат Let's Encrypt при условии, что DNS-запись ci.example.com уже указывает на IP вашего VPS, а порты 80/443 открыты.

Если у вас уже стоит Traefik как единая точка входа для нескольких сервисов на сервере, добавьте лейблы к woodpecker-server в compose-файле вместо отдельного Caddy — логика та же, что для любого HTTP-сервиса за Traefik.

Проверьте, что порт 9000 (gRPC между server и agent) слушает только docker-compose внутри общей сети контейнеров и не проброшен наружу — в примере выше он вообще не вынесен в ports, что и требуется, если agent живёт на том же хосте. Если агент выносите на отдельный сервер, gRPC придётся публиковать и защищать TLS-сертификатом отдельно — для старта проще держать server и agent на одной машине.

Первый пайплайн: .woodpecker.yml

Зайдите на https://ci.example.com, авторизуйтесь через Gitea (или ваш провайдер), включите нужный репозиторий переключателем в списке — теперь на пуш в него будет приходить вебхук и создаваться пайплайн.

В корне репозитория создайте .woodpecker.yml:

steps:
  install:
    image: node:20
    commands:
      - npm ci

  test:
    image: node:20
    commands:
      - npm test

  build:
    image: node:20
    commands:
      - npm run build
    when:
      branch: main

  deploy:
    image: alpine:3
    commands:
      - echo "деплой на прод"
    when:
      branch: main
      event: push

Каждый шаг — отдельный контейнер, они выполняются последовательно (если не указано иное через depends_on), а между шагами общее рабочее пространство — файлы, созданные на этапе install, доступны на test и build. Секция when фильтрует, при каких событиях и ветках шаг вообще запускается — это заменяет отдельные if из более сложных CI.

Секреты (токены, пароли) не пишите в YAML — добавляйте их через UI: Repository → Settings → Secrets, а в пайплайне обращайтесь как к переменной окружения:

  deploy:
    image: alpine:3
    commands:
      - echo "$DEPLOY_TOKEN" | some-deploy-tool
    secrets: [ deploy_token ]

Коммитите .woodpecker.yml и делаете push — в веб-интерфейсе увидите живой лог сборки по шагам, с таймингами и кодами возврата каждой команды.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Чем Woodpecker принципиально лучше или хуже Drone CI?

Функционально почти идентичен последней открытой версии Drone, но развивается дальше и остаётся полностью бесплатным без ограничений по числу параллельных пайплайнов — то, что в текущем Drone доступно только в платном тарифе.

Можно ли использовать SQLite в проде?

Для одного-двух разработчиков и невысокой частоты сборок — да, это же значение по умолчанию. При росте команды и параллельных пайплайнов переходите на Postgres через WOODPECKER_DATABASE_DRIVER=postgres и WOODPECKER_DATABASE_DATASOURCE — под нагрузкой SQLite начинает блокироваться на конкурентной записи.

Нужен ли agent на отдельном сервере?

Нет, для старта агент прекрасно живёт в том же docker-compose, что и server, на одном VPS. Отдельные агенты имеет смысл добавлять, когда одного узла не хватает по CPU/RAM под параллельные сборки — тогда добавляете ещё один woodpecker-agent с тем же WOODPECKER_AGENT_SECRET на новом хосте.

Пайплайн падает с ошибкой доступа к Docker внутри шага сборки.

Обычная причина — вы монтируете сокет Docker в сам агент (это нужно для запуска шагов), но пытаетесь дополнительно собирать Docker-образы внутри шага командой docker build. Тогда монтируйте сокет ещё и в конкретный шаг явно через volumes в .woodpecker.yml, либо используйте образ docker:dind для изолированной сборки образов.

Как обновить Woodpecker до новой версии?

docker compose pull && docker compose up -d — при переходе через мажорные версии сверяйтесь с changelog проекта, между релизами иногда меняются имена переменных окружения и структура .woodpecker.yml.

Что делать, если вебхук от Gitea/GitHub не доходит до сервера?

Проверьте, что WOODPECKER_HOST в compose-файле совпадает с реальным внешним доменом (включая https://), а Redirect URI в OAuth-приложении провайдера — с WOODPECKER_HOST плюс /authorize. Расхождение в этих двух местах — самая частая причина, по которой авторизация или вебхуки молча не работают.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →