- Remove Syncthing mention from authelia comment in docker-compose - Fix backup.sh.j2 comment: hourly → every 6 hours - Update CLAUDE.md: add docs update rule, fix backup schedule note - Update STATUS.md: dash.csrx.ru fixed, PTR pending, backup schedule, mail hostnames - Update BACKLOG.md: mark DNS/PTR/backup-schedule done, add SnappyMail domain task - Update DECISIONS.md: fix backup section (no --storage-class COLD, correct schedule) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
116 lines
7.7 KiB
Markdown
116 lines
7.7 KiB
Markdown
# Журнал архитектурных решений
|
||
|
||
> Фиксируй здесь: что решили, почему, какие альтернативы отвергли.
|
||
> Формат: дата | решение | причина | альтернативы
|
||
|
||
---
|
||
|
||
## Инфраструктура
|
||
|
||
### Два сервера (main + tools)
|
||
**Дата:** начало проекта
|
||
**Решение:** Разделить сервисы на два VPS: main для ядра, tools для вспомогательных.
|
||
**Причина:** main (1 vCPU / 2 GB RAM) перегружен — Plane + Forgejo + мониторинг занимают почти всю память. tools позволяет разгрузить.
|
||
**Итог:** Outline, n8n, mail работают на tools. Traefik на main проксирует к tools через IP:PORT.
|
||
|
||
### Traefik вместо nginx/caddy
|
||
**Дата:** начало проекта
|
||
**Решение:** Traefik v3 как единственный точка входа.
|
||
**Причина:** Автоматический TLS через Let's Encrypt, file provider для маршрутов, удобная интеграция с Docker.
|
||
**Альтернативы:** nginx + certbot (ручной renewal), Caddy (проще но меньше гибкости).
|
||
|
||
### Cloudflare proxy + UFW whitelist
|
||
**Дата:** начало проекта
|
||
**Решение:** Порты 80/443 открыты только для IP Cloudflare.
|
||
**Причина:** Скрывает реальный IP сервера, защита от DDoS на уровне Cloudflare, бесплатный WAF.
|
||
**Важно:** Некоторые сервисы (wiki, vault, webmail) должны быть DNS-only (оранжевое облако off) — когда Cloudflare не поддерживает нужные порты или протоколы.
|
||
|
||
### Wildcard TLS через DNS-01
|
||
**Дата:** начало проекта
|
||
**Решение:** Один сертификат `*.csrx.ru` вместо отдельных на каждый поддомен.
|
||
**Причина:** Новый сервис — ноль ожидания сертификата. Cloudflare DNS-01 работает без HTTP-challenge.
|
||
**Конфиг:** `roles/services/templates/traefik/traefik.yml.j2` — certresolver `letsencrypt`.
|
||
|
||
---
|
||
|
||
## Безопасность
|
||
|
||
### Authelia для 2FA
|
||
**Дата:** начало проекта
|
||
**Решение:** Authelia + TOTP защищает admin-панели (Traefik dashboard, Plane god-mode).
|
||
**Причина:** Одна точка SSO, не нужно настраивать auth в каждом сервисе.
|
||
**Альтернативы:** Keycloak (тяжелее, требует больше ресурсов), Authentik (сложнее).
|
||
|
||
### CrowdSec community edition
|
||
**Дата:** начало проекта
|
||
**Решение:** CrowdSec без платного API ключа.
|
||
**Причина:** Бесплатная tier достаточна. Анализирует логи Traefik + auth.log.
|
||
**Ограничение:** Нет расширенных threat feeds — только community reputation.
|
||
|
||
### Syncthing — удалён
|
||
**Дата:** 2026-03
|
||
**Решение:** Удалить Syncthing полностью из инфраструктуры.
|
||
**Причина:** Не используется. Открытые порты (22000, 21027) без сервиса — лишняя attack surface.
|
||
**Что убрали:** UFW rules, docker image, domain_sync, переменную vault, Authelia правило.
|
||
|
||
---
|
||
|
||
## Сервисы
|
||
|
||
### Outline wiki — email magic link
|
||
**Дата:** 2026-02
|
||
**Решение:** Авторизация через email magic link (SMTP → docker-mailserver).
|
||
**Причина:** Outline не поддерживает простую login/password аутентификацию без SSO.
|
||
**Проблемы решённые:**
|
||
- `guestSignin=true` в БД обязателен для email auth
|
||
- `jwtSecret` в БД хранится в зашифрованном виде — при смене `SECRET_KEY` нужно пересоздать
|
||
|
||
### docker-mailserver вместо внешнего SMTP
|
||
**Дата:** 2026-03
|
||
**Решение:** Self-hosted Postfix + Dovecot на tools-сервере.
|
||
**Причина:** Полный контроль, аккаунты @csrx.ru для приёма и отправки, нет зависимости от внешних SMTP.
|
||
**Конфиг:** SSL_TYPE=letsencrypt через certbot с Cloudflare DNS-01. DKIM через opendkim.
|
||
**Альтернативы:** Mailgun/SendGrid (только отправка, без приёма), Maddy (менее зрелый).
|
||
|
||
### Бэкап в Timeweb S3
|
||
**Дата:** 2026-03
|
||
**Решение:** Backup каждые 6 часов (00/06/12/18) → S3 `visual-backup/data/`, 7 дней хранения.
|
||
**Причина:** 6 часов = баланс между частотой и нагрузкой на сервер. Тип хранилища COLD задаётся на уровне бакета в Timeweb, не через параметр `--storage-class` (Timeweb S3 не поддерживает этот параметр).
|
||
**Формат архива:** единый `main_data_YYYY-MM-DD_HH-MM.tar.gz` с `data/databases/` и `data/volumes/`.
|
||
|
||
### SnappyMail вместо Roundcube
|
||
**Дата:** 2026-03
|
||
**Решение:** djmaze/snappymail как веб-клиент почты на `mail.csrx.ru`.
|
||
**Причина:** Лёгкий, современный UI, простой Docker образ.
|
||
**Альтернативы:** Roundcube (тяжелее, требует MySQL), Rainloop (заброшен).
|
||
|
||
### mx.csrx.ru вместо mail.csrx.ru для MX-сервера
|
||
**Дата:** 2026-03
|
||
**Решение:** docker-mailserver hostname = `mx.csrx.ru`, веб-клиент = `mail.csrx.ru`.
|
||
**Причина:** Стандарт индустрии — MX-хост называется `mx`, пользовательский интерфейс — `mail`.
|
||
Раньше оба указывали на разные вещи под одним именем, что запутывало.
|
||
**DNS:** `mx.csrx.ru` → 85.193.83.9 (DNS-only, прямые порты SMTP/IMAP).
|
||
`mail.csrx.ru` → 87.249.49.32 (Cloudflare proxied, HTTPS вебмейл через Traefik).
|
||
**SPF:** `v=spf1 mx -all` — `-all` жёстче чем `~all`, явно запрещает чужие отправители.
|
||
**DMARC:** `p=quarantine` — подозрительные письма в спам (было `p=none` — только мониторинг).
|
||
|
||
---
|
||
|
||
## CI/CD
|
||
|
||
### Forgejo Actions
|
||
**Дата:** начало проекта
|
||
**Решение:** Forgejo Actions + act_runner для CI/CD деплоя.
|
||
**Причина:** Self-hosted, интегрировано с Forgejo, совместимо с GitHub Actions синтаксисом.
|
||
**Принцип:** Push в master → `ansible-playbook deploy.yml` + `tools.yml`. Никаких ручных правок на сервере.
|
||
|
||
---
|
||
|
||
## Известные компромиссы
|
||
|
||
| Компромисс | Почему так | Что улучшить |
|
||
|-----------|-----------|-------------|
|
||
| act_runner монтирует `/var/run/docker.sock` | Нужен для запуска job-контейнеров | Rootless Docker или ограниченный API |
|
||
| Plane использует `:stable` тег | Plane не публикует версионные теги | Мониторить GitHub releases |
|
||
| Мониторинг на main (не на отдельном сервере) | mon-сервер пока не задеплоен | Создать `playbooks/mon.yml` |
|
||
| Нет бэкапа tools-сервера | Бэкап роль подключена только к main | Добавить в `tools.yml` |
|