Files
MatchLiveTv/docs/infrastructure/SERVER_DEPLOYMENT.md
Emiliano Frascaro 498f6069d0 Documenta l'architettura completa del sistema.
Aggiunge docs/ARCHITECTURE.md con topologia rete, edge nginx, flussi HLS/replay e monitoraggio ops; allinea i documenti esistenti.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-14 21:26:35 +02:00

7.2 KiB

Deploy server — Match Live TV Backend

Server: eminux@192.168.1.146 (Debian 13)
Path deploy: ~/matchlivetv (dopo bootstrap opzionale: /opt/matchlivetv)
Ultimo aggiornamento: 2026-06-14

Architettura completa: ARCHITECTURE.md


Architettura rete

Internet
    │
    ├──► Router WAN :443 ──► Nginx Proxy Manager (LAN) ──► http://192.168.1.146:3000 (edge nginx)
    │                                                          ├── /hls/  → MediaMTX :8888
    │                                                          ├── /media/ → Garage :3900
    │                                                          └── /      → Rails (API + web)
    │
    └──► Router WAN :1935 ──► MediaMTX RTMP (telefoni, ingest video diretto)

Il flusso video live e replay non passa da Puma: HLS e MP4 sono serviti da edge verso MediaMTX e Garage; Rails fa auth e redirect.


Scelte tecniche

Scelta Motivazione
Docker + Compose Riproducibilità, stesso stack in dev e prod
docker-compose.prod.yml separato Dev monta volumi sorgente; prod usa immagine buildata
Rails esposto su :3000 solo LAN NPM termina HTTPS; non esporre 3000 su WAN
MediaMTX :1935 su WAN RTMP non supporta facilmente reverse proxy TLS su NPM
API MediaMTX :9997 non pubblicata Solo rete Docker interna
Postgres/Redis senza porte host Sicurezza
Kamal non usato in questa fase Compose sufficiente per singolo nodo; Kamal in roadmap Gitea

Porte router (port forwarding verso 192.168.1.146)

Aprire su Internet

Porta Protocollo Servizio
1935 TCP RTMP ingest (obbligatorio per streaming da 4G)

Opzionale

Porta Protocollo Servizio
8888 TCP HLS playback registrazioni

Non aprire

Porta Motivo
443 Gestito da NPM (altro host LAN), non da questo server
3000 API raggiungibile via NPM sulla LAN
5432, 6379 Database interni
9997 API MediaMTX
8554 RTSP non usato MVP

Nginx Proxy Manager (HTTPS)

  1. Proxy Host → Forward Hostname: http://192.168.1.146:3000 (dominio principale www.matchlivetv.it, redirect apex matchlivetv.itwww)

    La porta 3000 è servita dal container edge (nginx locale), non da Rails direttamente. Durante i rilasci Rails viene mostrata una pagina di cortesia invece del 502 bianco di NPM.

  2. Websockets: ON (obbligatorio per /cable)

  3. HLS: nessuna custom location necessaria — edge instrada /hls/ verso MediaMTX internamente. Un solo Proxy Host verso :3000 basta.

  4. SSL Let's Encrypt su NPM

  5. Aggiorna infra/.env sul server:

    • APP_PUBLIC_URL=https://www.matchlivetv.it
    • HLS_PUBLIC_URL=https://www.matchlivetv.it/hls
    • CORS_ORIGINS=https://www.matchlivetv.it,https://matchlivetv.it
    • ALLOWED_HOSTS=www.matchlivetv.it,matchlivetv.it,192.168.1.146
    • MEDIAMTX_RTMP_URL=rtmp://www.matchlivetv.it:1935
    • YOUTUBE_REDIRECT_URI=https://www.matchlivetv.it/api/v1/youtube/callback (solo tier premium)

Installazione iniziale (una tantum)

Prerequisito: sudo senza password

L'utente eminux deve poter eseguire sudo senza password da SSH, oppure eseguire il bootstrap da console Proxmox:

echo 'eminux ALL=(ALL) NOPASSWD: ALL' | sudo tee /etc/sudoers.d/eminux-nopasswd
sudo chmod 440 /etc/sudoers.d/eminux-nopasswd

1. Bootstrap server (Docker, UFW, /opt)

Sul server:

sudo bash ~/matchlivetv/scripts/deploy/server_bootstrap.sh

Installa: Docker Engine, Compose plugin, UFW (22, 1935, 8888, 3000 da LAN), crea /opt/matchlivetv.

Riavviare la sessione SSH dopo bootstrap per il gruppo docker.

2. Spostare deploy in /opt (opzionale)

sudo mv ~/matchlivetv /opt/matchlivetv
sudo chown -R eminux:eminux /opt/matchlivetv

3. Configurare secret

cd /opt/matchlivetv/infra   # o ~/matchlivetv/infra
nano .env   # verificare POSTGRES_PASSWORD, SECRET_KEY_BASE, MEDIAMTX_RTMP_URL, ecc.

4. Avviare stack

bash /opt/matchlivetv/scripts/deploy/post_bootstrap_deploy.sh

Oppure manualmente:

cd /opt/matchlivetv/infra
docker compose -f docker-compose.prod.yml --env-file .env up -d --build

5. Seed dati demo (una tantum)

docker compose -f docker-compose.prod.yml exec rails bundle exec rails db:seed

Credenziali demo: coach@matchlivetv.test / password123

6. Verifica

curl http://192.168.1.146:3000/up
curl -X POST http://192.168.1.146:3000/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"coach@matchlivetv.test","password":"password123"}'

Aggiornamento codice (pre-Gitea)

Dalla macchina di sviluppo:

bash scripts/deploy/release_production.sh

Oppure sync manuale: scripts/deploy/sync_to_server.sh, poi sul server bash scripts/deploy/release_production.sh --local.


Operazioni quotidiane

cd /opt/matchlivetv/infra

# Stato
docker compose -f docker-compose.prod.yml ps

# Log
docker compose -f docker-compose.prod.yml logs -f rails
docker compose -f docker-compose.prod.yml logs -f mediamtx

# Restart
docker compose -f docker-compose.prod.yml restart rails sidekiq

# Stop
docker compose -f docker-compose.prod.yml down

Backup volumi

  • postgres_data — database
  • recordings — HLS MediaMTX
docker run --rm -v infra_postgres_data:/data -v $(pwd):/backup alpine \
  tar czf /backup/postgres_backup_$(date +%F).tar.gz -C /data .

Variabili ambiente (infra/.env)

Variabile Descrizione
POSTGRES_PASSWORD Password DB
SECRET_KEY_BASE Rails secret
JWT_SECRET Token API mobile
MEDIAMTX_WEBHOOK_SECRET HMAC webhook
MEDIAMTX_RTMP_URL URL pubblico RTMP per telefoni
APP_PUBLIC_URL Base HTTPS per link watch (/live/:id)
HLS_PUBLIC_URL Base URL HLS (es. https://dominio/hls)
CORS_ORIGINS Origini app (dominio HTTPS)
ALLOWED_HOSTS Host header Rails
YOUTUBE_* OAuth YouTube (tier premium)

Template: infra/.env.production.example


Roadmap Gitea / CI (fase 2)

  1. Repository Gitea con mirror monorepo
  2. Pipeline su push main:
    • bundle exec rspec (backend)
    • docker build immagine matchlivetv/backend:$CI_COMMIT_SHA
    • Push registry (Gitea packages o Docker Hub privato)
  3. Deploy job SSH:
    docker compose -f docker-compose.prod.yml pull
    docker compose -f docker-compose.prod.yml up -d
    
  4. Secret in Gitea: tutte le variabili .env

Stato deploy 2026-05-25

Step Stato
Codice sincronizzato in ~/matchlivetv Completato
infra/.env con secret generati Completato (sul server)
Docker installato In attesa — richiede sudo bash server_bootstrap.sh
Stack avviato In attesa — dopo Docker

Informazioni ancora da definire

  • IP pubblico WAN o DDNS per MEDIAMTX_RTMP_URL da internet
  • Dominio per NPM e certificato SSL
  • Credenziali YouTube OAuth produzione
  • URL repository Gitea