Как настроить Github Actions

Неудобно гонять файлы на хостинг вручную, хочется чтобы при коммите изменённые файлы отправлялись автоматически. С этим нам поможет Github Actions.

Вводные данные

  • Хостинг — Beget
  • Редактор — Cursor
  • FPT-клиент — Forklift

Если у вас что-то отличается, ищите похожие кнопки, настройки.

План

  1. Создаём доступ на хостинге
  2. Прописываем Secrets
  3. Создаём файл workflow
  4. Делаем коммит, который запускает автозагрузку.

Создаём доступ

На хостинге создаём FTP-доступ. На Бегете это находится на главном экране.

  1. Прописываем логин, сохраняем
  2. Создаём пароль, сохраняем.
  3. В выпадающем списке выбираем путь до папки проекта. Если у вас такого нет, вы потом сможете прописать путь до папки.
  4. Сохраняем сервер.
  5. Кликаем на Включить SSH
  6. Нажимаем на Добавить

Прописываем Secrets

Переходим в настройки репозитория и нажимаем на Secrets and Variables и нажимаем Actions.

После этого нам необходимо нажать на кнопку New repository secret

После этого откроется форма для заполнения.

Здесь мы должны вписать те данные, которые мы сохраняли при создании FTP-доступа. Для каждого из нижеперечисленных надо создать свой Secret.

FTP_SERVER — название сервера

FTP_USERNAME — логин

FTP_PASSWORD — пароль

FTP_SERVER_DIR — путь до папки должен быть просто /, так как мы уже в FTP-доступе прописали путь до папки. Но если у вас не было выбора папки при создании FTP доступа, вы здесь указываете полный путь до папки. На конце обязательно должен быть /

В итоге это будет выглядеть так

Если вы писали что-то неправильно, не переживайте. Вы можете удалить Secret и создать заново.

Создаём файл deploy. yml

  1. В корне проекта создаём папку .github,
  2. Внутри папку workflows
  3. Внутри неё файл deploy.yml

Содержание файла deploy. yml

Мне его написала нейронка. Если вы используете Cursor, то попросите её написать файл под ваш проект.

name: Deploy Project

on:
  push:
    branches: [ main, master ]
    paths-ignore:
      - 'README.md'
      - '.github/**'
      - '.gitignore'
  workflow_dispatch:

jobs:
  deploy:
    runs-on: ubuntu-latest
    
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 1
        
      - name: Deploy to production
        uses: SamKirkland/FTP-Deploy-Action@v4.3.4
        with:
          server: ${{ secrets.FTP_SERVER }}
          username: ${{ secrets.FTP_USERNAME }}
          password: ${{ secrets.FTP_PASSWORD }}
          server-dir: ${{ secrets.FTP_SERVER_DIR }}
          dangerous-clean-slate: false
          dry-run: false
          exclude: |
            **/.git*
            **/.git*/**
            **/node_modules/**
            README.md
            .htpasswd
            .env
            .env.*
          local-dir: ./
          timeout: 60000
          protocol: ftp
          state-name: .ftp-deploy-sync-state.json 

Делаем коммит

Делаем коммит и после коммита должна запуститься загрузка на хостинг. Проверять во вкладке Actions

Вы можете кликнуть на него и посмотреть, как он проходил. Если будут какие-то ошибки, он покажет их здесь. После исправления ошибок можно перезапустить конкретно этот Action, чтобы не делать много коммитов.

Как перенести на другой сайт

У нас всё остается точно так же, кроме пользователя и пароля. Мы настраиваем переменные FTP_SERVER и FTP_SERVER_DIR так, чтобы они ссылались на основной сервер и директорию /, а сам путь вы уже указали при создании FPT на хостинге.

Когда вы создали новый FTP, который привязан к другому сайту, вам в секретах нужно заменить только логин и пароль.

Ускоряем деплой: добавляем rsync к GitHub Actions

Если загрузка по FTP стала тормозить — файлов много, проект вырос — можно переключиться на rsync. Это быстрее и надёжнее. Работает поверх SSH.

Плюс rsync в том, что он загружает только изменённые файлы. FTP-экшен тоже так умеет, но rsync делает это эффективнее — сравнивает файлы по контрольным суммам, а не по дате.

Что нужно для rsync

  • SSH-доступ к серверу (не FTP, а именно SSH)
  • Хостинг должен поддерживать SSH (Beget, Timeweb, VPS — поддерживают)

На shared-хостингах SSH обычно включается отдельно. На Beget это в разделе «SSH-доступ».

Настраиваем SSH-ключи

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

Генерируем ключ

Открываем терминал (или Git Bash на Windows) и вводим:

ssh-keygen -t ed25519 -C "github-actions"

Когда спросит путь — можно оставить по умолчанию или указать свой. Пароль лучше не ставить (просто нажать Enter).

Получим два файла:

  • id_ed25519 — приватный ключ (никому не показываем)
  • id_ed25519.pub — публичный ключ (добавим на сервер)

Добавляем публичный ключ на сервер

Копируем содержимое id_ed25519.pub.

На Beget идём в SSH-доступ → SSH-ключи → добавляем новый ключ. Вставляем содержимое публичного ключа.

На других хостингах ищем похожий раздел. Или подключаемся по SSH с паролем и добавляем ключ в файл ~/.ssh/authorized_keys:

echo "тут-содержимое-публичного-ключа" >> ~/.ssh/authorized_keys

Добавляем приватный ключ в GitHub

Идём в настройки репозитория → Secrets and Variables → Actions.

Создаём новый секрет:

  • Имя: SSH_PRIVATE_KEY
  • Значение: всё содержимое файла id_ed25519 (включая -----BEGIN… и -----END…)

Также добавляем:

  • SSH_HOST — адрес сервера (например, server123.hosting.ru)
  • SSH_USER — имя пользователя SSH
  • SSH_PORT — порт SSH (обычно 22, на Beget — 22)

Меняем workflow

Открываем файл .github/workflows/deploy.yml и меняем его содержимое:

name: Deploy Project

on:
  push:
    branches: [ main, master ]
    paths-ignore:
      - 'README.md'
      - '.github/**'
      - '.gitignore'
  workflow_dispatch:

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 1

      - name: Setup SSH
        run: |
          mkdir -p ~/.ssh
          echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_ed25519
          chmod 600 ~/.ssh/id_ed25519
          ssh-keyscan -p ${{ secrets.SSH_PORT }} ${{ secrets.SSH_HOST }} >> ~/.ssh/known_hosts

      - name: Deploy with rsync
        run: |
          rsync -avz --delete 
            --exclude '.git' 
            --exclude '.github' 
            --exclude 'node_modules' 
            --exclude '.env' 
            --exclude '.env.*' 
            --exclude 'README.md' 
            -e "ssh -p ${{ secrets.SSH_PORT }}" 
            ./ ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}:${{ secrets.DEPLOY_PATH }}

Добавляем ещё один секрет:

  • DEPLOY_PATH — путь до папки проекта на сервере (например, /home/user/public_html/project/)

Что делает rsync

Разберём команду:

  • -a — архивный режим (сохраняет права, даты, рекурсивно)
  • -v — показывает что загружает
  • -z — сжимает при передаче
  • --delete — удаляет на сервере файлы, которых нет в репозитории
  • --exclude — исключает файлы из загрузки
  • -e «ssh -p …» — указывает порт SSH

Если хочется оставить FTP как запасной вариант

Можно сделать два workflow — один для rsync, другой для FTP. Запускать вручную тот, который нужен.

Создаём .github/workflows/deploy-rsync.yml:

name: Deploy (rsync)

on:
  workflow_dispatch:

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 1

      - name: Setup SSH
        run: |
          mkdir -p ~/.ssh
          echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_ed25519
          chmod 600 ~/.ssh/id_ed25519
          ssh-keyscan -p ${{ secrets.SSH_PORT }} ${{ secrets.SSH_HOST }} >> ~/.ssh/known_hosts

      - name: Deploy with rsync
        run: |
          rsync -avz --delete 
            --exclude '.git' 
            --exclude '.github' 
            --exclude 'node_modules' 
            --exclude '.env' 
            --exclude '.env.*' 
            --exclude 'README.md' 
            -e "ssh -p ${{ secrets.SSH_PORT }}" 
            ./ ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}:${{ secrets.DEPLOY_PATH }}

А старый FTP-вариант переименовываем в deploy-ftp.yml. Теперь во вкладке Actions можно выбрать нужный вариант и запустить вручную.

Автоматический выбор: rsync основной, FTP если упал

Можно сделать хитрее — сначала пробуем rsync, если не получилось — откатываемся на FTP:

name: Deploy Project

on:
  push:
    branches: [ main, master ]
    paths-ignore:
      - 'README.md'
      - '.github/**'
      - '.gitignore'
  workflow_dispatch:

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 1

      - name: Try rsync deploy
        id: rsync
        continue-on-error: true
        run: |
          mkdir -p ~/.ssh
          echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_ed25519
          chmod 600 ~/.ssh/id_ed25519
          ssh-keyscan -p ${{ secrets.SSH_PORT }} ${{ secrets.SSH_HOST }} >> ~/.ssh/known_hosts 2>/dev/null
          rsync -avz --delete 
            --exclude '.git' 
            --exclude '.github' 
            --exclude 'node_modules' 
            --exclude '.env' 
            --exclude '.env.*' 
            --exclude 'README.md' 
            -e "ssh -p ${{ secrets.SSH_PORT }}" 
            ./ ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}:${{ secrets.DEPLOY_PATH }}

      - name: Fallback to FTP
        if: steps.rsync.outcome == 'failure'
        uses: SamKirkland/FTP-Deploy-Action@v4.3.4
        with:
          server: ${{ secrets.FTP_SERVER }}
          username: ${{ secrets.FTP_USERNAME }}
          password: ${{ secrets.FTP_PASSWORD }}
          server-dir: ${{ secrets.FTP_SERVER_DIR }}
          dangerous-clean-slate: false
          exclude: |
            **/.git*
            **/.git*/**
            **/node_modules/**
            README.md
            .htpasswd
            .env
            .env.*
          local-dir: ./
          timeout: 60000
          protocol: ftp

Так если SSH не настроен или что-то сломалось — загрузится по FTP.

Частые проблемы

Permission denied (publickey)

Ключ не добавлен на сервер или добавлен неправильно. Проверь, что публичный ключ (.pub) добавлен в authorized_keys на сервере.

Host key verification failed

GitHub не знает сервер. Строка с ssh-keyscan должна это исправить. Если не помогает — проверь адрес сервера и порт.

rsync: command not found

На некоторых дешёвых хостингах rsync не установлен. Тогда либо просим хостинг поставить, либо остаёмся на FTP.

Connection timed out

Скорее всего, закрыт порт SSH или неправильный адрес. Проверь настройки SSH на хостинге.

Итого

rsync быстрее FTP, особенно на больших проектах. Загружает только изменения, не гоняет всё заново. Работает по SSH — надёжнее и безопаснее.

Минус — нужен SSH-доступ. На shared-хостингах он есть не везде или его нужно включать отдельно. Но если есть — однозначно стоит перейти.

Разница во времени между FTP и rsync