From d593add0f3093b9ce0e4153b4b4a897966a8878d Mon Sep 17 00:00:00 2001 From: Max Ronzhin Date: Sat, 25 Jul 2026 22:58:38 +0300 Subject: [PATCH] deploy: bind backend/livekit-signaling/monitoring/llm ports to loopback Close host-published ports that don't need to be reachable from outside the docker network: nginx already proxies backend/livekit by service name, and admin UIs (prometheus/grafana) and llm servers should only be reachable via SSH tunnel. Only 80/443/7881 + the WebRTC UDP range stay open to the internet. --- .env.example | 6 ++++++ deploy/docker-compose.yml | 25 +++++++++++++++++++------ docs/deploy/monitoring.md | 10 ++++++++++ 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/.env.example b/.env.example index 2bfd50a..07d2235 100644 --- a/.env.example +++ b/.env.example @@ -137,6 +137,12 @@ LLM_TOKENIZER_FILE=qwen3.5-4b-instruct.tokenizer.json LLM_TOKENIZER_URL=https://huggingface.co/Qwen/Qwen3.5-4B/resolve/main/tokenizer.json # --- Мониторинг (профиль compose `monitoring`) --- +# Prometheus (9090) и Grafana (3001) публикуются ТОЛЬКО на 127.0.0.1 +# (deploy/docker-compose.yml) — с боевого сервера доступ через ssh-туннель, +# напр. `ssh -L 3001:127.0.0.1:3001 -L 9090:127.0.0.1:9090 @`, +# затем открыть http://localhost:3001 / :9090 у себя локально. То же для +# backend (8000, локальный curl-дебаг), livekit signaling (7880, снаружи +# работает только через nginx wss://) и llm/llm-gpu (8080/8081). GRAFANA_ADMIN_USER=admin GRAFANA_ADMIN_PASSWORD=change-me-grafana diff --git a/deploy/docker-compose.yml b/deploy/docker-compose.yml index fd872bd..af2a61d 100644 --- a/deploy/docker-compose.yml +++ b/deploy/docker-compose.yml @@ -81,8 +81,12 @@ services: volumes: - ../config:/app/config:ro - media:/app/media + # Публикуем ТОЛЬКО на loopback: backend нужен снаружи compose-сети + # только для локального curl-дебага на сервере — nginx проксирует + # запросы по имени `backend:8000` внутри docker-сети, публичный доступ + # идёт исключительно через nginx (80/443). ports: - - "8000:8000" + - "127.0.0.1:8000:8000" depends_on: postgres: condition: service_healthy @@ -375,8 +379,13 @@ services: # обязательно в кавычках: YAML запрещает ": " внутри неквотированного # plain-скаляра. LIVEKIT_KEYS: "${LIVEKIT_API_KEY:?LIVEKIT_API_KEY не задан в .env}: ${LIVEKIT_API_SECRET:?LIVEKIT_API_SECRET не задан в .env}" + # 7880 (signaling) — ТОЛЬКО loopback: nginx проксирует /livekit/ по имени + # `livekit:7880` внутри docker-сети (см. nginx.conf.template), браузеры + # снаружи ходят через nginx/443 (wss://), прямой доступ к 7880 им не + # нужен. 7881/tcp и UDP-диапазон ниже — реальные медиа-порты, остаются + # публичными. ports: - - "7880:7880" # HTTP/WebSocket signaling + - "127.0.0.1:7880:7880" # HTTP/WebSocket signaling - "7881:7881" # RTC TCP fallback # Узкий диапазон для dev на macOS: широкий (50000-60000) почти всегда # конфликтует с занятыми UDP-портами хоста и тормозит Docker Desktop. @@ -556,8 +565,9 @@ services: LLAMA_ARG_ENDPOINT_METRICS: 1 volumes: - llm-models:/models/qwen:ro + # Loopback-only: admin/debug доступ по ssh-туннелю, наружу не публикуется. ports: - - "8080:8080" + - "127.0.0.1:8080:8080" depends_on: llm-model-init: condition: service_completed_successfully @@ -596,8 +606,9 @@ services: LLAMA_ARG_ENDPOINT_METRICS: 1 volumes: - llm-models:/models/qwen:ro + # Loopback-only: admin/debug доступ по ssh-туннелю, наружу не публикуется. ports: - - "8081:8080" + - "127.0.0.1:8081:8080" # Алиас `llm` в сети compose (в дополнение к штатному `llm-gpu`) — # `llm` и `llm-gpu` взаимоисключающи по профилю (install.sh включает # ровно один), поэтому Prometheus (deploy/monitoring/prometheus.yml, @@ -639,8 +650,9 @@ services: - ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml:ro - ./monitoring/alerts.yml:/etc/prometheus/alerts.yml:ro - prometheus_data:/prometheus + # Loopback-only: админ-доступ по ssh-туннелю, наружу не публикуется. ports: - - "9090:9090" + - "127.0.0.1:9090:9090" healthcheck: test: ["CMD-SHELL", "wget -q -O- http://127.0.0.1:9090/-/healthy || exit 1"] interval: 10s @@ -697,8 +709,9 @@ services: - ./monitoring/grafana/provisioning:/etc/grafana/provisioning:ro - ./monitoring/grafana/dashboards:/var/lib/grafana/dashboards:ro - grafana_data:/var/lib/grafana + # Loopback-only: админ-доступ по ssh-туннелю, наружу не публикуется. ports: - - "3001:3000" + - "127.0.0.1:3001:3000" depends_on: prometheus: condition: service_healthy diff --git a/docs/deploy/monitoring.md b/docs/deploy/monitoring.md index e2b1778..4f35a18 100644 --- a/docs/deploy/monitoring.md +++ b/docs/deploy/monitoring.md @@ -27,6 +27,16 @@ docker compose -f deploy/docker-compose.yml --env-file .env --profile monitoring `GRAFANA_ADMIN_USER`/`GRAFANA_ADMIN_PASSWORD`; `install.sh` генерирует пароль при первой установке) +⚠️ На боевом сервере оба порта публикуются ТОЛЬКО на `127.0.0.1` +(`deploy/docker-compose.yml`) — открытые наружу admin-панели без +дополнительной аутентификации ранее уже приводили к компрометации сервисов +на этом проекте (см. `.forcc/deploy/SESSION2-FINDINGS.md`). С другой машины +используйте ssh-туннель: +```bash +ssh -L 9090:127.0.0.1:9090 -L 3001:127.0.0.1:3001 @ +``` +и открывайте `http://localhost:9090` / `http://localhost:3001` у себя. + Дашборд «Пайплайны пост-обработки» (папка VidConf в Grafana) появляется сразу — источник данных и дашборд провижинятся из файлов, без ручной настройки.