Files
veilix.app/docs/09-infrastructure.md
T

13 KiB
Raw Blame History

09. Инфраструктура

1. Сервер (проверено 18–20.10.2026)

Что Значение
ОС Ubuntu 26.04.1 LTS
Ресурсы 4 vCPU, 7.7 ГБ RAM, 8 ГБ swap, 145 ГБ диска (занято 24 ГБ)
IP 169.58.76.183 — сайты (PTR fr-ub2gs3.veilix.cc, прямая запись совпадает); 173.212.216.183 — основной, через него по умолчанию идёт исходящий трафик (PTR vmi3593751.contaboserver.net)
Установлено Node 24.22, PostgreSQL 18.6, nginx 1.28 (модули geoip2 и brotli подключены), Redis 8, Postfix 3.10, OpenDKIM, certbot 4.0, Docker 29 (не используем), git
Нет pnpm, база GeoLite2 (.mmdb), сертификаты TLS, geoipupdate
DNS все 15 хостов проекта (вместе с umi.veilix.cc) указывают на 169.58.76.183; DNS-хостинг — Gcore

2. Папки

/home/vx_dev/veilix_dev/          — dev (пользователь vx_dev): рабочая копия git, .env, media/
/home/vx_prod/veilix/             — prod (пользователь vx_prod), закрыто для остальных
  releases/<дата-тег>/            — собранные релизы (храним 5 последних)
  current -> releases/…           — симлинк на работающий релиз
  shared/.env                     — секреты prod
  shared/media/                   — загруженные файлы prod
/home/umami/umami/                — Umami (пользователь umami)

vx — личный пользователь администратора, к проекту отношения не имеет. Под vx_prod нет редактора и ИИ-агентов, VSCode Remote под vx_prod не подключаем (D-004). Домашние папки всех пользователей — 750, владелец — сам пользователь. Пустые папки /home/vx/veilix.app, /home/vx/my.veilix.app, /home/vx/tg.veilix.app проекту не нужны.

3. Процессы

  1. Каждый сервис — под своим пользователем ОС, как systemd user-юнит. Root один раз включает loginctl enable-linger для vx_dev, vx_prod и umami, чтобы юниты работали без входа в систему.
  2. veilix-dev.service (vx_dev): pnpm dev на 127.0.0.1:3100 из /home/vx_dev/veilix_dev, перезапуск при сбое. Файл юнита — ops/systemd/veilix-dev.service в репозитории, подключён через systemctl --user link.
  3. veilix.service (vx_prod): pnpm start на порту 3000 из /home/vx_prod/veilix/current, NODE_ENV=production, перезапуск всегда.
  4. umami.service (umami): Umami на порту 3300.
  5. Фоновые задачи Payload выполняются внутри процессов приложения (02-architecture.md, раздел 7).
  6. Логи — journald, у каждого пользователя свои (journalctl --user -u veilix под vx_prod). Сессии Claude логи prod не видят: при разборе проблем prod их присылает пользователь.
  7. Проверка живости — /svc/health (с проверкой базы).

4. nginx

Хосты Куда Доступ
veilix.app, veilixvpn.com, my.veilix.app, my.veilixvpn.com, tg.veilix.app, tg.veilixvpn.com 127.0.0.1:3000 открыт
plc.veilix.cc 127.0.0.1:3000 только разрешённые IP
dev.veilix.app, dev.my.veilix.app, dev.veilixvpn.com, dev.my.veilixvpn.com 127.0.0.1:3100 только разрешённые IP или пароль; X-Robots-Tag: noindex
dev.tg.veilix.app, dev.tg.veilixvpn.com 127.0.0.1:3100 открыт для Telegram; приложение пускает только разрешённые Telegram-аккаунты
dev.plc.veilix.cc 127.0.0.1:3100 только разрешённые IP
umi.veilix.cc 127.0.0.1:3300 только разрешённые IP
  1. Слушает 169.58.76.183, порты 80 (редирект на HTTPS и проверка certbot) и 443. TLS 1.2 и 1.3, HTTP/2, HSTS.
  2. Сертификаты — certbot, проверка через HTTP.
  3. Сжатие — brotli и gzip.
  4. GeoIP: блок geoip2 в /etc/nginx/conf/ip.conf, база /var/lib/GeoIP/GeoLite2-Country.mmdb с auto_reload. Переменная $geoip_country_code уходит приложению заголовком X-Geo-Country; такой же заголовок от клиента nginx затирает. Старый модуль GeoIP v1 (modules-enabled/50-mod-http-geoip.conf) отключён: он занимает те же имена переменных, и nginx -t падает с ошибкой «the duplicate "geoip_country_code" variable».
  5. Заголовки к приложению — общий файл /etc/nginx/snippets/veilix_proxy.conf (плюс maps/upgrade.conf для WebSocket), его подключает каждый location с proxy_pass: Host, X-Real-IP и X-Forwarded-For (оба — $remote_addr: nginx стоит первым, цепочку от клиента не принимаем), X-Forwarded-Proto, X-Geo-Country, заголовки WebSocket (нужны горячей перезагрузке dev). proxy_set_header не наследуется в location со своими proxy_set_header, поэтому файл подключается в каждый такой location.
  6. В nginx.conf подключаются только sites-enabled/*.conf: файлы сайтов должны заканчиваться на .conf. Сайты: sites-available/02_vx_veilix-prod.conf, 02_vx_veilix-dev.conf, 02_vx_plc-prod.conf, 02_vx_plc-dev.conf. Сертификаты Let's Encrypt (certbot, проверка через nginx): veilix.app (6 prod-хостов брендов), dev.veilix.app (6 dev-хостов), plc.veilix.cc, dev.plc.veilix.cc. a. Доступ по IP — файл conf/ip_list_admin.conf со строками allow …;, в location после него deny all;. Подключается на хостах админки и dev, кроме dev.tg.*. b. dev.tg.* — отдельный server без ограничения по IP, с X-Robots-Tag: noindex. c. На порту 80 — location / { return 301 https://$host$request_uri; }. Именно внутри location, а не на уровне server: так certbot при продлении может вставить свой location для проверки домена.
  7. Лимиты запросов (limit_req) на эндпоинты входа и формы.
  8. Для tg.* (этап 3) разрешить показ во фрейме Telegram Web (frame-ancestors для доменов telegram.org).
  9. Пути трекера Umami на доменах брендов проксируются на 127.0.0.1:3300 (08-integrations.md, раздел 8).
  10. Конфигурацию готовит Claude текстом на согласование, применяет root.

5. PostgreSQL

  1. Базы veilix_dev, veilix_prod и umami. Владелец каждой — роль с именем пользователя ОС: vx_dev, vx_prod, umami.
  2. Вход по Unix-сокету с проверкой пользователя ОС: стандартное правило Ubuntu local all all peer в pg_hba.conf пускает пользователя ОС только под ролью с тем же именем. Паролей нет, pg_hba.conf и pg_ident.conf править не нужно.
  3. У каждой базы снято право подключения для всех (REVOKE CONNECT … FROM PUBLIC): войти может только владелец. vx_dev в veilix_prod не попадёт.
  4. Роль владеет своей базой: Payload нужны права на изменение схемы (push в dev, миграции в prod).
  5. Строка подключения: postgresql://vx_dev@/veilix_dev?host=/var/run/postgresql (для prod — vx_prod@/veilix_prod).

6. Почта (Postfix)

  1. smtp_bind_address = 169.58.76.183, myhostname = fr-ub2gs3.veilix.cc: письма уходят с IP, у которого обратная запись совпадает с прямой.
  2. OpenDKIM: ключи для veilix.app и veilixvpn.com (селектор, напр. mail).
  3. DNS для каждого из двух доменов: a. SPF: v=spf1 ip4:169.58.76.183 -all (плюс SMTP-провайдер, если используем); b. DKIM: TXT mail._domainkey.<домен> с открытым ключом; c. DMARC: _dmarc.<домен> — сначала v=DMARC1; p=none; rua=mailto:…, после проверки — p=quarantine.
  4. Проверить, что хостер не закрывает исходящий порт 25 и что 169.58.76.183 нет в чёрных списках.
  5. Приём почты поддержки (help@…) — где ящик, вопрос Q-16.

7. Бэкапы

  1. Prod-база: каждую ночь pg_dump -Fc veilix_prod, хранить 14 ежедневных и 8 еженедельных, копия на другой сервер (куда — Q-14). Раз в месяц — проверочное восстановление в отдельную базу.
  2. shared/media — синхронизация на тот же внешний сервер.
  3. Dev не бэкапим: код — в git, данные dev — тестовые.

8. Задачи для root по этапам

№ Этап Задача Статус на 21.10.2026
R-00 0 Переезд разработки: перенести /home/vx/veilix_dev в /home/vx_dev/veilix_dev (владелец vx_dev); SSH-ключ vx_dev для VSCode; Claude Code под vx_dev сделано
R-01 0 Репозиторий в Gitea; SSH-ключ vx_dev с правом push; для vx_prod — ключ только на чтение (deploy key) в работе: репозиторий ssh://git@gte.apr.sh:26789/andreypr207/veilix.app.git подключён как origin; ключ vx_dev — ~/.ssh/veilix_gitea_ed25519, ждёт добавления в Gitea как deploy key с правом записи; ключ vx_prod — на этапе 1h
R-02 1a PostgreSQL: роли vx_dev, vx_prod, umami и их базы (раздел 5) сделано и проверено: vx_dev входит в veilix_dev, в veilix_prod — отказ
R-03 1a pnpm: corepack enable pnpm сделано
R-04 1a Пользователи vx_dev, vx_prod, umami; loginctl enable-linger для них сделано
R-05 1a nginx и сертификаты для всех хостов (раздел 4) сделано: опечатка исправлена, X-Robots-Tag на всех dev-хостах
R-06 1a MaxMind: geoipupdate (ключ в /etc/GeoIP.conf, база в /var/lib/GeoIP, таймер geoipupdate.timer); отключить старый модуль GeoIP v1; блок geoip2 (раздел 4, пункт 4) сделано
R-07 1c Postfix, OpenDKIM, DNS-записи SPF, DKIM, DMARC — или данные SMTP-провайдера
R-08 1h PostgreSQL для prod — если не сделано вместе с R-02 сделано в R-02
R-09 1h nginx и сертификаты для prod-хостов сделано вместе с R-05
R-10 1h Umami: nginx и сертификат для umi.veilix.cc (DNS уже есть; база — в R-02)
R-11 1h Бэкапы prod-базы и media на внешний сервер (Q-14)
R-12 2 VPS с Chatwoot и Twenty, ключи API; 2 бота поддержки в BotFather
R-13 3 Боты в BotFather: 2 основных и тестовые; домен для Telegram Login; адреса MiniApp
R-14 4 Аккаунты платёжных систем (сначала тестовые), адреса вебхуков
R-15 1h По желанию (Q-18): sudo-правило, разрешающее vx_dev запускать от имени vx_prod только команду выкладки
R-16 1h По желанию: правило nftables — к 127.0.0.1:3000 подключаются только www-data (nginx) и vx_prod (10-security.md, раздел 7)
R-17 1a nginx dev: отдельный location /_next/webpack-hmr с proxy_read_timeout 1h в server-блоках dev-хостов и dev.plc.veilix.cc. Иначе WebSocket горячей перезагрузки закрывается каждые 30 секунд (proxy_read_timeout 30 в nginx.conf) в работе: есть в dev.plc и dev.tg.*; нужен ещё в блоке dev.veilix.app, dev.veilixvpn.com, dev.my.*