Архитектура

Один сервер вместо десяти

Сервер держит несколько проектов и не смешивает их между собой. Ниже — то, что можно перепроверить: хост, изоляция, путь изменения, проверки, бэкапы.

01Хост

Железо и базовый слой

Расположение
Амстердам, Нидерланды, один VPS (провайдер VDSina)
ОС
Ubuntu 24.04 LTS
Ресурсы
2 vCPU · 4 ГБ RAM · 79 ГБ SSD
Веб-сервер
Caddy 2.11, TLS выпускается автоматически (Let's Encrypt)
Запуск сервисов
systemd, отдельный юнит на проект

02Изоляция

Проекты не знают друг о друге

Изоляция — не настройка «на будущее», а условие запуска: проект без неё просто не принимается.

Слои узла: три проекта в границах изоляции над слоем управления, веб-сервером и системой Сверху три проекта, каждый в своей изоляции; ниже слой управления доставкой и бэкапами, веб-сервер и операционная система. границы изоляции · на каждый проект свой пользователь, свой юнит, свой репозиторий TaskVista бот в Telegram base-pilot шаблон проекта админ-узел слой управления слой управления приёмка · доставка · бэкапы · мониторинг Caddy 2.11 домены · TLS · заголовки Ubuntu 24.04 LTS · 2 vCPU · 4 ГБ · 79 ГБ
Сверху вниз: проекты в границах изоляции, слой управления, веб-сервер, система

Статику сайтов пишет только суперпользователь, сервисы проектов не ходят по чужим каталогам. Поэтому проект без рамки на схеме просто не принимается — это условие запуска, а не настройка «на будущее».

03Путь изменения

Push → гейт → доставка

Один маршрут для всех проектов. Ручных копирований на сервер нет: всё, что попадает в прод, прошло проверку.

Путь изменения: push, гейт, слияние по правилу, доставка, перезапуск Пять шагов слева направо. Если гейт показал красный результат, доставки не происходит и изменение возвращается автору. 01 02 03 04 05 git push коммит гейт тесты и правила слияние по правилу доставка файлы и юниты перезапуск systemd, секунды красный результат — доставки нет, правка возвращается автору
Схема доставки: гейт — обязательный шаг, обойти его нельзя

Красный гейт — это норма. Он ловит ошибку до сервера; цена такой остановки — минуты, цена ошибки в проде — часы.

04Проверки

Что проверяется само

Четыре вида проверок идут без участия человека. Их задача — заметить проблему раньше, чем она станет заметной снаружи.

01

Самопроверка хоста

Состояние самого сервера и его юнитов: что запущено, что упало, что перезапускалось.

02

Аудит дрейфа

Сверка фактической конфигурации с ожидаемой. Всё, что изменилось в обход правил, видно отдельным отчётом.

03

Свежесть бэкапов

Снимки делаются по расписанию — и проверяется, что последний не устарел.

04

Сторож

Health-проверки проектов и уведомления в Telegram: сообщение приходит, когда что-то сломалось, а не после жалобы.

05Бэкапы

Снимок, который проверяли

Каждый день по каждому проекту снимаются данные. К снимку прикладывается контрольная сумма sha256, а его пригодность проверяется восстановлением: снимок, из которого ни разу не разворачивались, — это надежда, а не бэкап.

Проверка свежести бэкапов идёт в том же автоматическом режиме, что и остальные проверки, — её результат виден, даже если о ней никто не вспомнил.

06Несколько сайтов

Один адрес на сайт, общие порты

Caddy слушает 80 и 443 и различает сайты по домену. У каждого сайта свой блок конфигурации и свой сертификат, который выпускается автоматически. Отдельный IP-адрес для нового сайта не нужен.

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

07Заголовки

Строже, чем принято по умолчанию

Сайт отдаётся с заголовками безопасности: скрипты запрещены полностью, страница не может быть встроена в чужой фрейм.

Content-Security-Policy
default-src 'self'; script-src 'none'; style-src 'self'; img-src 'self' data:; frame-ancestors 'none'; base-uri 'none'
Strict-Transport-Security
max-age=31536000; includeSubDomains
X-Content-Type-Options
nosniff
X-Frame-Options
DENY
Referrer-Policy
strict-origin-when-cross-origin

Поэтому у сайта нет ни одного скрипта и ни одного инлайнового стиля — только внешний файл стилей с того же домена. И ни одного запроса на чужой сервер.