Статичный сайт с Vite + Caddy + Docker: пошаговое руководство

от автора

В данной статье будет подробно рассмотрен полный цикл деплоя сайта, используюшего Vite в качестве инструмента сборки. Мы напишем многоступенчатый Dockerfile, чтобы собрать образ с готовой статикой, и поднимем контейнер с сервером Caddy, который автоматически выдаст и будет обновлять сертификаты Let’s Encrypt.

Нам понадобится

  1. Арендованный или домашний сервер на Ubuntu с публичным IP

  2. Домен, привязанный к IP

  3. Docker

  4. Готовый проект с vite

  5. Терминал

Структура проекта

Подразумевается, что у вас уже есть проект использующий сборщик Vite, в качестве примера будет показан простой сайт с документацией на VitePress, конфигурация для docker и caddy находится в корневой папке проекта

root├── Caddyfile├── Dockerfile├── docker-compose.yaml├── docs│        ├── index.md│        └── .vitepress├── package-lock.json└── package.json

Сборка проекта

При выполнении команды npm run build создается папка /dist, содержащая файл index.html и плоскую структуру каталога /assets с файлами .js и .css. Сервер Node.js здесь не задействован — на выходе получаются исключительно статические файлы.

Это важно для Docker в продуктовой среде Node.js не требуется. Нужен только сервер для раздачи статических файлов. В качестве сервера в данном примере выбран Caddy — современный веб-сервер, написанный на Go, который распространяется как единый статически скомпилированный бинарник без внешних зависимостей.

Ключевые преимущества

  • Автоматический HTTPS — Caddy получает и обновляет сетрификаты Let’s Encrypt по протоколу ACME прямо из коробки, без необходимости настраивать Certbot или монтировать volume с сертификатами, Для продуктовой среды это означает, что достаточно указать домен в Caddyfile, и сервер сам позабоитстя о шифровании.

  • Простая конфигурация — синтаксис Caddyfile интуитивно понятен и лаконичен. Для раздачи статики из /dist нужна всего одна строча: root * /usr/share/caddy + file_server. В отличии от Nginx, где для базового кейса требуется 10-15 строк с location, alias, try_files и типами mime.

Из минусов можно отметить больший оверхед по ресурсам (из-за рантайма Go), но в контексте раздачи статических файлов разница в 5-10% производительности незаметна.

Конфигурируем Caddy

Ниже приведен пример конфигурации для сервера, с настройками домена, TLS и кэширования

# Привязанный домен, берется из .env файла конфигурации{$DOMAIN} {    # Почта для получения сертификатов Let's Encrypt    tls {$EMAIL}    # Указывает, где находятся файлы сайта    # * означает, что правило применяется ко всем запросам    # Путь /usr/share/caddy — стандартная папка для статики в Caddy    root * /usr/share/caddy    # Включает сервер для отдачи файлов из корневой директории    # Автоматически определяет MIME-типы    file_server    # Включает GZIP-сжатие для ответов сервера    encode gzip    # Устанавливает заголовки кеширования для статических ресурсов:    header /assets/* Cache-Control: "public, max-age32536000, immutable"    header /*.css Cache-Control: "public, max-age=31536000, immutable"    header /*.js Cache-Control: "public, max-age=31536000, immutable"    # Попытка найти файл → если нет, то папку → если ничего нет, отдать index.html    try_files {path} {path}/ /index.html    # Заголовки безопасности    header {      # Требует HTTPS в течение 2 лет (63,072,000 сек)      Strict-Transport-Security "max-age=63072000"      # Запрещает браузеру определять MIME-тип (защита от MIME-атак)      X-Content-Type-Options "nosniff"      # Включает защиту от XSS-атак      X-XSS-Protection "1; mode=block"      # Запрещает встраивание сайта во frame/iframe (защита от clickjacking)      X-Frame-Options "DENY"    }}

Конфигурируем Dockerfile 

# Сборка сайта с использованием Node.jsFROM node:24-slim AS builderWORKDIR /app# Установка зависимостей (кешируется, если не менялся package.json)COPY package*.json ./RUN npm ci# Копирование исходников и сборкаCOPY docs ./docsRUN npm run docs:build # Результат: /app/docs/.vitepress/dist# Финальный образ Alpine + CaddyFROM alpine:3.23.5# Установка веб-сервера CaddyRUN apk add --no-cache caddy# Копируем собранный сайт из первого этапа в стандартную папку CaddyCOPY --from=builder /app/docs/.vitepress/dist /usr/share/caddy# Копируем конфиг CaddyCOPY Caddyfile /etc/caddy/Caddyfile# Открываем порты HTTP/HTTPSEXPOSE 80 443# Запуск CaddyCMD ["caddy", "run", "--config", "/etc/caddy/Caddyfile", "--adapter", "caddyfile"]

Конфигурируем docker-compose.yml 

version: "3.8"services:# Название сервиса (может быть любым)caddy:  build: # Dockerfile находится в текущей директории (.)    context: . # Используем файл с именем Dockerfile для сборки образа    dockerfile: Dockerfile  container_name: vitepress-site  # Политика перезапуска:  # - контейнер будет автоматически перезапускаться, если упадёт  # - не будет перезапускаться, только если остановлен вручную  restart: unless-stopped  ports:    # Открываем порт 80 (HTTP)    - "80:80"    # Открываем порт 443 (HTTPS)    - "443:443"  volumes:    # Том для хранения данных Caddy (сертификаты, база данных)    - caddy_data:/data    # Том для конфигурации Caddy    - caddy_config:/config  environment:    # Передаём переменную окружения DOMAIN из .env файла    - DOMAIN=${DOMAIN}    # Передаём переменную окружения EMAIL из .env файла    - EMAIL=${EMAIL}  networks:    - webvolumes:  caddy_data:  caddy_config:networks:  web: # Создаём сеть с драйвером bridge (стандартная сеть Docker)  driver: bridge

Файл с переменными .env

Перед запуском docker compose в корне проекта нужно создать .env файл с переменными, docker автоматически подтянет их при запуске.

DOMAIN=ваш доменEMAIL=ваша почта

Перенос кода на сервер

Легче всего доставить готовый проект можно с использованием системы контроля версий(GitHub, GitLab, Bitbucket)

На удаленной машине установите git(если отсутствует)

sudo apt update && sudo apt install git -y # Для Ubuntu/Debian

Проверить можно следующей командой

git --version # git version 2.50.1

Склонируйте проект и перейдите в корневую папку

git clone http://github.com/user/site.git && \  cd site

Запуск

  • Подключаемся к серверу по ssh

  • В корне проекта выполняем команду

docker compose up --build -d

Проверить работоспособность можно со своего компьютера через curl 

curl domain.com

Итог

Это решение представляет собой полноценную конфигурацию на базе Docker для развертывания React-приложений (собранных с помощью Vite). Оно включает многоэтапную сборку с использованием Node и caddy, автоматическую настройку TLS и правильные заголовки кэширования. Надеюсь данная статья оказалась полезной для вас.

ссылка на оригинал статьи https://habr.com/ru/articles/1065978/