31 января 2026 г.

GitHub, Docker и деплой: база вайб-кодера

Практический гайд по основным инструментам для деплоя проекта на продакшн: GitHub CLI, Docker, SSH, GitHub Actions, Nginx и SSL сертификаты.

Дисклеймер: Это базовые практики, которые помогут задеплоить проект на VPS и обеспечить его работоспособность. Для поддержки продакшн-версий и аудита безопасности инфраструктуры рекомендуется обращаться к профессиональным DevOps-инженерам.

Версии ПО, описанные в статье, актуальные на февраль 2026 года

  • OS Server: Ubuntu 24.04 LTS (Noble Numbat)
  • Docker: Engine 27+, Compose V2 (команда docker compose)
  • Node.js: 22 LTS (Active LTS на 2026)
  • GitHub CLI (gh): v2.50+
  • GitHub Actions: actions/checkout@v4, appleboy/ssh-action@v1.2.0

Термины

  • Git — система контроля версий. Позволяет сохранять историю изменений кода и работать над проектом в команде.
  • VPS (Virtual Private Server) — арендованный виртуальный сервер, "удаленный компьютер", который работает круглосуточно.
  • SSH (Secure Shell) — протокол для безопасного управления сервером через командную строку.
  • Docker — технология упаковки приложения в изолированный контейнер со всем необходимым для запуска. Гарантирует, что "работает у меня — заработает и там".
  • Docker Compose — инструмент для запуска нескольких связанных контейнеров (например, приложение + база данных) одной командой.
  • CI/CD — автоматическая доставка кода: после git push система сама тестирует и обновляет приложение на сервере.
  • Local / Dev / Stage / Prod — окружения. Local — компьютер разработчика, Dev — общий сервер для разработки, Stage — тестовый сервер (копия боевого), Prod — боевой сервер с реальными пользователями.
  • Nginx — быстрый веб-сервер. В данном гайде используется как Reverse Proxy — принимает запросы из интернета и передает их приложению.
  • SSL (Secure Sockets Layer) — технология безопасности, создающая зашифрованное соединение между сервером и браузером (HTTPS). Защищает данные пользователей.

Warp: LLM как DevOps помощник

Warp — это современный терминал, который позволяет доверить работу с командной строкой LLM. Вот что это дает:

  • AI Agent Mode: Можно писать на английском или русском что нужно сделать ("SSH to prod и проверь статус докера"), а Warp генерирует команды и показывает diff перед выполнением
  • Seamless SSH: После подключения по SSH на удаленный сервер, можно дать возможность LLM выполнить на нём команды
  • Command blocks: Весь вывод организован в блоки, которые легко искать и скроллить (удобно при дебаге)
  • Notebooks: Комбинирование Markdown-документации с рабочими SSH-командами

Как это работает в вайб-кодинге: Вместо того чтобы помнить все флаги Docker и Nginx, проблема описывается LLM (например, Claude Code) в Warp: "Деплой не прошел, логи говорят permission denied". Warp генерирует команды для диагностики, пользователь смотрит diff и кликает "run".

Установка: brew install warp на macOS, скачать для Linux/Windows.


SSH ключи

Это нужно сделать один раз. После этого будет работать везде.

Генерация SSH ключа

ssh-keygen -t ed25519 -C "your_email@example.com"
# Где your_email@example.com — email, привязанный к GitHub

Система спросит:

  • Путь для сохранения → Просто Enter (по умолчанию ~/.ssh/id_ed25519)
  • Passphrase → Нужно ввести пароль или оставить пусто (рекомендуется пароль)

Создалось два файла:

  • ~/.ssh/id_ed25519 — приватный ключ (хранить в надежном месте)
  • ~/.ssh/id_ed25519.pub — публичный ключ (тот, что добавляется в GitHub)

Добавление ключа в SSH agent

# Стартуем SSH agent
eval "$(ssh-agent -s)"

Добавляем ключ

ssh-add ~/.ssh/id_ed25519

Если задавал пароль, нужно ввести его сейчас

Копирование публичного ключа

# Выведет весь ключ в консоль
cat ~/.ssh/id_ed25519.pub

На macOS удобнее скопировать в буфер сразу:

cat ~/.ssh/id_ed25519.pub | pbcopy

Должен выглядеть так: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5... your_email@example.com

Добавление ключа на GitHub

Веб:

  1. Зайти на github.com/settings/ssh
  2. Нажать "New SSH key"
  3. Title — например "My Laptop" (для удобства, если несколько ключей)
  4. Key — вставить скопированный ключ
  5. Key type — выбрать "Authentication"
  6. "Add SSH key"

Или через CLI:

gh ssh-key add ~/.ssh/id_ed25519.pub --type authentication

🤖 Warp Way: Генерация ключей через Warp:

"Сгенерируй новый ed25519 ssh ключ для my@email.com, добавь в агент и скопируй публичный ключ в буфер обмена" "Добавь ssh ключ в github используя gh cli"

Проверка подключения

ssh -T git@github.com

Если виден вывод типа Hi username! You've successfully authenticated... — готово! ✅

После этого:

  • Клонирование репо через SSH: git clone git@github.com:username/repo.git
  • Пуш без пароля: git push
  • Всё работает везде

GitHub

Создание репозитория с gh CLI

Если GitHub.com уже открыт и работа идет через интерфейс — это нормально, но использование CLI часто экономит время.

Установка gh (GitHub CLI, ориентируемся на v2.50+):

# macOS
brew install gh

Linux (Debian/Ubuntu)

sudo apt install gh

или скачи отсюда: https://cli.github.com

🤖 Warp Way:

"Установи github cli"

Единоразовая аутентификация:

gh auth login
# Выбрать:
# - GitHub.com
# - SSH (безопаснее, мы это уже настроили)
# - Yes to add SSH key to agent

Создание репо прямо из терминала:

# Самый быстрый способ:
gh repo create my-project --public --source=. --push

Где:

--public — делает репо открытым (или --private)

--source=. — берет текущую папку как исходник

--push — сразу пушит в GitHub

Для выбора через интерактивное меню:

gh repo create

Готово. Репо создано, git инициализирован, remote добавлен. За 10 секунд вместо 2 минут в веб-интерфейсе.

Локальная инициализация: git init, git add

Старт нового проекта:

mkdir my-awesome-app
cd my-awesome-app

Инициализация Git

git init

Создание файлов (README, код, etc.)

echo "# My Awesome App" > README.md

Добавление в staging area

git add README.md

Или добавление всего сразу

git add .

Коммит

git commit -m "Initial commit"

Важно: Перед git push необходимо убедиться, что репо создан на GitHub (через gh repo create выше).

# Добавление remote (если gh не сделал это автоматически)
git remote add origin git@github.com:username/my-awesome-app.git

Пуш

git push -u origin main

🤖 Warp Way:

"Инициализируй git репозиторий, добавь все файлы, закоммить как 'Initial commit' и запушь в origin main"

Warp сгенерирует цепочку команд. Останется только нажать Enter.

Docker: упаковать приложение и забыть

Зачем Docker

Один раз создаётся образ — потом одинаково работает на локальной машине, на стейджинге, в продакшене. Это исключает проблемы с различиями версий Node.js и окружения.

Минимум: Dockerfile + compose.yaml

Важно про безопасность: Пароли нельзя хранить в коде. Следует использовать файл .env.

Dockerfile — рецепт сборки образа приложения:

# Берём готовый образ Node (версия 22 LTS - Active в 2026)
FROM node:22-alpine

Рабочая директория в контейнере

WORKDIR /app

Копируем package.json и package-lock.json

COPY package*.json ./

Устанавливаем зависимости

RUN npm install

Копируем весь код

COPY . .

Какой порт слушает приложение

EXPOSE 3000

Команда для запуска

CMD ["npm", "start"]

compose.yaml (раньше назывался docker-compose.yml, но V2 рекомендует новое имя) — упрощает запуск локально и на сервере:

# В Docker Compose V2 поле version (например, '3.8') больше не обязательно
services:
  app:
    build: .  # Собираем из Dockerfile
    ports:
      - "3000:3000"  # Локальный порт 3000 → контейнер 3000
    environment:
      NODE_ENV: development
      DATABASE_URL: postgres://postgres:${DB_PASSWORD}@db:5432/myapp
    depends_on:
      - db
    volumes:
      - .:/app  # Горячая перезагрузка (для разработки)
      - /app/node_modules

db: image: postgres:16-alpine # Postgres 16 (Stable) environment: POSTGRES_PASSWORD: ${DB_PASSWORD} POSTGRES_DB: myapp volumes: - postgres_data:/var/lib/postgresql/data

volumes: postgres_data:

Создание файла .env (и добавление его в .gitignore!):

DB_PASSWORD=supersecretpassword123

🤖 Warp Way: Генерация Docker-файлов:

"Создай Dockerfile для приложения Node.js 22 и compose.yaml с базой данных postgres 16"

Запуск:

# Собрать образ и запустить контейнеры
docker compose up -d

-d = запустить в фоне

Логи

docker compose logs -f app

Остановить

docker compose down

🤖 Warp Way:

"Запусти docker compose в фоне" "Следи за логами сервиса app" "Останови все контейнеры docker"

Продвинутый уровень: TypeScript (NestJS / Fastify)

Для TypeScript одного Dockerfile мало — код нужно скомпилировать. Используем Multi-stage build: сборка в одном контейнере, запуск в другом (чистом и легком).

# Stage 1: Сборка
FROM node:22-alpine AS builder
WORKDIR /app

Копируем конфиги зависимостей

COPY package*.json ./

Устанавливаем ВСЕ зависимости (включая devDependencies для сборки)

RUN npm ci

Копируем исходный код

COPY . .

Собираем TypeScript в JavaScript (папка dist)

RUN npm run build

Stage 2: Продакшн (лёгкий образ)

FROM node:22-alpine AS runner WORKDIR /app

COPY package*.json ./

Устанавливаем ТОЛЬКО продакшн зависимости

RUN npm ci --omit=dev

Копируем собранное приложение из Stage 1

COPY --from=builder /app/dist ./dist

EXPOSE 3000

Запускаем (обычно node dist/main.js)

CMD ["node", "dist/main"]

🤖 Warp Way:

"Сгенерируй multi-stage Dockerfile для приложения NestJS используя node:22-alpine с этапами builder и runner"

В чем фишка: Исходники TS и тяжелые dev-пакеты не попадают в итоговый образ. Он весит в 5 раз меньше.


Деплой: из репы на сервер

Подготовка сервера (один раз)

Важно: Сервер должен быть настроен на вход только по SSH ключу. Никаких паролей. Это база безопасности и требование для автоматического деплоя через GitHub Actions.

Ориентируемся на Ubuntu 24.04 LTS. На чистый VPS сначала нужно установить Docker. Одной командой:

curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh # Установит актуальный Docker Engine (v27+)

🤖 Warp Way:

"Установи docker и docker compose на ubuntu используя официальный скрипт"

GitHub Actions

Push в репо → автоматический деплой на сервер. Настраивается один раз.

Что нужно:

  • SSH ключ сервера (без пароля)
  • Адрес сервера
  • Путь, где лежит приложение на сервере

.github/workflows/deploy.yml:

name: Deploy

on: push: branches: - main

jobs: deploy: runs-on: ubuntu-latest # В 2026 году это обычно Ubuntu 24.04 steps: - uses: actions/checkout@v4

  - name: Deploy to server
    uses: appleboy/ssh-action@v1.2.0 # Используем фиксированную версию для стабильности (не master)
    with:
      host: ${{ secrets.SERVER_HOST }}
      username: ${{ secrets.SERVER_USER }}
      key: ${{ secrets.SERVER_SSH_KEY }}
      script: |
        # Если папки нет — клонируем, если есть — просто заходим
        if [ ! -d "/var/www/myapp" ]; then
          git clone git@github.com:username/my-project.git /var/www/myapp
        fi
        cd /var/www/myapp
        
        git pull origin main
        # Создаем .env из секретов (если нужно) или убеждаемся что он есть
        docker compose down
        docker compose up -d --build

🤖 Warp Way:

"Создай workflow github action для деплоя на сервер через ssh при пуше в ветку main используя appleboy/ssh-action"

Что сделать один раз в GitHub:

  1. Settings → Secrets and variables → Actions
  2. Добавить секреты:
    • SERVER_HOST — IP сервера
    • SERVER_USER — пользователь (обычно root или ubuntu)
    • SERVER_SSH_KEY — весь приватный SSH ключ (результат cat ~/.ssh/id_rsa на сервере)

Готово. Теперь каждый git push main деплоит приложение автоматически.

SSH + git pull (для собственного сервера)

Проще, чем Actions. Достаточно зайти на сервер и обновить приложение.

На сервере один раз:

# Клонируем репо
git clone git@github.com:username/my-app.git /var/www/myapp
cd /var/www/myapp

Собираем Docker образ

docker compose build

Запускаем

docker compose up -d

🤖 Warp Way:

"Клонируй https://github.com/username/my-app.git в /var/www/myapp и запусти docker compose в фоне"

После этого, для обновления:

# С локальной машины:
git push origin main

На сервере (или через Warp AI):

cd /var/www/myapp git pull origin main docker compose down docker compose up -d --build

Одна команда для быстрого обновления:

ssh user@server.com "cd /var/www/myapp && git pull && docker compose down && docker compose up -d --build"

🤖 Warp Way: Удаленное управление сервером:

"Зайди по SSH на user@server.com, перейди в /var/www/myapp, подтяни изменения из git и перезапусти docker compose с пересборкой"

Warp сам соберет сложную команду в одну строку.


Nginx и SSL сертификаты

Зачем Nginx

Nginx — это обратный прокси (reverse proxy). Приложение работает на порту 3000, а Nginx слушает порты 80 и 443, принимает трафик и пробрасывает его приложению. Плюсы:

  • HTTPS/SSL в одном месте
  • Возможность держать несколько приложений на одном сервере
  • Кэширование, сжатие, раздача статики

Базовая конфигурация Nginx

Важно: Для Ubuntu 24.04 (Nginx 1.24) используется старый синтаксис listen ... http2. Для более свежих версий Nginx (1.25+) нужно писать http2 on;.

/etc/nginx/sites-available/myapp:

server {
    listen 80;
    server_name example.com www.example.com;

# Перенаправляем HTTP на HTTPS (дальше про это)
return 301 https://$server_name$request_uri;

}

server { listen 443 ssl http2; server_name example.com www.example.com;

# SSL сертификаты (дальше про как их получить)
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

# Пробрасываем трафик приложению на порту 3000
location / {
    proxy_pass http://localhost:3000;
    
    # Важные заголовки
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}

}

Активация конфигурации:

# Создаём symlink
sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/myapp

Проверяем синтаксис

sudo nginx -t

Перезагружаем Nginx

sudo systemctl reload nginx

🤖 Warp Way (включить сайт):

"Включи сайт nginx myapp, создав симлинк из sites-available, проверь конфиг и перезагрузи сервис"

🤖 Warp Way (создать конфиг): Автоматическая генерация конфига:

"Сгенерируй конфиг nginx для домена example.com с проксированием на localhost:3000, http2 и заголовками безопасности. Сохрани его в /etc/nginx/sites-available/myapp"

Он выдаст готовый блок кода или команду cat <<EOF ....

Let's Encrypt и Certbot — бесплатные SSL сертификаты

Установка Certbot:

sudo apt update
sudo apt install certbot python3-certbot-nginx # Версия из репозитория Ubuntu 24.04

🤖 Warp Way:

"Установи certbot для nginx"

Получение сертификата:

sudo certbot --nginx -d example.com -d www.example.com

🤖 Warp Way:

"Запроси ssl сертификат для example.com используя certbot"

Certbot:

  1. Проверяет владение доменом (HTTP challenge на порт 80)
  2. Получает сертификат от Let's Encrypt
  3. Автоматически обновляет Nginx конфиг с SSL директивами
  4. Спрашивает email для напоминаний о продлении

После выполнения:

  • Сертификат в /etc/letsencrypt/live/example.com/
  • Nginx конфиг обновлён (HTTP → HTTPS redirect)
  • HTTPS работает

Проверка возобновления сертификата:

sudo systemctl list-timers | grep certbot
# Должен быть активный таймер

Тест возобновления (безопасно)

sudo certbot renew --dry-run

Сертификаты Let's Encrypt действуют 90 дней, но Certbot продлевает их автоматически.

Дополнительно: безопасность

1. Firewall (UFW) Не стоит оставлять лишние порты открытыми. Рекомендуется закрыть всё, кроме SSH и веба:

sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable

🤖 Warp Way:

"Включи фаервол ufw, разрешив только ssh и http/https трафик"

2. Security Headers Добавляем заголовки в конфиг Nginx:

server {
    listen 443 ssl http2;
    server_name example.com;
    
# ... SSL и proxy_pass ...

# Безопасность
add_header X-Frame-Options &quot;SAMEORIGIN&quot; always;
add_header X-Content-Type-Options &quot;nosniff&quot; always;
add_header X-XSS-Protection &quot;1; mode=block&quot; always;
add_header Referrer-Policy &quot;no-referrer-when-downgrade&quot; always;
add_header Content-Security-Policy &quot;default-src &#39;self&#39; http: https: data: blob: &#39;unsafe-inline&#39;&quot; always;

}

🤖 Warp Way:

"Добавь заголовки безопасности (X-Frame-Options, X-Content-Type-Options и т.д.) в файл конфигурации nginx"

Проверка SSL:

# Локально
curl https://example.com

Или через SSL Labs (https://www.ssllabs.com/ssltest/)

🤖 Warp Way:

"Проверь детали ssl сертификата для example.com используя curl"


Real-world flow: собираем всё вместе

Сценарий: создание Node.js приложения с базой данных.

Инициализация проекта:

mkdir my-app && cd my-app
git init
echo "# My App" > README.md
npm init -y
gh repo create my-app --public --source=. --push

🤖 Warp Way:

"Создай новую папку my-app, инициализируй npm проект, git репозиторий и создай публичный репозиторий github с пушем в origin"

Создание Dockerfile и compose.yaml (как выше с Node + PostgreSQL).

На сервере:

git clone git@github.com:username/my-app.git /var/www/my-app
cd /var/www/my-app
docker compose up -d

🤖 Warp Way:

"Клонируй https://github.com/username/my-app в /var/www/my-app и запусти docker compose в фоне"

Настройка Nginx и SSL (как выше).

Каждый раз при пуше кода:

git push origin main
# На сервере (если используются GitHub Actions, это происходит автоматически):
cd /var/www/my-app && git pull && docker compose down && docker compose up -d --build

🤖 Warp Way:

"Запушь изменения в main и зайди по ssh на сервер, чтобы подтянуть изменения и перезапустить docker compose с пересборкой"


Частые проблемы и решения

Docker контейнер не стартует:

docker compose logs app  # Смотреть логи

🤖 Warp: > "Покажи последние логи контейнера app и объясни ошибки"

Nginx не видит приложение:

# Проверка, что приложение слушает на 3000
docker compose ps  # Контейнер должен быть UP
curl http://localhost:3000  # С сервера

🤖 Warp: > "Проверь, слушается ли порт 3000 и запущен ли docker контейнер"

SSL сертификат истек:

sudo certbot renew  # Обновить сейчас (обычно автоматически)

🤖 Warp: > "Обнови все сертификаты certbot вручную"

Git не пушится (permission denied):

# Проверка SSH ключа
ssh -T git@github.com
# Если ошибка — см. раздел про SSH ключи

🤖 Warp: > "Проверь ssh соединение с github"


Итого

  • Warp — терминал, который понимает команды на английском
  • gh CLI — создание репо за 10 секунд
  • SSH ключи — один раз настроить, потом забыть
  • Docker — одна команда docker compose up, и всё работает везде
  • GitHub Actions — push в репо, и приложение деплоится автоматически
  • Nginx + Let's Encrypt — HTTPS за 5 минут

Полезные ссылки