SEES P2P
Документация окружения
Сводка по сервисам, маршрутизации, данным и командам. Актуально для docker-compose проекта.
1) Стек и маршрутизация
Сервисы (docker-compose): caddy, coturn, signaling (Node.js), cams (Flask+Gunicorn), redis, netdata.
- /user — пользовательская SPA (Caddy → статика).
- /admin — админская SPA + Basic Auth.
- /admin/monitor/ — Netdata за Basic Auth (обязателен завершающий слэш).
- /api/auth/* →
cams:8000(регистрация/логин/профиль/выход). - /api/cams и /api/camera* →
cams:8000(CRUD камер). - остальное /api/* →
signaling:${SIGNAL_PORT}. - WebSocket →
wss://nvr.sees.su{SIGNAL_WS_PATH}. - GET /health (Caddy) → 200 OK, GET /healthz (cams) → 200 OK.
2) Дерево каталогов (хост)
/opt/sees-p2p/
├─ docker-compose.yml
├─ .env # переменные окружения
├─ caddy/
│ └─ Caddyfile # конфиг фронта (bind-mount)
├─ www/
│ ├─ user/ # SPA для пользователей (index.html и т.д.)
│ └─ admin/ # SPA для админки (index.html, status.html)
├─ signaling/
│ └─ index.js # Node-сервер сигналинга
├─ cams/
│ ├─ Dockerfile
│ └─ app.py # Flask API: auth + камеры + /healthz
└─ coturn/
└─ turnserver.conf # конфиг TURN/STUN
3) Томa Docker
- caddy_data
/data в контейнере — сертификаты/ACME - caddy_config
/config в контейнере Caddy - redis_data
/data в контейнере Redis (dump.rdb) - netdata_lib / netdata_cache
данные Netdata
4) Caddy — правила и ключевые блоки
Критично: специфичные маршруты должны идти выше общего @api.
# Глобально{ email {ADMIN_EMAIL} } {DOMAIN} { # --- Cams (до общего /api/*) --- @cams path /api/cams* handle @cams { reverse_proxy cams:8000 } @cam path /api/camera* handle @cam { reverse_proxy cams:8000 } # --- Auth --- @auth path /api/auth* handle @auth { reverse_proxy cams:8000 } # --- WebSocket сигналинг --- @ws path {SIGNAL_WS_PATH}* handle @ws { reverse_proxy signaling:{SIGNAL_PORT} } # --- Общее REST сигналинга --- @api path /api/* handle @api { reverse_proxy signaling:{SIGNAL_PORT} } # --- Админка (SPA) --- handle_path /admin* { basic_auth { admin <bcrypt_hash> } root * /srv/www/admin try_files {path} /index.html file_server } # --- Netdata под Basic Auth --- handle_path /admin/monitor* { basic_auth { admin <bcrypt_hash> } reverse_proxy netdata:19999 { header_up Host {upstream_hostport} header_up X-Forwarded-Host {host} header_up X-Forwarded-Proto {scheme} } } # --- Пользовательская SPA --- handle_path /user* { root * /srv/www/user try_files {path} /index.html file_server } # --- Health --- handle /health { respond "OK" 200 } # --- Фоллбек --- handle { respond "TURN/STUN ready at {DOMAIN}:3478/5349" 200 } }
Проверка/перезагрузка
# Проверка конфига локально (с подстановкой env)
docker run --rm \
-e ADMIN_EMAIL="$(grep -m1 '^ADMIN_EMAIL=' .env | cut -d= -f2)" \
-e DOMAIN="$(grep -m1 '^DOMAIN=' .env | cut -d= -f2)" \
-e SIGNAL_PORT="$(grep -m1 '^SIGNAL_PORT=' .env | cut -d= -f2)" \
-e SIGNAL_WS_PATH="$(grep -m1 '^SIGNAL_WS_PATH=' .env | cut -d= -f2)" \
-v $PWD/caddy/Caddyfile:/etc/caddy/Caddyfile:ro \
caddy:2 caddy validate --config /etc/caddy/Caddyfile
# Перечитать конфиг внутри контейнера
docker compose exec caddy caddy reload --config /etc/caddy/Caddyfile || docker compose restart caddy
5) cams / Flask API
Auth: POST /api/auth/register, POST /api/auth/login, POST /api/auth/logout, GET /api/auth/me
Камеры: GET /api/cams (только свои), POST /api/camera/add, GET/PUT/DELETE /api/camera/<id>
Служебное: GET /healthz
6) Сессии/куки
- На логине создаётся
sid(случайный токен), кладётся в Redis с TTL 7 дней. - Клиент получает
Set-Cookie: sid=...; Secure; HttpOnly; SameSite=Lax; Path=/. - Любой пользовательский запрос читает куку
sidи подтягивает профиль.
7) Модель данных Redis
user:{username} → JSON профиль {username,email,phone,password(hash),created_at}
users:index → SET всех логинов
sess:{sid} → строка c username (TTL 7 дней)
user:{username}:cams → SET id камер пользователя
camera:{id} → JSON {id,name,url,owner,created_at}
Файл базы: /data/dump.rdb внутри контейнера Redis (том redis_data).
8) Переменные .env
DOMAIN=nvr.sees.su
ADMIN_EMAIL=...
REDIS_PASSWORD=...
SIGNAL_PORT=...
SIGNAL_WS_PATH=/ws
# coturn
EXTERNAL_IP=...
TURN_SHARED_SECRET=...
RELAY_MIN_PORT=...
RELAY_MAX_PORT=...
REALM=${DOMAIN}
9) Порты и сети
- Caddy: 80, 443/tcp + 443/udp (HTTP/3)
- coturn: 3478 (UDP/TCP), 5349 (TLS) + диапазон relay (host network)
- signaling:
${SIGNAL_PORT}(наружу через Caddy) - cams: 8000 (внутренняя сеть, наружу через Caddy)
- netdata: 19999 (доступ через
/admin/monitor/)
10) Проверки (curl)
# user/admin SPA
docker compose exec caddy sh -lc 'curl -I http://localhost/user | head -n1'
curl -I https://nvr.sees.su/user | head -n1
curl -I -u admin:*** https://nvr.sees.su/admin/ | head -n1
# netdata (нужен завершающий слэш)
curl -I -u admin:*** https://nvr.sees.su/admin/monitor/ | head -n1
# cams JSON
curl -si https://nvr.sees.su/api/cams | head -n5
# Регистрация/логин/профиль + камеры
curl -si -X POST https://nvr.sees.su/api/auth/register \
-H 'Content-Type: application/json' \
-d '{"username":"demo","password":"demo123","email":"demo@example.com","phone":"+79990000000"}'
curl -c /tmp/sid.txt -b /tmp/sid.txt -si -X POST https://nvr.sees.su/api/auth/login \
-H 'Content-Type: application/json' \
-d '{"username":"demo","password":"demo123"}'
curl -c /tmp/sid.txt -b /tmp/sid.txt -s https://nvr.sees.su/api/auth/me
curl -c /tmp/sid.txt -b /tmp/sid.txt -sX POST https://nvr.sees.su/api/camera/add \
-H 'Content-Type: application/json' \
-d '{"name":"Demo Cam","url":"rtsp://example.com/stream"}'
curl -c /tmp/sid.txt -b /tmp/sid.txt -s https://nvr.sees.su/api/cams
11) Бэкап / восстановление Redis
# Снапшот и копия
docker compose exec redis redis-cli -a "$REDIS_PASSWORD" BGSAVE
sleep 2
docker compose cp redis:/data/dump.rdb ./backup/redis/dump-$(date +%F-%H%M%S).rdb
# Восстановление
docker compose stop redis
docker compose cp ./backup/redis/dump-YYYY-MM-DD-HHMMSS.rdb redis:/data/dump.rdb
docker compose start redis
12) Basic Auth (админ)
# Сгенерировать bcrypt-хеш
docker run --rm caddy:2 caddy hash-password --plaintext 'НОВЫЙ_ПАРОЛЬ'
# Вставить хеш в Caddyfile → перезапустить caddy
13) Обновление фронтов
- Файлы лежат в
./www/userи./www/admin. - Сервить отдаёт Caddy прямо из bind-монта — пересборка не нужна.
- Если браузер держит старое, сделайте Ctrl+F5 или откройте в инкогнито.
14) Типовые проблемы
- 502 на /api/auth/* или /api/camera* — проверьте порядок в Caddy:
@authдолжен быть выше@api. - 401/404 на /admin — проверьте Basic Auth и
try_files {path} /index.html. - 400 на /admin/monitor — используйте со слэшем:
/admin/monitor/и Basic Auth. - cams не стартует — смотрите трейс:
docker compose logs cams | tail -n 200. - user «белый» — как правило кэш. Сверьте исходник
curl -s /user | head, сделайте хард-рефреш.
15) Что можно улучшить
- Подтверждение email/телефона, rate-limit, сброс пароля.
- Выход со всех устройств, ротация
sid. - Роли (RBAC) и разграничение API.
- Секьюрные заголовки (CSP/HSTS) для статики.
- Скрипт бэкапов
scripts/backup.sh(по расписанию). - Интеграция /user с auth (UI: вход/выход, только свои камеры).
Написать комментарий