При автоматизации деплоя 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).
Два рабочих подхода:
- Деплоить под пользователем, у которого владелец файлов совпадает с тем, что ожидает веб-сервер.
- После 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 только там, где они действительно нужны.
