Копировать файлы вручную долго и ненадёжно. Выберите способ под свой процесс: для личного проекта хватит push на сервер, для команды удобнее деплой из CI.
Способ 1: push прямо на сервер
На сервере создаётся «голый» репозиторий. После каждого push хук post-receive выкладывает код в рабочий каталог и перезапускает приложение.
$ adduser --disabled-password --gecos "" deploy$ mkdir -p /srv/app$ chown deploy:deploy /srv/app$ su - deploy$ git init --bare ~/app.git$ #!/bin/bash$ set -euo pipefail$ TARGET=/srv/app$ BRANCH=main$ while read oldrev newrev ref; do$ if [ "$ref" = "refs/heads/$BRANCH" ]; then$ git --work-tree="$TARGET" --git-dir="$HOME/app.git" checkout -f "$BRANCH"$ cd "$TARGET"$ npm ci --omit=dev$ pm2 reload app$ echo "Deployed $newrev"$ fi$ done$ chmod +x ~/app.git/hooks/post-receiveНа своём компьютере добавьте удалённый репозиторий и отправьте код. Публичный SSH-ключ разработчика должен лежать в /home/deploy/.ssh/authorized_keys.
$ git remote add production deploy@203.0.113.10:app.git$ git push production mainСпособ 2: git pull по deploy-ключу
Код лежит на GitHub или GitLab, а сервер забирает его сам. Deploy key даёт доступ только к одному репозиторию и только на чтение — это безопаснее, чем личный ключ.
$ su - deploy$ ssh-keygen -t ed25519 -f ~/.ssh/deploy_app -N "" -C "deploy@server"$ cat ~/.ssh/deploy_app.pubДобавьте выведенный ключ в настройках репозитория (в GitHub: Settings → Deploy keys, без права записи). Затем укажите ключ для хоста:
Host github.com IdentityFile ~/.ssh/deploy_app IdentitiesOnly yes$ git clone git@github.com:you/app.git /srv/app$ cd /srv/app && git pull --ff-onlyСпособ 3: GitHub Actions по SSH
CI подключается к серверу по отдельному ключу и выполняет команды деплоя. Создайте ключ, положите публичную часть в authorized_keys пользователя deploy, а приватную — в секреты репозитория (Settings → Secrets and variables → Actions) под именем DEPLOY_KEY. Туда же добавьте адрес сервера как DEPLOY_HOST и вывод ssh-keyscan как KNOWN_HOSTS.
$ ssh-keygen -t ed25519 -f ./ci_deploy -N "" -C "github-actions"$ ssh-keyscan -t ed25519 203.0.113.10name: deployon: push: branches: [main]jobs: deploy: runs-on: ubuntu-latest steps: - name: SSH key run: | mkdir -p ~/.ssh echo "${{ secrets.DEPLOY_KEY }}" > ~/.ssh/id_ed25519 chmod 600 ~/.ssh/id_ed25519 echo "${{ secrets.KNOWN_HOSTS }}" > ~/.ssh/known_hosts - name: Deploy run: ssh deploy@${{ secrets.DEPLOY_HOST }} 'cd /srv/app && git pull --ff-only && npm ci --omit=dev && pm2 reload app'Чтобы ограничить CI-ключ, в authorized_keys перед ним можно указать from="адрес" или command="скрипт" — тогда ключ сработает только с нужных адресов или только для одной команды.
Частые ошибки
- Хук не срабатывает — файл post-receive не исполняемый или ветка называется не так, как в BRANCH.
- В хуке «command not found» для npm или pm2 — у неинтерактивной оболочки другой PATH. Пропишите полные пути.
- git pull просит пароль — репозиторий клонирован по HTTPS, а ключ настроен для SSH. Смените адрес:
git remote set-url origin git@github.com:you/app.git.