Files
split-trainer/docs/DEPLOY.md
T
darkoandClaude Sonnet 5.5 e897a6c5eb Развёртывание на Debian 12/13: Docker, nginx, работа за обратным прокси
- приложение перенесено в public/, инструкции в docs/
- Dockerfile (nginx без root-прав), docker-compose.yml с ограничениями
- deploy/split-trainer.conf: CSP и заголовки безопасности, no-cache по ETag,
  /healthz, реальный IP из X-Forwarded-For только от частных сетей,
  редиректы без внутреннего хоста
- deploy/install-debian.sh: установка и обновление без Docker
- docs/DEPLOY.md: требования, установка, примеры прокси (nginx, Caddy, Traefik), подпуть

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 12:35:47 +03:00

11 KiB
Raw Blame History

Развёртывание на своём сервере (Debian 12 / 13)

Сплит-тренер состоит из статических файлов (HTML, CSS, JS) и ничего не хранит на сервере. Нет бэкенда, базы данных, куки и обращений к внешним сайтам. Сервер только отдаёт файлы, поэтому требования минимальные.

1. Минимальные требования

Сервер

Минимум Комментарий
ОС Debian 12 (bookworm) или Debian 13 (trixie), amd64 или arm64
CPU / RAM 1 vCPU, 128 МБ свободной памяти nginx в простое занимает 5–10 МБ; для контейнера задан лимит 64 МБ
Диск порядка 500 МБ с Docker Engine (сам образ занимает несколько десятков МБ) или ~10 МБ с nginx из пакетов сам сайт меньше 1 МБ
Сеть один TCP-порт; по умолчанию 127.0.0.1:8080 наружу выставляет обратный прокси
Исходящий доступ только на время установки (apt или docker pull) во время работы сайту интернет не нужен
ПО (вариант A) Docker Engine 24+ с плагином Compose v2 рекомендуется официальный репозиторий: docs.docker.com/engine/install/debian
ПО (вариант B) nginx 1.22+ из пакетов Debian (в Debian 12 это 1.22, в 13 это 1.26) ставится скриптом
Права root или sudo на время установки сайт работает без root-прав

Нужно выбрать один вариант: A или B.

Домен и HTTPS

  • Для работы сайта HTTPS не обязателен: приложение не использует API, требующие защищённого контекста.
  • Но на публичном адресе HTTPS нужен: его даёт ваш обратный прокси (раздел 4).

Браузеры пользователей

Современные: Chrome и Edge 111+, Firefox 113+, Safari 16.2+ (примерно 2023 год и новее). Для работы нужен включённый JavaScript и localStorage.

2. Что важно знать про данные

  • Прогресс и статистика хранятся в браузере пользователя (localStorage), на сервер ничего не отправляется. Резервировать на сервере нечего.
  • Данные привязаны к адресу сайта (схема + домен + порт). Если сменить домен, пользователи начнут «с нуля»; смена пути (/trainer/) прогресс не затрагивает.
  • Файл раскладки Vial (.vil) читается локально в браузере и никуда не загружается.

3. Установка

Склонируйте репозиторий на сервер:

git clone https://gittea.khad1997pav.ru/khadzhibekovpa/split-trainer.git
cd split-trainer

Вариант A: Docker (рекомендуется)

docker compose up -d --build
curl -i http://127.0.0.1:8080/healthz      # должно ответить 200 и "ok"
  • Порт по умолчанию открыт только на localhost. Изменить: файл .env рядом с docker-compose.yml, например PORT=9000 и/или BIND=0.0.0.0 (откроет наружу: тогда закройте порт файрволом для всех, кроме прокси).
  • Контейнер работает без root-прав, с файловой системой «только чтение», без лишних возможностей ядра и с лимитом памяти.
  • Если прокси тоже в Docker, уберите блок ports: и подключите сервис к общей сети прокси: он слушает 8080 внутри контейнера.

Вариант B: nginx из пакетов Debian

sudo ./deploy/install-debian.sh
curl -i http://127.0.0.1:8080/healthz

Скрипт ставит nginx, копирует файлы в /var/www/split-trainer и подключает отдельный конфиг split-trainer.conf. Чужие сайты и настройки он не трогает.

Параметры (переменные окружения):

Переменная По умолчанию Назначение
LISTEN 127.0.0.1:8080 адрес и порт (или только порт)
DOMAIN _ server_name, можно несколько через пробел
WEBROOT /var/www/split-trainer куда копировать файлы
FORCE 0 1: разрешить запуск не на Debian 12/13

Без прокси, прямо на порту 80:

sudo LISTEN=80 DOMAIN=trainer.example.com ./deploy/install-debian.sh

Если порт 80 уже занят «сайтом по умолчанию» nginx и вы не задали DOMAIN, будет открываться страница «Welcome to nginx»: укажите домен или отключите сайт по умолчанию (sudo rm /etc/nginx/sites-enabled/default && sudo systemctl reload nginx).

Обновление

git pull
docker compose up -d --build        # вариант A
# или
sudo ./deploy/install-debian.sh     # вариант B

Браузеры подхватят новую версию сами: сайт отдаётся с Cache-Control: no-cache, то есть при каждом открытии версия сверяется по ETag.

4. За обратным прокси

От прокси ничего особенного не требуется: сайт статический, без WebSocket, без нестандартных заголовков, все ссылки внутри относительные. Достаточно передать запрос на 127.0.0.1:8080.

nginx

server {
    listen 443 ssl;
    server_name trainer.example.com;

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

    # HTTPS завершается здесь, поэтому HSTS должен ставить именно прокси
    add_header Strict-Transport-Security "max-age=31536000" always;

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

Caddy

trainer.example.com {
    reverse_proxy 127.0.0.1:8080
}

HTTPS-сертификат Caddy получит сам.

Traefik (Docker, метки в docker-compose.override.yml)

services:
  split-trainer:
    ports: !reset []
    networks: [traefik]
    labels:
      - traefik.enable=true
      - traefik.http.routers.trainer.rule=Host(`trainer.example.com`)
      - traefik.http.routers.trainer.tls.certresolver=letsencrypt
      - traefik.http.services.trainer.loadbalancer.server.port=8080
networks:
  traefik:
    external: true

Имена сети и резолвера замените на свои. Тег !reset требует Docker Compose 2.24 или новее.

Под подпутём (https://example.com/trainer/)

Приложение можно отдавать из подкаталога: все пути в нём относительные, свой конфиг менять не нужно. Прокси должен убрать префикс (завершающий / в proxy_pass обязателен):

location = /trainer { return 301 /trainer/; }
location /trainer/   { proxy_pass http://127.0.0.1:8080/; proxy_set_header Host $host; }

Для Caddy:

example.com {
    redir /trainer /trainer/
    handle_path /trainer/* { reverse_proxy 127.0.0.1:8080 }
}

Настоящий IP клиента в логах

Конфиг доверяет заголовку X-Forwarded-For только от прокси из частных сетей и localhost (127.0.0.0/8, 10/8, 172.16/12, 192.168/16). Если ваш прокси стоит на другом сервере с публичным адресом, добавьте его в set_real_ip_from в deploy/split-trainer.conf и пересоберите или переустановите.

5. Что отдаёт сервер

  • GET /healthz отвечает 200 ok (для мониторинга и healthcheck).
  • Заголовки безопасности: строгий Content-Security-Policy (только свои скрипты и стили, никаких внешних адресов), X-Content-Type-Options, Referrer-Policy: no-referrer, X-Frame-Options, Permissions-Policy.
  • Файлы сжимаются gzip, скрытые файлы (.git, .env) не отдаются, версия nginx в ответах скрыта.

6. Если что-то не работает

Симптом Причина и решение
502 / 504 от прокси Сайт не запущен или слушает другой порт: docker compose ps, curl http://127.0.0.1:8080/healthz
Белая страница под /trainer/ Нет завершающего / в proxy_pass или нет редиректа /trainer на /trainer/ (см. выше)
После обновления видна старая версия Обновите страницу с Ctrl+F5; если стоит CDN или кеш на прокси, исключите сайт из кеширования
Прогресс пропал после смены адреса localStorage привязан к адресу сайта (схема + домен + порт); вернуть старый адрес
nginx -t ругается (вариант B) Покажите вывод sudo nginx -t; чаще всего порт занят другим сайтом
Нужно изменить текст упражнений Правьте public/data.js и обновите сайт командой из раздела «Обновление»