Деплой на VPS с nginx

Проект на Vite в режиме разработки опирается на dev-сервер с HMR, проксированием модулей и динамической трансформацией кода. Для деплоя на VPS требуется финальная статическая сборка, которая формируется командой сборки.

npm run build

После выполнения команды создаётся каталог dist, содержащий оптимизированные ресурсы: JavaScript-бандлы, CSS, шрифты, изображения и HTML-точку входа. Важная особенность Vite — хеширование файлов, что позволяет безопасно настраивать агрессивное кэширование на уровне nginx.

Внутренняя структура dist обычно выглядит следующим образом:

dist/
  assets/
    index-8f3a1c2d.js
    index-4b91d1e6.css
  index.html

Каждый файл в assets содержит уникальный hash, зависящий от содержимого. Это исключает необходимость ручного управления версионированием статики.


Перенос собранного проекта на VPS

После сборки содержимое dist переносится на сервер. На практике используются rsync или scp.

rsync -avz dist/ user@server_ip:/var/www/vite-app

или

scp -r dist/* user@server_ip:/var/www/vite-app

На сервере заранее создаётся директория для проекта:

mkdir -p /var/www/vite-app

Важный момент — переносится только результат сборки, без node_modules и исходного кода, так как nginx работает со статическими файлами.


Установка nginx на VPS

На большинстве Linux-дистрибутивов установка выполняется стандартным пакетным менеджером.

apt update
apt install nginx

После установки сервис запускается автоматически:

systemctl status nginx

Корневая директория nginx по умолчанию:

/var/www/html

Однако для отдельных приложений создаётся собственный server block.


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

Для Vite-приложения создаётся отдельный конфиг:

nano /etc/nginx/sites-available/vite-app

Пример конфигурации:

server {
    listen 80;
    server_name example.com;

    root /var/www/vite-app;
    index index.html;

    location / {
        try_files $uri $uri/ /index.html;
    }
}

Активация сайта:

ln -s /etc/nginx/sites-available/vite-app /etc/nginx/sites-enabled/
nginx -t
systemctl reload nginx

Поддержка SPA-роутинга

Vite часто используется для SPA-приложений (React, Vue, Svelte). В таком случае маршрутизация обрабатывается на клиенте, а nginx должен всегда отдавать index.html, если файл не найден.

Ключевая директива:

try_files $uri $uri/ /index.html;

Поведение:

  • если запрашивается /assets/index.js — отдаётся файл
  • если запрашивается /dashboard — возвращается index.html
  • роутинг обрабатывается JavaScript-приложением

Без этой настройки при обновлении страницы на внутренних маршрутах возникает 404 ошибка.


Настройка кэширования статики

Vite генерирует файлы с хешами, поэтому можно безопасно включать долгосрочное кэширование.

location /assets/ {
    expires 1y;
    add_header Cache-Control "public, immutable";
}

Для HTML-каркаса кэширование отключается:

location /index.html {
    expires -1;
    add_header Cache-Control "no-cache";
}

Такое разделение позволяет ускорить загрузку без риска устаревших версий приложения.


Сжатие gzip и brotli

Сжатие снижает объём передаваемых данных, особенно для JS-бандлов.

Активация gzip:

gzip on;
gzip_types text/plain text/css application/javascript application/json;
gzip_min_length 1000;

Если доступен brotli-модуль:

brotli on;
brotli_types text/plain text/css application/javascript application/json;

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


Заголовки безопасности

Для production-развёртывания добавляются базовые HTTP-заголовки:

add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options DENY;
add_header X-XSS-Protection "1; mode=block";
add_header Referrer-Policy no-referrer-when-downgrade;

При необходимости можно включить Content Security Policy:

add_header Content-Security-Policy "default-src 'self'; script-src 'self'";

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

Для доменного имени подключается SSL-сертификат через certbot.

Установка:

apt install certbot python3-certbot-nginx

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

certbot --nginx -d example.com

После выполнения автоматически добавляется HTTPS-конфигурация:

server {
    listen 443 ssl;
    server_name example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    root /var/www/vite-app;

    location / {
        try_files $uri $uri/ /index.html;
    }
}

Дополнительно добавляется редирект HTTP → HTTPS:

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

Особенности base path в Vite

При размещении приложения не в корне домена требуется настройка base в vite.config.js.

export default {
  base: "/app/"
}

В nginx аналогично:

location /app/ {
    try_files $uri $uri/ /app/index.html;
}

Несоответствие base и nginx-конфигурации приводит к ошибкам загрузки ассетов.


Переменные окружения и runtime конфигурация

Vite подставляет переменные на этапе сборки. Это означает, что изменение API-адреса требует новой сборки:

VITE_API_URL=https://api.example.com

Для VPS-деплоя часто используется разделение окружений:

  • .env.production
  • .env.staging

После изменения переменных выполняется повторный билд и обновление dist.


Типичные проблемы при деплое

404 на обновлении страницы

Причина — отсутствие try_files для SPA. Решение — корректная маршрутизация на index.html.


Не загружаются assets

Причина часто связана с неправильным base в Vite. Проверяется соответствие путей в index.html.


Белый экран

Обычно вызван:

  • ошибкой JavaScript в бандле
  • неправильным MIME-type
  • некорректным путём к API

Проверка выполняется через nginx error.log и DevTools браузера.


Логи и диагностика nginx

Основные логи:

/var/log/nginx/access.log
/var/log/nginx/error.log

Просмотр в реальном времени:

tail -f /var/log/nginx/error.log

При проблемах с маршрутизацией или отдачей файлов логирование является основным источником диагностики.


Обновление приложения без простоя

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

rsync -avz --delete dist/ user@server:/var/www/vite-app

Благодаря хешированным ассетам старые файлы не конфликтуют с новыми, а переход происходит мгновенно после перезагрузки страницы.

При необходимости минимизации риска используется промежуточная директория:

/var/www/releases/20260529_01/

и переключение symlink:

/var/www/current -> /var/www/releases/20260529_01

nginx указывает на /var/www/current.