Comandi di verifica¶
Comandi usati e verificati il 27/10/2026 su ServerIT. Tutti in sola lettura, tranne la sezione Backup, che crea file ma non modifica i servizi.
Le password non si scrivono mai nei comandi: si usano le variabili d'ambiente già presenti nei container (MYSQL_ROOT_PASSWORD, REDIS_PASSWORD). Questi comandi stampano solo numeri e date, quindi l'output si può condividere. Non condividere output che contengono MAC, codici impianto o nomi.
Fotografia di ServerIT¶
docker ps -a --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}'
docker compose ls
sudo ss -tulpn | grep LISTEN # servizi in ascolto, anche fuori da Docker
free -h; df -h /; uptime
ip -br addr; ip route
cd ~/mdm_mid_server && git status && git diff --stat
Registro dei box (Redis)¶
R=qalarm_internal_new-redis-1
# box online adesso
docker exec $R sh -c 'export REDISCLI_AUTH="$REDIS_PASSWORD"; redis-cli --scan --pattern "MAC_*" | wc -l'
# box nel registro e quanti con la scheda PIN
docker exec $R sh -c 'export REDISCLI_AUTH="$REDIS_PASSWORD"; t=0; p=0;
for k in $(redis-cli --scan); do case "$k" in MAC_*) continue;; esac
[ "$(redis-cli type "$k")" = string ] || continue
v=$(redis-cli get "$k"); case "$v" in *last_update*) t=$((t+1));
echo "$v" | grep -q "\"has_pin\": *true" && p=$((p+1));; esac
done; echo "box=$t con_pin=$p"'
# ultimo aggiornamento e stato online di ogni box, senza mostrare i MAC
docker exec $R sh -c 'export REDISCLI_AUTH="$REDIS_PASSWORD";
for k in $(redis-cli --scan); do case "$k" in MAC_*) continue;; esac
[ "$(redis-cli type "$k")" = string ] || continue
v=$(redis-cli get "$k"); case "$v" in *last_update*)
echo "$(echo "$v" | grep -o "\"last_update\": *\"[^\"]*\"") online=$(redis-cli exists "MAC_$k")";; esac
done | sort'
# persistenza
docker inspect $R --format '{{range .Mounts}}{{.Type}} {{.Destination}} {{.Name}}{{"\n"}}{{end}}'
docker exec $R sh -c 'export REDISCLI_AUTH="$REDIS_PASSWORD"; redis-cli config get appendonly; redis-cli config get save; redis-cli lastsave'
Nota: redis-cli --scan scorre tutte le chiavi. Con poche decine di box va bene; non usarlo in un ciclo continuo.
Database (MySQL)¶
M=msql_container
docker exec $M sh -c 'mysql -u root -p"$MYSQL_ROOT_PASSWORD" -N q_alarm_mid -e "
SELECT \"installations (backup)\", COUNT(*) FROM installations
UNION ALL SELECT \"new_installations\", COUNT(*) FROM new_installations;"' 2>/dev/null
# dimensione delle tabelle
docker exec $M sh -c 'mysql -u root -p"$MYSQL_ROOT_PASSWORD" -e "
SELECT table_name, table_rows, ROUND((data_length+index_length)/1024/1024,1) AS mb
FROM information_schema.tables WHERE table_schema=\"q_alarm_mid\" ORDER BY mb DESC;"' 2>/dev/null
Se l'output è vuoto, la variabile MYSQL_ROOT_PASSWORD non è impostata nel container (l'errore è nascosto da 2>/dev/null).
Midserver e servizi¶
docker logs midserver --since 24h 2>&1 | tail -n 50
docker logs midserver --since 720h 2>&1 | grep -cE '<percorso>' # quante chiamate a un endpoint in 30 giorni
docker logs mosquitto --since 24h 2>&1 | grep -c 'New client'
curl -s -o /dev/null -w '%{http_code}\n' 'http://localhost:8080/ewelink.php?action=health'
Backup¶
Crea file, non modifica i servizi. Spostare subito i file fuori dalla VM.
D=$(date +%F)
# MySQL (nessun blocco delle tabelle InnoDB)
docker exec msql_container sh -c 'exec mysqldump -u root -p"$MYSQL_ROOT_PASSWORD" --single-transaction --routines --triggers q_alarm_mid' 2>/dev/null | gzip > q_alarm_mid-$D.sql.gz
ls -lh q_alarm_mid-$D.sql.gz # controllare che non sia di pochi byte
# Redis: forza uno snapshot e copia il file (aspettare che LASTSAVE cambi)
docker exec qalarm_internal_new-redis-1 sh -c 'export REDISCLI_AUTH="$REDIS_PASSWORD"; redis-cli lastsave; redis-cli bgsave'
sleep 5
docker exec qalarm_internal_new-redis-1 sh -c 'export REDISCLI_AUTH="$REDIS_PASSWORD"; redis-cli lastsave'
docker cp qalarm_internal_new-redis-1:/data/dump.rdb redis-$D.rdb
# configurazione di ServerIT (contiene segreti: conservare cifrato)
tar czf serverit-config-$D.tgz -C ~ mdm_mid_server/docker-compose.yml mdm_mid_server/.env.prod mdm_mid_server/server_data ewelink_integration/compose.yaml ewelink_integration/data
VPN: cosa raggiunge un box¶
Serve a verificare R3 (attività T0.4). Va eseguito da un box, possibilmente di test, collegato alla VPN dei clienti (172.16.16.x). Da un PC sulla VPN aziendale di Cava il risultato non vale. Fa solo tentativi di connessione TCP, senza inviare dati né modificare nulla.
check() { timeout 3 bash -c "</dev/tcp/$1/$2" 2>/dev/null && echo "APERTA $1:$2 $3" || echo "chiusa $1:$2 $3"; }
# attese APERTE (servono ai box)
check 172.16.16.253 5000 "midserver HTTP"
check 172.16.16.253 1883 "Mosquitto"
# dovrebbero essere CHIUSE per un box
check 172.16.16.253 3306 "MySQL midserver"
check 172.16.16.253 6379 "Redis midserver"
check 172.16.16.253 7070 "phpMyAdmin"
check 172.16.16.253 8080 "ewelink (relè e cancelli)"
check 172.16.16.253 81 "admin Nginx Proxy Manager"
check 172.16.16.253 22 "SSH ServerIT"
check 172.16.16.1 80 "pannello pfSense"
check 185.31.66.229 8006 "Proxmox"
check 170.10.0.101 80 "FreePBX web"
check 170.10.0.107 22 "SSH Coolify dev"
check 172.16.16.252 5000 "midserver dev"
# un altro box: sostituire con l'IP VPN di un altro box di test
check 172.16.16.XXX 5005 "API di un altro box"
Come leggere il risultato: se una qualsiasi delle righe "dovrebbero essere CHIUSE" risulta APERTA, R3 è confermato. Annotare il risultato (solo le righe, senza dati dei clienti) in rischi-e-problemi.md.
Su pfSense, controllare anche Firewall → Rules → Floating, che non era stato letto il 27/10.
pfSense e Proxmox¶
Da interfaccia web, con un'utenza in sola lettura:
- pfSense: Firewall → NAT → Port Forward, Firewall → Virtual IPs, Firewall → Rules (WAN, WG_VPN, WG_STS_CAVA, gruppo WireGuard), VPN → WireGuard → Status, Diagnostics → ARP Table, Diagnostics → States (filtro per IP), Status → Traffic Graph.
- Proxmox: Datacenter → Summary, Node → Network, VM → Hardware, Datacenter → Backup. Via API con un token PVEAuditor: GET /api2/json/cluster/resources, /nodes/pve/network, /nodes/pve/qemu/<id>/config, /cluster/backup.