Вместо ручного FTP при каждом изменении — настройте git push для автоматического деплоя. Занимает 15 минут, экономит часы работы.
Деплой на VPS через Git bare repo
# На VPS: создать bare репозиторий
mkdir -p /var/repo/mysite.git
cd /var/repo/mysite.git
git init --bare
# Создать хук post-receive
nano hooks/post-receive
#!/bin/bash
GIT_WORK_TREE=/var/www/mysite git checkout -f main
echo "Deployed to /var/www/mysite"
chmod +x hooks/post-receive
# На локальном компьютере:
git remote add production user@server-ip:/var/repo/mysite.git
git push production main
Деплой на cPanel хостинг через Git
cPanel → Файлы → Git™ Version Control:
- Create → укажите путь к репозиторию (
public_html) - Укажите URL GitHub/GitLab репозитория
- Нажмите Update from Remote для ручного деплоя
GitHub Actions: полный автодеплой
# .github/workflows/deploy.yml
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy via SSH
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.SERVER_IP }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
cd /var/www/mysite
git pull origin main
composer install --no-dev
php artisan migrate --force
Частые ошибки при Git-деплое
Ниже — сообщения, с которыми реально сталкиваются при первой настройке bare-репозитория и хуков, и что за ними стоит.
Permission denied (publickey).
fatal: Could not read from remote repository.
bash: hooks/post-receive: Permission denied
remote: error: hook declined to update refs/heads/main
error: failed to push some refs to 'server-ip:/var/repo/mysite.git'
fatal: 'production' does not appear to be a git repository
| Сообщение | Причина | Решение |
|---|---|---|
| Permission denied (publickey) | SSH-ключ клиента не добавлен на сервере или используется не тот ключ | Проверить ssh -T user@server-ip -i путь_к_ключу, добавить публичный ключ в ~/.ssh/authorized_keys |
| hooks/post-receive: Permission denied | Хук не помечен исполняемым файлом — пропущен chmod +x | Выполнить chmod +x hooks/post-receive и проверить первую строку файла (#!/bin/bash) |
| hook declined to update refs / failed to push some refs | Сам хук завершился с ненулевым кодом — например, git checkout -f упал из-за прав на рабочей директории | Запустить хук вручную: bash hooks/post-receive, исправить владельца и права на /var/www/mysite |
| fatal: 'production' does not appear to be a git repository | Неверный URL remote или опечатка в пути к bare-репозиторию | Сверить git remote -v с реальным путём на сервере — каталог должен заканчиваться на .git |
Сравнение способов деплоя
| Способ | Нужен SSH | Скорость деплоя | Когда применять |
|---|---|---|---|
| Bare repo + post-receive hook | Да, ключевой доступ обязателен | Мгновенно после git push | VPS с полным доступом, свой пайплайн без сторонних сервисов |
| cPanel Git Version Control | Не обязателен, работает через веб-интерфейс | Вручную по кнопке Update from Remote | Shared-хостинг, разработчик без SSH-доступа |
| GitHub Actions | Да, для шага подключения по SSH к серверу | Автоматически при push в main, 1–3 минуты | Команда, нужны тесты и сборка перед выкладкой |
Когда Git-деплой не подходит
- Сайт хранит пользовательские файлы (медиатеку, загрузки) прямо в рабочей директории репозитория —
git checkout -fпри деплое может задеть их без аккуратного.gitignore - Нужен zero-downtime деплой с мгновенным откатом — простой
checkout -fне даёт атомарной подмены версии, для этого нужна схема с релизами и симлинком на текущий каталог - На хостинге нет ни SSH, ни раздела Git Version Control в панели — тогда остаётся только обычная загрузка по FTP
- В репозитории регулярно меняются тяжёлые бинарные файлы (видео, дампы БД) — Git плохо справляется с ними без Git LFS, а LFS доступен не на каждом сервере
Как проверить, что деплой прошёл успешно
# На сервере: сравнить текущий коммит с тем, что запушили локально
cd /var/repo/mysite.git && git log -1 --oneline
# В рабочей директории: время изменения файлов должно быть свежим
stat -c '%y' /var/www/mysite/index.php
# Сайт отвечает без ошибки 500
curl -I https://yourdomain.com/
- Сравните хеш коммита в bare-репозитории с тем, что было запушено локально — они обязаны совпадать
- Проверьте время изменения файлов в рабочей директории через
stat— оно должно обновиться в момент деплоя - Откройте сайт через
curl -I: если хук отработал, ноcomposer installупал, файлы обновятся, а сайт всё равно сломается - В GitHub Actions проверьте вкладку Actions — последний workflow run должен быть зелёным, даже если
git pushпрошёл без ошибок
Настройку доступа по ключам вместо пароля для самого сервера разбирает статья SSH-доступ на shared-хостинге, а автоматизацию побочных задач после деплоя — материал про cron-задачи в cPanel.
Частые вопросы
Как настроить деплой без простоя и с быстрым откатом, если git checkout -f не атомарен?
Простой checkout -f подменяет файлы прямо в рабочей директории, и сайт на секунду видит неполный набор файлов. Для надёжности код разворачивают в отдельную папку для каждого релиза и держат симлинк на текущую версию: хук собирает новый релиз, проверяет его и переключает симлинк одной операцией. Откат — просто симлинк на предыдущую папку.
Что произойдёт с файлами, изменёнными вручную прямо на сервере, при следующем git push?
Хук выполняет git checkout -f, а это значит принудительную перезапись отслеживаемых файлов версией из коммита — любая ручная правка конфига или кода прямо на сервере исчезнет без предупреждения при следующем деплое. Пользовательские загрузки и медиатеку это не трогает, только если они не отслеживаются репозиторием и описаны в .gitignore.
Как откатиться к предыдущей версии сайта, если новый деплой сломал работу?
На VPS с bare-репозиторием достаточно переключиться на нужный коммит в рабочей директории командой git checkout и заново выполнить шаги хука вручную — composer install и миграции при необходимости. В cPanel проще указать в Git Version Control предыдущий коммит и снова нажать обновление из удалённого репозитория. Для мгновенного отката полезна схема релизов с симлинком.
Стоит ли переходить на GitHub Actions, если уже настроен git push через bare-репозиторий?
Bare-репозиторий с хуком быстрее и проще для одиночного разработчика — деплой происходит сразу после push без ожидания внешнего сервиса. GitHub Actions оправдан, когда перед выкладкой нужны сборка, тесты или шаг composer install с проверкой результата: пайплайн остановит деплой при ошибке сборки, тогда как простой хук применит код в любом случае.