heather: enable jitsi meet stack (jitsi.iscg.dev)

Стек: web + prosody + jicofo + jvb + coturn. Перенесено с jul11 (2026-07-12):
- config (web/prosody/jicofo/jvb) → named volumes heather_jitsi-{web,prosody,jicofo,jvb,transcripts}
- prosody user mikl.dat сохранён (internal auth)
- образ PIN: stable-11031 (как на jul11, НЕ :latest)
- пароли (jicofo/jvb/jigasi/jibri/turn) НОВЫЕ, в pass iscg.dev/jitsi/
- env-файл /var/lib/jitsi-secrets/jitsi.env (root:docker 0640)
- coturn в host network (real client IPs), realm=turn.iscg.dev
- JVB 10000/udp публично (YC SG уже ANY ANY open)
- Caddy: WebSocket routes /xmpp-websocket, /colibri-ws (hop-by-hop upgrade)
- DISABLE_HTTPS=1 (Caddy терминирует TLS)
This commit is contained in:
mikl 2026-07-12 21:56:37 +03:00
parent cc6ef61d0a
commit ee8ce3f99f
2 changed files with 147 additions and 4 deletions

View file

@ -34,9 +34,12 @@
teable-db = {}; teable-db = {};
teable-redis = {}; teable-redis = {};
teable-assets = {}; teable-assets = {};
# jitsi-стек (когда добавим): # jitsi-стек
# jitsi-prosody-config = {}; jitsi-web = {};
# jitsi-jvb-config = {}; jitsi-prosody = {};
jitsi-jicofo = {};
jitsi-jvb = {};
jitsi-transcripts = {};
}; };
services = { services = {
# === Forgejo (git.iscg.dev) === # === Forgejo (git.iscg.dev) ===
@ -139,6 +142,132 @@
service.volumes = [ "teable-redis:/data" ]; service.volumes = [ "teable-redis:/data" ];
}; };
# === Jitsi Meet (jitsi.iscg.dev) ===
# Стек: web, prosody, jicofo, jvb, coturn. Перенесено с jul11 (2026-07-12):
# - config (web/prosody/jicofo/jvb) → named volumes (включая prosody user mikl)
# - образ PIN: stable-11031 (как на jul11, НЕ :latest)
# - пароли (jicofo/jvb/jigasi/jibri/turn) НОВЫЕ, в pass iscg.dev/jitsi/
# - env-файл /var/lib/jitsi-secrets/jitsi.env на heather (root:docker 0640)
# Coturn в host network (нужно для real client IPs). JVB 10000/udp публично.
# Caddy терминирует TLS, web внутренне HTTP (DISABLE_HTTPS=1).
# Документация: https://jitsi.github.io/handbook/docs/devops-guide/devops-guide-docker/
# WebSocket routes (/xmpp-websocket, /colibri-ws) — в caddy.nix.
jitsi-web = {
service.image = "jitsi/web:stable-11031";
service.container_name = "jitsi-web";
service.restart = "unless-stopped";
service.ports = [ "127.0.0.1:8000:80" ];
service.volumes = [
"jitsi-web:/config"
"jitsi-web:/var/spool/cron/crontabs"
"jitsi-transcripts:/usr/share/jitsi-meet/transcripts"
];
service.depends_on = [ "jitsi-jvb" ];
service.env_file = [ "/var/lib/jitsi-secrets/jitsi.env" ];
service.environment = {
PUBLIC_URL = "https://jitsi.iscg.dev";
DISABLE_HTTPS = "1";
ENABLE_HTTP_REDIRECT = "0";
ENABLE_HSTS = "0";
ENABLE_LETSENCRYPT = "0";
TZ = "Europe/Moscow";
HTTP_PORT = "8000";
JVB_ADVERTISE_IPS = "51.250.45.111";
APP_NAME = "mikl meet";
PROVIDER_NAME = "mikl meet";
SHOW_JITSI_WATERMARK = "false";
SHOW_POWERED_BY = "false";
DISABLE_JOIN_LEAVE_NOTIFICATIONS = "true";
DISABLE_VIDEO_BACKGROUND = "true";
ENABLE_AUTH = "1";
AUTH_TYPE = "internal";
ENABLE_GUESTS = "1";
ENABLE_XMPP_WEBSOCKET = "1";
ENABLE_COLIBRI_WEBSOCKET = "1";
RESOLUTION = "1080";
RESOLUTION_MIN = "360";
ENABLE_SIMULCAST = "true";
ENABLE_P2P = "true";
ENABLE_CODEC_VP8 = "1";
ENABLE_CODEC_VP9 = "1";
ENABLE_CODEC_H264 = "1";
ENABLE_CODEC_AV1 = "0";
VIDEOQUALITY_BITRATE_VP8_STANDARD = "1500";
VIDEOQUALITY_BITRATE_VP8_HIGH = "2500";
VIDEOQUALITY_BITRATE_VP8_LOW = "200";
};
};
jitsi-prosody = {
service.image = "jitsi/prosody:stable-11031";
service.container_name = "jitsi-prosody";
service.restart = "unless-stopped";
service.expose = [ "5222" "5269" "5347" "5280" ];
service.volumes = [
"jitsi-prosody:/config"
];
service.env_file = [ "/var/lib/jitsi-secrets/jitsi.env" ];
service.environment = {
TZ = "Europe/Moscow";
ENABLE_AUTH = "1";
AUTH_TYPE = "internal";
ENABLE_GUESTS = "1";
ENABLE_XMPP_WEBSOCKET = "1";
ENABLE_IPV6 = "0";
PUBLIC_URL = "https://jitsi.iscg.dev";
};
};
jitsi-jicofo = {
service.image = "jitsi/jicofo:stable-11031";
service.container_name = "jitsi-jicofo";
service.restart = "unless-stopped";
service.ports = [ "127.0.0.1:8888:8888" ];
service.volumes = [ "jitsi-jicofo:/config" ];
service.depends_on = [ "jitsi-prosody" ];
service.env_file = [ "/var/lib/jitsi-secrets/jitsi.env" ];
service.environment = {
TZ = "Europe/Moscow";
ENABLE_AUTH = "1";
AUTH_TYPE = "internal";
JICOFO_MAX_MEMORY = "1024m";
MAX_PARTICIPANTS = "10";
};
};
jitsi-jvb = {
service.image = "jitsi/jvb:stable-11031";
service.container_name = "jitsi-jvb";
service.restart = "unless-stopped";
service.ports = [
"10000:10000/udp" # публично — media traffic
"127.0.0.1:8080:8080" # colibri REST (localhost only)
];
service.volumes = [ "jitsi-jvb:/config" ];
service.depends_on = [ "jitsi-prosody" ];
service.env_file = [ "/var/lib/jitsi-secrets/jitsi.env" ];
service.environment = {
TZ = "Europe/Moscow";
PUBLIC_URL = "https://jitsi.iscg.dev";
JVB_ADVERTISE_IPS = "51.250.45.111";
JVB_PORT = "10000";
JVB_DISABLE_STUN = "0";
VIDEOBRIDGE_MAX_MEMORY = "2048m";
DOCKER_HOST_ADDRESS = "51.250.45.111";
};
};
jitsi-coturn = {
# Coturn в host network: нужно для real client IPs и корректной NAT traversal.
# Конфликтов с systemd coturn на heather НЕТ (мы его не поднимаем, в отличие от jul11).
service.image = "coturn/coturn:4.7";
service.container_name = "jitsi-coturn";
service.restart = "unless-stopped";
service.network_mode = "host";
service.env_file = [ "/var/lib/jitsi-secrets/jitsi.env" ];
service.command = "-v --log-file=stdout --realm=turn.iscg.dev --external-ip=51.250.45.111 --use-auth-secret --static-auth-secret=$${TURN_STATIC_AUTH_SECRET} --min-port=49160 --max-port=49200 --no-tls --no-dtls --fingerprint --no-cli --simple-log";
};
# === Silverbullet (note.iscg.dev) — ИСКЛЮЧЕНИЕ: bind mount === # === Silverbullet (note.iscg.dev) — ИСКЛЮЧЕНИЕ: bind mount ===
# Space = /srv/syncthing/herbarium (sync'ается syncthing на устройства). # Space = /srv/syncthing/herbarium (sync'ается syncthing на устройства).
# Единственный сервис без named volume — по твоему решению, чтобы notes # Единственный сервис без named volume — по твоему решению, чтобы notes

View file

@ -73,8 +73,22 @@ in {
encode zstd gzip encode zstd gzip
''; '';
# Jitsi Meet # Jitsi Meet (web + WebSocket routes)
"jitsi.iscg.dev".extraConfig = '' "jitsi.iscg.dev".extraConfig = ''
# WebSocket routes — hop-by-hop, требуют явного upgrade
@xmpp path /xmpp-websocket*
reverse_proxy @xmpp 127.0.0.1:8000 {
header_up Host {host}
header_up Upgrade {http.upgrade}
header_up Connection {http.connection}
}
@colibri path /colibri-ws*
reverse_proxy @colibri 127.0.0.1:8000 {
header_up Host {host}
header_up Upgrade {http.upgrade}
header_up Connection {http.connection}
}
# Остальное → web контейнер
reverse_proxy 127.0.0.1:8000 reverse_proxy 127.0.0.1:8000
encode zstd gzip encode zstd gzip
''; '';