Il monorepo punta a native/android (login, wizard, diretta RTMP, tabellone WebSocket, pausa/telemetria) con encode 16:9 e orientamento via sensore; eliminati mobile/ e gli script Flutter obsoleti. Co-authored-by: Cursor <cursoragent@cursor.com>
7.2 KiB
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-05-27
Architettura rete
Internet
│
├──► Router WAN :443 ──► Nginx Proxy Manager (LAN) ──► http://192.168.1.146:3000 (Rails API + Action Cable)
│
└──► Router WAN :1935 ──► MediaMTX RTMP (telefoni, ingest video diretto)
Il flusso video non passa da Rails: telefono → RTMP :1935 → MediaMTX → relay ffmpeg → YouTube.
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)
- Proxy Host → Forward Hostname:
http://192.168.1.146:3000(dominio principalewww.matchlivetv.it, redirect apexmatchlivetv.it→www) - Websockets: ON (obbligatorio per
/cable) - Custom location HLS (spettatori):
- Location:
/hls - Forward:
http://192.168.1.146:8888(in NPM usare proxy pass che rimuove il prefisso/hls, così MediaMTX riceve/live/match_{uuid}/index.m3u8) - Scheme: http
- URL pubblico:
https://www.matchlivetv.it/hls/live/match_{uuid}/index.m3u8
- Location:
- SSL Let's Encrypt su NPM
- Aggiorna
infra/.envsul server:APP_PUBLIC_URL=https://www.matchlivetv.itHLS_PUBLIC_URL=https://www.matchlivetv.it/hlsCORS_ORIGINS=https://www.matchlivetv.it,https://matchlivetv.itALLOWED_HOSTS=www.matchlivetv.it,matchlivetv.it,192.168.1.146MEDIAMTX_RTMP_URL=rtmp://www.matchlivetv.it:1935YOUTUBE_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:
# Tar + scp (rsync non installato sul server)
tar -C /path/to/MatchLiveTV/src -czf /tmp/matchlivetv-deploy.tar.gz \
--exclude='./native/android/build' --exclude='./backend/log' --exclude='./.git' .
scp /tmp/matchlivetv-deploy.tar.gz eminux@192.168.1.146:~/
ssh eminux@192.168.1.146 'tar -xzf ~/matchlivetv-deploy.tar.gz -C ~/matchlivetv'
# Sul server
cd ~/matchlivetv/infra && docker compose -f docker-compose.prod.yml up -d --build
Script: scripts/deploy/sync_to_server.sh (richiede rsync sul server).
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— databaserecordings— 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)
- Repository Gitea con mirror monorepo
- Pipeline su push
main:bundle exec rspec(backend)docker buildimmaginematchlivetv/backend:$CI_COMMIT_SHA- Push registry (Gitea packages o Docker Hub privato)
- Deploy job SSH:
docker compose -f docker-compose.prod.yml pull docker compose -f docker-compose.prod.yml up -d - 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_URLda internet - Dominio per NPM e certificato SSL
- Credenziali YouTube OAuth produzione
- URL repository Gitea