Files
ipam_control/docs/changes/034-caddy-publication/SUMMARY.md
T
ayurishchevandClaude Opus 5.5 8384c2c311 Задачи 034-035: публикация через Caddy, последний вход пользователя
034 Публикация стенда как https://rxipam.rxmsk.ru через общий Caddy хоста (Caddyfile вне репозитория):
    UI и /api/v1 доступны из интернета, /docs, /redoc, /openapi.json — только из частных сетей
    (RFC 1918/4193, loopback). Caddy проксирует на опубликованный порт приложения — общая Docker-сеть
    отклонена из-за коллизии имён app/db с Nextcloud. TRUSTED_PROXIES=172.16.0.0/12: реальный IP
    клиента из X-Forwarded-For. Интеграционный тест журнала больше не проверяет подделку XFF с хоста
    (хост за Caddy доверенный), логику покрывает unit-тест.
035 Дата и IP последнего входа в разделе «Пользователи»: users.last_login_at / last_login_ip
    (миграция 0014 с заполнением из журнала), запись при успешном входе, UserOut, колонка в UI.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 15:45:30 +03:00

54 lines
7.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Итог: публикация через Caddy — rxipam.rxmsk.ru (изменение 034)
План: `PLAN.md`. Стенд `ipam_control_006` опубликован как `https://rxipam.rxmsk.ru` через общий Caddy хоста (`/opt/lvraid/apps/caddy`).
Из интернета доступны UI и `/api/v1`; Swagger и OpenAPI — только из частных сетей.
## Отклонение от плана: без общей Docker-сети
План предлагал подключить приложение к сети Caddy `app_internal` (`docker-compose.caddy.yml`, алиас `ipam-app`).
При применении обнаружилась коллизия имён. Compose регистрирует имя сервиса как DNS-алиас в каждой сети контейнера,
а в `app_internal` уже есть `db` и `app` стека Nextcloud:
- приложение по имени `db` ушло в базу Nextcloud и не стартовало;
- Caddy адресует Nextcloud как `app:9000` — второй `app` в той же сети ломал бы Nextcloud.
Подключение откатили примерно через минуту: приложение всё это время перезапускалось, в логе Nextcloud ошибок нет, `rxcloud` отвечает.
**Итоговая схема:** Caddy проксирует на опубликованный порт приложения через шлюз своей сети — `reverse_proxy 172.19.0.1:8088`.
Сети не объединяются, `docker-compose.yml` не менялся, `docker-compose.caddy.yml` не создавался.
## Что сделано
| Где | Изменение |
|---|---|
| `/opt/lvraid/apps/caddy/Caddyfile` (вне репозитория) | Блок `rxipam.rxmsk.ru`: access-лог `rxipam.log` (JSON, INFO, ротация); `@docs_external` (`/docs`, `/docs/*`, `/redoc`, `/redoc/*`, `/openapi.json` и `not remote_ip private_ranges`) → 404; `reverse_proxy 172.19.0.1:8088`; HSTS, `-Server`. Бэкап: `Caddyfile.bak-2026-09-27`. Правка на месте, inode сохранён — контейнер видит новый файл; применено `caddy reload` |
| `.env` стенда (вне репозитория) | `TRUSTED_PROXIES=172.16.0.0/12`: запросы Caddy приходят в приложение с шлюза Docker-моста (`172.31.0.1`) через NAT хоста. Диапазон вместо /32 — подсеть проекта может смениться при пересоздании сети |
| `.env.example` | Закомментированный пример `TRUSTED_PROXIES` для публикации через Caddy на том же хосте |
| `README.md` | «Публикация и эксплуатация» — фактическая схема вместо примера; строка 034 в истории |
| `tests/test_journal.py` | Из интеграционного `test_client_ip_and_request_meta_recorded` убрана проверка «подделка XFF игнорируется»: с `TRUSTED_PROXIES=172.16.0.0/12` запросы тестов с хоста (через `172.31.0.1`) доверенные. Логику покрывает unit-тест `test_resolve_client_ip_trusts_forwarded_header_only_from_proxies` |
## Проверки
- `caddy validate` — конфигурация корректна; `caddy reload` без рестарта. Соседние сайты после reload: vault, artstore, aycv — 200, rxcloud — 302 (редирект на вход).
- Сертификат Let's Encrypt для `rxipam.rxmsk.ru` выпущен (DNS-01, Cloudflare).
- Из частной сети через Caddy: `/` 200, `/api/v1/auth/me` без токена 401, `/docs` и `/openapi.json` 200. Заголовки HSTS и CSP присутствуют.
- Matcher Swagger проверен на временном Caddy того же образа (тот же `path`, без условия по IP):
`/docs`, `//docs`, `/%64ocs`, `/docs/oauth2-redirect`, `/openapi.json`, `/%6fpenapi.json`, `/redoc`, `/%72edoc` → 404; `/` 200, API 401.
Проверка важна: приложение само отдаёт Swagger на URL-кодированные пути (`/%64ocs` → 200), и закрывает их именно Caddy.
- `private_ranges` раскрывается в `192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8, 127.0.0.1/8, fd00::/8, ::1`.
- Реальный IP клиента: запрос через Caddy с LAN-адреса хоста и подложным `X-Forwarded-For: 8.8.8.8` → в журнале `192.168.5.9`.
Подложный заголовок отброшен Caddy, реальный адрес получен из XFF.
- `pytest -q` — 15 passed (после правки теста выше).
- Пробные неудачные входы (`rv-probe-034`, `rv-probe-034b`) остались в журнале как события `session.failed`.
## Не проверено (требует пользователя)
- DNS: CNAME `rxipam` → `mkt.rxmsk.ru` (proxy Cloudflare выключен) ещё не создан — имя не резолвится.
- Доступ из интернета (мобильный интернет или внешний хост): `/` 200 и вход в UI; `/docs`, `/openapi.json` → 404;
в `rxipam.log` у этих запросов публичный `remote_ip`; в журнале приложения — публичный `client_ip` события входа.
## Рекомендации
- Доверие `172.16.0.0/12` означает, что процессы и контейнеры **на самом хосте** (приходят через шлюз Docker-моста) могут подставить свой IP в `X-Forwarded-For`. LAN- и интернет-клиенты этого не могут: у LAN-клиентов, идущих напрямую на `:8088`, в журнале реальные адреса. Исключить хост из доверенных можно только прямой сетью Caddy ↔ приложение без NAT — это требует переименовать сервисы `app`/`db` стенда (коллизия выше), отдельная задача.
- Split DNS на MikroTik (`rxipam.rxmsk.ru` → `192.168.5.9` в LAN): иначе LAN-клиенты через hairpin видны как `192.168.5.253`
и делят лимит «20 неудач на IP».
- План 031, часть 1 (`DOCS_ENABLED=false` по умолчанию) — вторая линия защиты Swagger, отдельной задачей.
- `172.19.0.1` — шлюз внешней сети `app_internal`. При её пересоздании с другой подсетью обновить `reverse_proxy` в Caddyfile.
## Откат
- Caddy: содержимое `Caddyfile.bak-2026-09-27` записать поверх `Caddyfile` на месте, затем `docker exec caddy caddy reload --config /etc/caddy/Caddyfile`.
- Стенд: убрать `TRUSTED_PROXIES` из `.env`, `docker compose -p ipam_control_006 up -d`.