При автоматизации деплоя WordPress через GitHub Actions на VPS важно не просто «залить файлы на сервер», а выстроить понятную и управляемую схему обновлений. Без этого легко столкнуться с ситуациями, когда обновления ломают сайт, перезаписываются пользовательские данные или возникают расхождения между средами.

Чтобы деплой WordPress на VPS с GitHub Actions был предсказуемым, важно заранее разделить «код» и «данные».

Код обычно включает:

  • wp-content/themes (темы)
  • wp-content/plugins (плагины)
  • wp-content/mu-plugins (если используете)
  • отдельные файлы конфигурации проекта (например, .htaccess, если работаете с Apache)
  • иногда — wp-content/uploads, если вы храните загрузки в репозитории (что встречается реже)

Данные обычно включают:

  • база данных MySQL/MariaDB (контент, настройки, пользовательские данные)
  • wp-content/uploads (медиафайлы), если они живут на сервере

rsync в этой схеме работает с файлами. Поэтому наиболее стабильный подход такой: деплоим код через rsync, а базу и медиа обновляем отдельными шагами (или вовсе не трогаем при каждом коммите), если это не требуется.

Ниже рассмотрен практичный вариант: репозиторий содержит то, что вы меняете в коде (темы/плагины и часть конфигов), а на VPS уже заранее установлен WordPress и настроены веб-сервер и база.

Подготовка VPS: веб-сервер, PHP, база и структура WordPress

Перед настройкой GitHub Actions и rsync сначала доведите VPS до состояния «WordPress уже работает».

Базовые требования

Вам обычно нужны:

  • веб-сервер (nginx или Apache)
  • PHP-FPM
  • MySQL или MariaDB
  • доступ по SSH с пользователем, под которым будет выполняться деплой

Для упрощения дальнейших действий заранее выберите путь, куда WordPress будет установлен, например:

  • /var/www/site
  • /srv/www/site

В nginx/Apache часто используют модель «одна директория на один сайт». Это удобно для rsync и прав.

Структура каталогов, которую стоит сохранить

Минимально вам нужны:

  • /var/www/site (корень сайта)
  • /var/www/site/wp-content/uploads (загрузки)
  • /var/www/site/wp-content/themes (темы)
  • /var/www/site/wp-content/plugins (плагины)
  • /var/www/site/wp-config.php (конфиг)

Если вы хотите более безопасные релизы (минимум шансов получить «полусобранный» сайт), можно добавить уровень релизов, но это опционально. Самый простой старт — деплой прямо в корень WordPress.

Настройка wp-config.php

В wp-config.php держатся ключи подключения к базе и настройки WordPress. Обычно этот файл не нужно перезаписывать автоматически из Git.

Поэтому заранее решите правило:

  • wp-config.php остаётся только на VPS и не коммитится в репозиторий
  • в репозитории хранится шаблон или только то, что безопасно обновлять

Это уменьшает риск случайно затереть прод-конфигурацию.

Подготовка репозитория: что хранить в Git, а что оставить на сервере

Чтобы деплой WordPress на VPS через rsync не превращался в бесконечные исключения, держите репозиторий «разумно минимальным».

Вариант, который чаще всего работает

Рекомендуемая структура репозитория:

  • themes/ (или wp-content/themes/…)
  • plugins/ (или wp-content/plugins/…)
  • deploy/ (скрипты, шаблоны файлов, если нужно)
  • конфиги проекта, которые не содержат секретов

Что не стоит класть в репозиторий:

  • wp-config.php
  • файлы с секретами БД/ключами
  • uploads (медиа) для большинства сценариев
  • весь WordPress core (если только вы не ведёте его как часть собственного приложения)

Проблема с тем, чтобы коммитить всё подряд, обычно одна: любой коммит превращается в большой rsync, а ещё повышается риск случайных перезаписей.

Как связать репозиторий с wp-content на сервере

Есть два способа:

  • Репозиторий хранит контент так, как на сервере
  • wp-content/themes/…
  • wp-content/plugins/…

Тогда rsync можно нацелить прямо в /var/www/site/wp-content/.

  • Репозиторий хранит темы/плагины вне wp-content
  • themes/…
  • plugins/…

Тогда rsync нужно направить в соответствующие места на VPS, например themes → /var/www/site/wp-content/themes.

Оба подхода рабочие. Первый удобнее, если вы постоянно переносите темы и плагины между серверами.

Убедитесь, что структура экспортируется корректно

Перед настройкой workflow проверьте на локальной машине:

  • что в репозитории лежат только нужные файлы
  • что нет случайных временных папок (node_modules, vendor, если вы их не деплоите)
  • что права на файлы в Git не ломают выполнение (для WordPress обычно достаточно корректных прав чтения)

Если вы используете build-процессы для тем (например, сборка CSS), убедитесь, что в репозиторий попадает итоговый результат сборки.

Настройка SSH для GitHub Actions: ключи, known_hosts и доступ по rsync

GitHub Actions деплоит по SSH. Самая частая ошибка на этом этапе — «прошли авторизацию локально, но в Actions всё падает».

Чтобы rsync работал, у GitHub должен быть SSH-ключ и доступ к VPS.

Создайте SSH-ключ для GitHub Actions

На вашей машине с доступом к серверу сделайте ключ для деплоя. Обычно удобнее создать отдельный ключ для CI, а не использовать ваш личный.

На VPS создайте пользователя для деплоя или используйте существующего. Например, deploy.

Дальше:

  • добавьте public key в ~/.ssh/authorized_keys на VPS для выбранного пользователя
  • проверьте, что вход по SSH проходит без пароля

Настройте секреты в GitHub

В репозитории GitHub откройте Settings → Secrets and variables → Actions и добавьте секреты, например:

  • VPS_HOST
  • VPS_USER
  • VPSSSHKEY (приватный ключ в формате текста)
  • WP_ROOT (путь до корня WordPress на сервере, например /var/www/site)

Важно: VPSSSHKEY добавляйте именно приватный ключ. Не забывайте, что в Secrets нельзя вставлять лишние пробелы и переносы, кроме тех, что формируют PEM-структуру.

Добавьте known_hosts, чтобы убрать сюрпризы

При первом подключении SSH просит подтвердить fingerprint. В CI это приводит к ошибкам вида Host key verification failed.

Надёжная практика — заранее добавить knownhosts. В workflow обычно делают так: получают host key и добавляют в файл knownhosts.

В зависимости от политики безопасности вашего сервера можно:

  • либо явно добавлять host key в known_hosts в workflow
  • либо использовать StrictHostKeyChecking с заранее подготовленным known_hosts

Ниже в примере workflow оба варианта будут учтены концептуально.

Команда rsync для WordPress: исключения, права и перенос без поломок

Теперь самое прикладное: как именно запускать rsync, чтобы деплой WordPress на VPS был «чистым».

Принцип: rsync обновляет код, но не трогает критичные файлы

Если вы деплоите только темы и плагины, то запускаете rsync на wp-content, но с исключениями.

Типичные исключения:

  • исключить wp-content/uploads (если медиа остаются на сервере)
  • исключить wp-config.php
  • при необходимости исключить файлы, которые генерируются на сервере (например, кеши)

Также полезен режим удаления:

  • —delete помогает убрать файлы, удалённые в репозитории

Но —delete опасен, если целевой каталог на сервере содержит «данные», которые вы не хотите трогать. Поэтому сочетайте —delete только там, где синхронизация действительно полная.

Пример rsync: темы и плагины в wp-content

Допустим, репозиторий содержит каталоги themes/ и plugins/. Тогда вы можете синхронизировать их в wp-content.

Пример (адаптируйте пути под вашу схему репозитория):

  • темы → /var/www/site/wp-content/themes/
  • плагины → /var/www/site/wp-content/plugins/

Команда логически такая:

  • rsync -az —delete -e «ssh -p 22» themes/ VPS:/var/www/site/wp-content/themes/
  • rsync -az —delete -e «ssh -p 22» plugins/ VPS:/var/www/site/wp-content/plugins/

Если вы используете wp-content в репозитории напрямую, тогда синхронизация будет проще: один rsync в wp-content.

Права на файлы: частая причина «сайт белый»

После rsync файлы могут оказаться с «не тем» владельцем. Тогда nginx/Apache видит файлы, но PHP не может читать или WordPress не может писать (например, в каталогах cache).

Два рабочих подхода:

  1. Деплоить под пользователем, у которого владелец файлов совпадает с тем, что ожидает веб-сервер.
  2. После rsync делать chown/chmod на удалённой стороне.

Для стабильности чаще применяют второй подход: rsync копирует, а затем команда SSH выставляет корректные владельца и права.

Про атомарность: чтобы не было «полупереноса»

rsync обычно проходит быстро, но на больших проектах или при медленном диске можно получить момент, когда часть файлов обновилась, а часть ещё нет.

Атомарный вариант:

  • rsync копирует в временный каталог релиза
  • затем вы переключаете symlink current → release

Это усложняет настройку, но снижает риск «поймать» неконсистентное состояние в момент деплоя.

Если сайт небольшой, можно начать с простого прямого rsync в live-каталог. Когда деплой станет регулярным и требования к стабильности вырастут, вернитесь к symlink-релизам.

GitHub Actions workflow: сборка и деплой по push в main

Теперь соберём все части в рабочий workflow. Ниже пример, который:

  • берёт код из репозитория
  • подключается к VPS по SSH
  • делает rsync
  • при необходимости запускает wp-cli команды (опционально)

Пример workflow .github/workflows/deploy.yml

Используйте следующий каркас и замените переменные под свою структуру. Важно: WP_ROOT и пути внутри rsync должны соответствовать вашему серверу и репозиторию.

«`yaml name: Deploy WordPress

on: push: branches:

  • main

jobs: deploy: runs-on: ubuntu-latest

steps:

  • name: Checkout

uses: actions/checkout@v4

  • name: Prepare SSH key

env: VPSSSHKEY: ${{ secrets.VPSSSHKEY }} run: | mkdir -p ~/.ssh echo «$VPSSSHKEY» > ~/.ssh/id_rsa chmod 600 ~/.ssh/id_rsa

  • name: Add VPS to known_hosts

env: VPSHOST: ${{ secrets.VPSHOST }} run: | mkdir -p ~/.ssh ssh-keyscan -H «$VPSHOST» >> ~/.ssh/knownhosts

  • name: Rsync themes

env: VPSHOST: ${{ secrets.VPSHOST }} VPSUSER: ${{ secrets.VPSUSER }} WPROOT: ${{ secrets.WPROOT }} run: | rsync -az —delete \ -e «ssh -o ServerAliveInterval=60» \ themes/ «${VPSUSER}@${VPSHOST}:${WP_ROOT}/wp-content/themes/»

  • name: Rsync plugins

env: VPSHOST: ${{ secrets.VPSHOST }} VPSUSER: ${{ secrets.VPSUSER }} WPROOT: ${{ secrets.WPROOT }} run: | rsync -az —delete \ -e «ssh -o ServerAliveInterval=60» \ plugins/ «${VPSUSER}@${VPSHOST}:${WP_ROOT}/wp-content/plugins/»

  • name: Fix permissions (optional)

env: VPSHOST: ${{ secrets.VPSHOST }} VPSUSER: ${{ secrets.VPSUSER }} WPROOT: ${{ secrets.WPROOT }} run: | ssh «${VPSUSER}@${VPSHOST}» » find ‘${WP_ROOT}/wp-content/themes’ -type d -exec chmod 755 {} \; find ‘${WP_ROOT}/wp-content/themes’ -type f -exec chmod 644 {} \; find ‘${WP_ROOT}/wp-content/plugins’ -type d -exec chmod 755 {} \; find ‘${WP_ROOT}/wp-content/plugins’ -type f -exec chmod 644 {} \; » «`

Ключевые моменты workflow

  • Подключение по SSH происходит через приватный ключ из GitHub Secrets.
  • known_hosts добавляется через ssh-keyscan, чтобы избежать вопросов fingerprint.
  • rsync используется с —delete, чтобы удалённые файлы в репозитории исчезали и на сервере.
  • После копирования выставляются права. Это не всегда нужно, но часто экономит время.

Что если у вас wp-content лежит прямо в репозитории

Тогда rsync может быть один:

  • rsync -az —delete wp-content/ user@host:$WP_ROOT/wp-content/

В этом случае внимательно исключите uploads, если они не должны перезаписываться:

  • делайте отдельный rsync для uploads или исключайте uploads из синхронизации кода.

Пример исключения:

  • rsync … —exclude «uploads/» wp-content/

Миграции и обновления: wp-cli, работа с базой данных и кэшами

rsync обновляет файлы. База данных и регенерация некоторых данных — отдельная тема.

Когда база не нужна

Если вы обновляете только код темы/плагина и не меняете структуру данных (например, нет изменения схемы таблиц и нет миграций), базу можно не трогать.

WordPress сам читает настройки и выводит контент, а код плагинов/тем применяется без изменений БД, если миграций не было.

Когда база всё-таки нужна

База требуется, если:

  • плагин включает миграции при активации
  • вы меняете настройки, которые обычно правятся через админку
  • проводите обновления, связанные со схемой данных

В таком случае добавляйте шаги запуска wp-cli на сервере. Общая идея:

  • выполнить wp-cli команду через ssh
  • или запустить скрипт миграций, если он есть в проекте

Пример логики шагов (конкретные команды зависят от того, что вы меняете):

  • обновить структуру/перестроить что-то (если это требуется вашему плагину)
  • деактивировать/активировать плагин, если миграции привязаны к активации
  • выполнить миграцию, если ваш плагин её регистрирует через wp-cli

wp-cli как инструмент в workflow

Если wp-cli установлен на VPS и доступен, workflow может выполнять:

  • wp plugin activate …
  • wp plugin update —all
  • wp rewrite flush
  • wp cache flush (если используете внутренние механизмы кэширования)

Точный набор команд зависит от вашего проекта. Важно не запускать «тяжёлые» сбросы при каждом деплое без необходимости.

Прогрев кэша и PHP opcode cache

На практике обновление PHP-кода может не сразу отразиться, если включён агрессивный opcode cache и он не валидирует изменения файлов по timestamp.

Чаще всего помогает одно из:

  • настройка validate timestamps (это на стороне PHP)
  • перезапуск php-fpm после деплоя (редко нужно постоянно, но иногда требуется)
  • сброс пользовательского кэша/страничного кэша, если он есть (Varnish, nginx caching, CDN)

Если у вас нет кэш-слоёв, дополнительных шагов может не понадобиться.

Проверка деплоя и типичные проблемы: от permissions до перезаписи конфигов

Деплой обычно ломается не в rsync как таковом, а в мелочах вокруг.

Проверка после rsync

После успешного workflow логично проверить:

  • сайт отвечает с нужной версией темы/плагина
  • корректно работают формы/страницы, которые завязаны на обновлённый код
  • отсутствуют ошибки в логах веб-сервера и PHP

Проверки, которые стоит держать в привычке:

  • tail -n 200 логов nginx и PHP-FPM
  • просмотр wp-content/debug.log (если включён отладочный лог в WordPress)
  • подтверждение, что wp-config.php не перезаписан

Типичные ошибки и как их избежать

1. Host key verification failed

Решение: добавить known_hosts в workflow через ssh-keyscan.

2. Permission denied при выполнении php или записи файлов

Причина: владелец/права не совпадают с тем, под кем работает веб-сервер. Решение: деплой под правильным пользователем или chmod/chown после rsync.

3. rsync стирает то, что не должно стираться

Причина: используется —delete для каталога, где есть данные. Решение: ограничивать —delete только теми директориями, где вы синхронизируете «всё»; uploads не включать, если он живёт на сервере.

4. Удалились файлы .htaccess или сломались ЧПУ

Причина: неверный набор файлов в репозитории или исключения в rsync. Решение: сверить, что нужные конфиги (в зависимости от nginx/Apache) попадают на сервер. Если Apache — .htaccess часто критичен.

5. Плагин требует зависимость, а она не деплоится

Причина: зависимости лежат в vendor или build-артефактах, которые вы исключили. Решение: чётко решить, деплоите вы итоговые артефакты в репозитории или собираете их в workflow.

6. GitHub Actions деплоит, но код не применился

Причина: кэш opcode/страничный кэш. Решение: перезагрузить php-fpm (или проверить настройки validate timestamps), при необходимости очистить кэш.

Безопасность и обслуживание: секреты, ротация ключей и стратегия релизов

Автоматизация деплоя добавляет удобство, но и повышает ответственность. Здесь важны мелкие детали.

Права для SSH-пользователя

Не давайте CI-пользователю лишние права:

  • если нужен только rsync и выполнение ограниченных команд, ограничьте доступ
  • используйте отдельного пользователя deploy

Если есть возможность, настройте sudo так, чтобы CI мог выполнять только нужные команды без полного доступа к системе.

Ротация ключей и контроль доступа

Регулярно:

  • обновляйте VPSSSHKEY, если есть подозрение на утечку
  • удаляйте старые ключи с VPS
  • ограничивайте ключ по типам команд (если вы используете advanced SSH restrictions)

Секреты и конфиги

Не храните:

  • пароли БД в репозитории
  • приватные ключи в репозитории

Секреты должны жить только в GitHub Secrets (или в другом секрет-хранилище, если используете).

Версионирование релизов через symlink (опционально)

Когда деплой станет критичным, переход на схему релизов повышает надёжность:

  • rsync в releases/<commit_sha>/
  • переключение symlink current
  • очистка старых релизов по политике

В этой модели вы можете откатиться простым переключением symlink назад.

Минус: нужно продумать права и сценарии, где WordPress ожидает реальные пути. Обычно symlink в корень сайта работает, но если вы используете нестандартные пути в конфигурации, заранее протестируйте.

Итог: как настроить стабильный деплой WordPress на VPS с GitHub Actions и rsync

Деплой WordPress на VPS с GitHub Actions и rsync становится стабильным, когда вы фиксируете три вещи: границы синхронизации (что копируем rsync’ом), отдельное отношение к базе и данным (uploads/БД) и дисциплину прав/конфигов (wp-config.php на сервере, секреты в GitHub Secrets).

Если вы начнёте с деплоя тем и плагинов в wp-content, исключите uploads и не будете трогать wp-config.php на каждом коммите, вы получите рабочую базу для дальнейшего усложнения: кэширование, атомарные релизы через symlink, миграции через wp-cli.

Следующий практический шаг: зафиксируйте структуру репозитория под ваш сервер и соберите минимальный workflow, который делает два rsync-вызова (themes и plugins). После этого добавляйте проверки и команды wp-cli только там, где они действительно нужны.

От mpns_by