Деплой Go приложения на VPS: продвинутое руководство

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение: От разработки до production-сервера на Go

Вы написали высокопроизводительное веб-приложение на Go (Golang). Компиляция в один бинарник, статическая типизация, встроенная работа с сетью — всё это даёт фору Node.js или Python. Но «оно работает на моей машине» — не аргумент для продакшена. Продвинутый деплой Go приложения на VPS — это не просто копирование файлов по SSH. Это настройка CI/CD пайплайна, контейнеризация, reverse proxy, автоматическое обновление сертификатов, мониторинг и graceful shutdown.

В этой статье мы разберём полный production-ready сценарий для Golang-приложения на Ubuntu 22.04 LTS. Вы узнаете, как настроить Docker-сборку, организовать zero-downtime деплой через GitHub Actions, прикрутить Nginx с SSL и настроить мониторинг метрик Prometheus.

1. Подготовка VPS и настройка окружения

Предположим, у вас есть VPS (DigitalOcean, Hetzner, Timeweb) с Ubuntu 22.04. Первым делом обновляем систему и устанавливаем базовый набор инструментов:

ssh root@your_server_ip
apt update && apt upgrade -y
apt install -y git curl htop net-tools ufw

Создаём пользователя deploy с sudo-правами (без пароля, только по SSH-ключу):

adduser deploy
usermod -aG sudo deploy
mkdir /home/deploy/.ssh
cp ~/.ssh/authorized_keys /home/deploy/.ssh/
chown -R deploy:deploy /home/deploy/.ssh
chmod 700 /home/deploy/.ssh && chmod 600 /home/deploy/.ssh/authorized_keys

Настраиваем фаервол UFW:

ufw allow OpenSSH
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable

Важно: Отключаем вход для root в /etc/ssh/sshd_config (PermitRootLogin no) и перезапускаем SSH (systemctl restart sshd).

1.1 Установка Docker и Docker Compose

Для Go-приложения контейнеризация — стандарт де-факто. Устанавливаем Docker по официальной инструкции:

curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh
usermod -aG docker deploy

Проверяем версию: docker --version. Далее устанавливаем Docker Compose v2 (плагин):

apt install -y docker-compose-plugin

2. CI/CD пайплайн с GitHub Actions и Docker

Продвинутый деплой подразумевает автоматизацию. Мы будем использовать GitHub Actions для сборки образа и отправки его на сервер через SSH с последующим запуском нового контейнера.

Структура проекта на Go:

myapp/
├── main.go
├── go.mod
├── Dockerfile
├── docker-compose.yml
└── .github/workflows/deploy.yml

Dockerfile (Multi-stage build):

FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /app/myapp .

FROM alpine:latest
RUN apk --no-cache add ca-certificates tzdata
WORKDIR /root/
COPY --from=builder /app/myapp .
EXPOSE 8080
CMD ["./myapp"]

docker-compose.yml (для production):

version: '3.8'
services:
  app:
    image: ghcr.io/your_username/myapp:latest
    restart: always
    ports:
      - "127.0.0.1:8080:8080"
    environment:
      - DB_URL=postgres://user:pass@db:5432/mydb
    depends_on:
      - db
  db:
    image: postgres:16-alpine
    restart: always
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
    volumes:
      - pg_data:/var/lib/postgresql/data
volumes:
  pg_data:

GitHub Actions workflow (.github/workflows/deploy.yml):

name: Deploy Go App
on:
  push:
    branches: [ main ]
jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Login to GitHub Container Registry
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GHCR_TOKEN }}
      - name: Build and push Docker image
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ghcr.io/your_username/myapp:latest
      - name: Deploy via SSH
        uses: appleboy/ssh-action@v1.0.3
        with:
          host: ${{ secrets.VPS_HOST }}
          username: ${{ secrets.VPS_USER }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script: |
            cd /home/deploy/myapp
            docker compose pull
            docker compose up -d --remove-orphans
            docker image prune -f

Не забудьте добавить секреты в репозиторий: GHCR_TOKEN, VPS_HOST, VPS_USER, SSH_PRIVATE_KEY.

3. Reverse Proxy Nginx, SSL и Systemd Service

Запускать Go-приложение напрямую на порту 80 — плохая практика. Используем Nginx как reverse proxy, который будет отдавать статику, проксировать запросы к нашему приложению и терминировать SSL.

3.1 Установка Nginx и Certbot

apt install -y nginx certbot python3-certbot-nginx

Создаём конфиг для нашего домена (/etc/nginx/sites-available/myapp.example.com):

server {
    listen 80;
    server_name myapp.example.com;
    return 301 https://$server_name$request_uri;
}

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

    ssl_certificate /etc/letsencrypt/live/myapp.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/myapp.example.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host                

Блоги

Рекомендаций по книгам