Перейти к содержимому
Catshredia
← К блогу

Цикл «сервер на VPS»: настройка конфигурация Nginx и Docker

Настройка сервера Nginx и конфигурации Docker

Развёртывание веб-приложений на одном сервере требует правильной изоляции сервисов и настройки обратного прокси. В этой статье мы разберём практический пример деплоя Next.js приложения с PostgreSQL через Docker и Nginx. Вы узнаете, как настроить multi-stage сборку для оптимизации размера образа, организовать коммуникацию между контейнерами и правильно сконфигурировать Nginx для обработки трафика нескольких доменов.

Docker конфиг catshredias-blog

Первым делом стоит прочитать статью https://habr.com/ru/companies/netologyru/articles/967546/, в ней описывается архитектура технологии и примеры использования для новичков.

На примере конфигурации сайта cathshredias-blog (https://catshredia.ru/) я опишу основные моменты, которые я использовал в Docker.

  • docker-compose.yml - основной файл, в котором описаны образы и их свойства:
services:
  db:
    image: postgres:16-alpine
    container_name: portfolio-db
    restart: unless-stopped
    environment:
      POSTGRES_DB: ${POSTGRES_DB:-portfolio_db}
      POSTGRES_USER: ${POSTGRES_USER:-postgres}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres}
    ports:
      - "127.0.0.1:55433:5432"
    volumes:
      - portfolio_pg_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 5s
      retries: 5

  web:
    build:
      context: .
      dockerfile: Dockerfile
      args:
        NPM_REGISTRY: ${NPM_REGISTRY:-https://registry.npmjs.org}
    container_name: portfolio-web
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy
    ports:
      - "127.0.0.1:3000:3000"
    env_file:
      - .env
    environment:
      DATABASE_URL: postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD:-postgres}@db:5432/${POSTGRES_DB:-portfolio_db}
      AUTH_SECRET: ${AUTH_SECRET}
      AUTH_URL: ${AUTH_URL:-http://localhost:3000}
      NEXT_PUBLIC_SITE_URL: ${NEXT_PUBLIC_SITE_URL:-http://localhost:3000}
      ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@catshredia.ru}
      ADMIN_PASSWORD: ${ADMIN_PASSWORD:-changeme}
      CRON_SECRET: ${CRON_SECRET:-}
      TELEGRAM_BOT_TOKEN: ${TELEGRAM_BOT_TOKEN:-}
      TELEGRAM_CHAT_ID: ${TELEGRAM_CHAT_ID:-}
      TELEGRAM_PROXY_URL: ${TELEGRAM_PROXY_URL:-}
      TURNSTILE_SECRET_KEY: ${TURNSTILE_SECRET_KEY:-}
    volumes:
      - uploads:/app/uploads

#  === образы миграции и засеивания  ===
# указываем volume Для БД и загрузок пользователей
volumes:
  portfolio_pg_data:
  uploads:

  • Dockerfile - файл, который гарантирует масштабируемость и переносимость образов:
# записываем node как базовый образ
FROM node:22-alpine AS base
# устанавливаем пакет совместимости через apk (пакетный менеджер)
RUN apk add --no-cache libc6-compat 
WORKDIR /app #рабочая директория

# сохраняем node образ в другой
FROM base AS deps
# используем зеркало во время установки npm ci
ARG NPM_REGISTRY=https://registry.npmjs.org
COPY package.json package-lock.json ./
RUN npm config set registry "${NPM_REGISTRY}" && npm ci

# создаем образ, который будем билдить и вносим в него зависимости из deps
FROM base AS builder
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npx prisma generate
ENV NEXT_TELEMETRY_DISABLED=1
RUN npm run build

# создаем образ для запуска, копируем зависимости из builder, устанавливаем порты и точки входа
FROM base AS runner
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
RUN addgroup --system --gid 1001 nodejs && adduser --system --uid 1001 nextjs
WORKDIR /app
COPY --from=builder /app/public ./public
COPY --from=builder /app/prisma ./prisma
COPY --from=builder /app/node_modules/.prisma ./node_modules/.prisma
COPY --from=builder /app/node_modules/@prisma ./node_modules/@prisma
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
COPY docker-entrypoint.sh /app/docker-entrypoint.sh
RUN mkdir -p /app/uploads && chown nextjs:nodejs /app/uploads \
  && chmod +x /app/docker-entrypoint.sh
USER nextjs
EXPOSE 3000
ENV PORT=3000
ENV HOSTNAME=0.0.0.0
ENTRYPOINT ["/app/docker-entrypoint.sh"]

Также добавим файл с точками входа:

#!/bin/sh
set -e
exec node .next/standalone/server.js

Обращу внимание на RUN npm config set registry "${NPM_REGISTRY}" && npm ci - настройка зеркала для скачивания через npm ci (для ру региона) и работы в условиях недоступности этих ресурсов.

  • .dockerignore файл - нужен для внесения директорий и файлов в список исключений для Docker (чтобы лишние файлы не попадали в обработку Docker).

Настройка конфигурации: 2 сайта - один сервер

Если существует несколько небольших проектов (не потребляющих много ресурсов, возможно их размещение на одном сервере. Далее, инструкция по настройке такой конфигурации.

У нас уже есть две конфигурации Docker, из них мы берем порты для внешнего трафика, подготовим nginx конфигурации

**/etc/nginx/sites-available/example.ru:**

вместо 3000 подставьте порт из docker конфига

server {
    listen 80;
    server_name example.ru;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        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;
    }
}

**/etc/nginx/sites-available/news.example.ru:**

вместо 8080 подставьте порт из docker конфига

server {
    listen 80;
    server_name news.example.ru;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_http_version 1.1;
        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;
    }

    # дополнительно пример конфига для хабов (например SignalR)
    location /hubs/ {
        proxy_pass http://127.0.0.1:8080/hubs/;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
  • Активируем конфиги

После создания файлов конфигурации необходимо создать символические ссылки в директорию sites-enabled и перезагрузить Nginx:

sudo ln -s /etc/nginx/sites-available/example.ru /etc/nginx/sites-enabled/
sudo ln -s /etc/nginx/sites-available/news.example.ru /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

Настройка HTTPS через Let's Encrypt

В 2026 году работа сайтов только по HTTP считается небезопасной. Браузеры помечают такие сайты как "Not Secure", а поисковые системы понижают их в выдаче. Рассмотрим настройку бесплатных SSL-сертификатов через Certbot.

  • установим Certbot и для каждого выдадим сертификаты
sudo apt update
sudo apt install certbot python3-certbot-nginx

sudo certbot --nginx -d example.ru
sudo certbot --nginx -d news.example.ru

Certbot автоматически:

  • Получит SSL-сертификат от Let's Encrypt
  • Обновит конфигурацию Nginx
  • Настроит редирект с HTTP на HTTPS
  • Добавит задачу в cron для автоматического обновления сертификатов Также возможно создание сертификатов через конфиг:
# Редирект с HTTP на HTTPS
server {
    listen 80;
    server_name example.ru;
    return 301 https://$host$request_uri;
}

# Основной HTTPS блок
server {
    listen 443 ssl http2;
    server_name example.ru;

    # Пути к сертификатам (автоматически создаются Certbot)
    ssl_certificate /etc/letsencrypt/live/example.ru/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.ru/privkey.pem;
    
    # Дополнительные настройки безопасности SSL
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        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;
    }
}

Проверка работы

# Тест конфигурации Nginx
sudo nginx -t

# Перезагрузка Nginx
sudo systemctl reload nginx

# Проверка статуса сертификата
sudo certbot certificates

# Онлайн проверка SSL
# https://www.ssllabs.com/ssltest/

Мы рассмотрели базовую архитектуру деплоя современного веб-приложения. Ключевые моменты: использование multi-stage Dockerfile для уменьшения размера образа, healthchecks для контроля состояния сервисов, и правильная настройка Nginx как reverse proxy. Для production-окружения обязательно добавьте HTTPS, мониторинг ресурсов и автоматические бэкапы базы данных. Помните: безопасность и отказоустойчивость важнее скорости развёртывания.

Комментарии

  • Ioann Pimenov

    Полезная статья, спасибо! Но есть несколько важных моментов, в которых автор неточен или не прав: Nginx-конфигурация неполная Вы показываете только файл в sites-available, но не упоминаете обязательный шаг - создание симлинка в sites-enabled:Bashsudo ln -s /etc/nginx/sites-available/yourdomain.ru /etc/nginx/sites-enabled/ sudo nginx -t && sudo systemctl reload nginxБез этого сайт не будет работать. Отсутствует HTTPS В 2026 году оставлять сайт только на 80 порту - уже не рекомендуется. Стоило бы показать хотя бы базовую конфигурацию с certbot + редирект http => https. Next.js Standalone В docker-entrypoint.sh лучше запускать не node server.js, а:Bashexec node .next/standalone/server.js(в зависимости от структуры после standalone сборки). Мелкие замечания: Лучше использовать Docker network вместо прямого бинда 127.0.0.1:5432:5432. В docker-compose.yml желательно указывать restart: unless-stopped. npm config set registry в Dockerfile обычно не нужен. Статья в целом хорошая и правильно показывает multi-stage build + Prisma, но из-за этих моментов у новичков могут возникнуть проблемы при попытке повторить. Хотелось бы увидеть обновлённую версию с этими правками 👍

    • Admin

      Я рад, что моя статья вам понравилась. По неточностям: - добавил симлинк в статью; - добавил инструкцию по настройке HTTPS и сертификатов в отдельный раздел; - docker-compose.yml желательно указывать restart: unless-stopped. - в данном случае избыточно; - RUN npm config set registry "${NPM_REGISTRY}" && npm ci - зеркало для ру региона, указал в тексте; - docker-compose.yml желательно указывать restart: unless-stopped. - уже указано;

Загрузка…