L'Infrastruttura Dietro la Piattaforma
Costruire una piattaforma come Play The Event non significa soltanto scrivere codice applicativo: significa anche progettare un'infrastruttura che garantisca affidabilità, riproducibilità e facilità di deploy. Dall'ambiente di sviluppo locale alla VPS di produzione, ogni componente infrastrutturale è stato pensato per ridurre i tempi di deploy, minimizzare gli errori manuali e garantire che i servizi siano sempre disponibili.
Questo articolo esplora l'intero stack DevOps di Play The Event: dalla containerizzazione con Docker Compose alla configurazione Nginx con SSL, dai servizi systemd agli script di automazione, fino alla gestione delle migrazioni database e della cache Redis.
Cosa Troverai in Questo Articolo
- Docker Compose per l'ambiente di sviluppo con MySQL, Redis, phpMyAdmin e Redis Commander
- Nginx come reverse proxy con SSL Let's Encrypt, rate limiting e security headers
- Servizi systemd per avvio automatico di backend e frontend
- 18+ script Bash per deploy, avvio, stop, restart e manutenzione
- 199 migrazioni Flyway per l'evoluzione dello schema MySQL
- Redis con configurazione 256MB e policy allkeys-lru
- Gestione log e monitoraggio salute dei servizi
Docker Compose: L'Ambiente di Sviluppo
L'ambiente di sviluppo di Play The Event è completamente containerizzato tramite Docker Compose. Quattro servizi orchestrati garantiscono che ogni sviluppatore possa avviare l'intero stack con un singolo comando, senza preoccuparsi di installare e configurare manualmente MySQL, Redis o i tool di amministrazione.
version: '3.8'
services:
# MySQL 8.4.3 - Database principale
mysql:
image: mysql:8.4.3
container_name: management-events-mysql
restart: unless-stopped
environment:
MYSQL_DATABASE: management_events_db
MYSQL_USER: events_user
TZ: Europe/Rome
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
- ./backend/src/main/resources/db/init:/docker-entrypoint-initdb.d
command:
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_unicode_ci
- --max_connections=200
- --innodb_buffer_pool_size=1G
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5
# Redis 7.4.1 - Cache e sessioni
redis:
image: redis:7.4.1-alpine
container_name: management-events-redis
restart: unless-stopped
ports:
- "6379:6379"
volumes:
- redis_data:/data
command: >
redis-server --appendonly yes
--maxmemory 256mb
--maxmemory-policy allkeys-lru
# phpMyAdmin - Gestione database via web
phpmyadmin:
image: phpmyadmin:5.2
container_name: management-events-phpmyadmin
ports:
- "8081:80"
depends_on:
mysql:
condition: service_healthy
# Redis Commander - Gestione cache via web
redis-commander:
image: rediscommander/redis-commander:latest
container_name: management-events-redis-commander
environment:
REDIS_HOSTS: local:redis:6379
ports:
- "8082:8081"
depends_on:
redis:
condition: service_healthy
Alcuni aspetti chiave della configurazione Docker:
- Health checks: sia MySQL che Redis hanno health check integrati. I servizi dipendenti (phpMyAdmin, Redis Commander) attendono che i servizi base siano pronti prima di avviarsi
- Volumi persistenti:
mysql_dataeredis_datagarantiscono che i dati sopravvivano al riavvio dei container - MySQL ottimizzato:
utf8mb4per supporto Unicode completo,innodb_buffer_pool_size=1Gper prestazioni ottimali, fino a 200 connessioni simultanee - Redis con AOF:
appendonly yesabilita la persistenza su disco. La policyallkeys-lruevita l'esaurimento della memoria eliminando le chiavi meno recentemente utilizzate
Porte dei Servizi di Sviluppo
- 3306 - MySQL 8.4.3 (database principale)
- 6379 - Redis 7.4.1 (cache e sessioni)
- 8080 - Backend Spring Boot (API REST)
- 4200 - Frontend Angular (dev server)
- 8081 - phpMyAdmin (gestione database)
- 8082 - Redis Commander (gestione cache)
Nginx: Reverse Proxy con SSL
In produzione, Nginx funge da reverse proxy davanti a tutti i servizi di Play The Event. Gestisce il terminamento SSL, il routing delle richieste, la compressione gzip, il caching degli asset statici e la protezione tramite rate limiting.
# Upstream per il backend Spring Boot
upstream backend_api {
server localhost:8080 fail_timeout=5s max_fails=3;
keepalive 32;
}
# Rate limiting zones
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=100r/m;
limit_req_zone $binary_remote_addr zone=login_limit:10m rate=10r/m;
server {
listen 443 ssl http2;
server_name playtheevent.com www.playtheevent.com;
# SSL Let's Encrypt
ssl_certificate /etc/letsencrypt/live/playtheevent.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/playtheevent.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# Gzip compression
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_comp_level 6;
gzip_types text/plain text/css application/json
application/javascript text/xml image/svg+xml;
# Backend API con rate limiting
location /api/ {
limit_req zone=api_limit burst=20 nodelay;
proxy_pass http://backend_api;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# Rate limiting stretto per login
location /api/auth/login {
limit_req zone=login_limit burst=5 nodelay;
proxy_pass http://backend_api;
}
# Frontend Angular (SSR o static)
location / {
try_files $uri $uri/ /index.html;
}
# Asset statici con cache lunga
location ~* \.(js|css|png|jpg|svg|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}
Sicurezza a Livello di Rete
La configurazione Nginx implementa diverse strategie di protezione:
- Rate limiting a due livelli: le API generali sono limitate a 100 richieste al minuto per IP, mentre gli endpoint di autenticazione hanno un limite molto più restrittivo di 10 richieste al minuto, con risposta HTTP 429 in caso di superamento
- SSL con Let's Encrypt: certificati gratuiti con rinnovo automatico tramite Certbot. Lo script
setup-ssl.shautomatizza la verifica DNS, l'installazione di Certbot e la generazione dei certificati - Security headers: protezione contro clickjacking (
X-Frame-Options), MIME sniffing (X-Content-Type-Options) e XSS (X-XSS-Protection) - Blocco file sensibili: qualsiasi richiesta a file che iniziano con
.(come.env,.git) viene bloccata automaticamente
Health Check Endpoint
Nginx espone un endpoint /health dedicato al monitoraggio esterno. Questo endpoint
restituisce una risposta semplice senza toccare il backend, permettendo ai sistemi di monitoraggio
di verificare che il reverse proxy sia attivo.
# Health check endpoint (risposta diretta da Nginx)
location /health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
# Nginx status per monitoraggio (solo localhost)
location /nginx_status {
stub_status on;
access_log off;
allow 127.0.0.1;
deny all;
}
Systemd: Servizi ad Avvio Automatico
Il backend Spring Boot e il frontend Angular vengono gestiti come servizi systemd sulla VPS Ubuntu 24.04. Questo garantisce che i servizi si riavviino automaticamente dopo un crash o un reboot del server.
[Unit]
Description=Play the Event - Backend Spring Boot API
After=network.target mysql.service
Wants=mysql.service
[Service]
Type=simple
User=federicocalo
WorkingDirectory=/home/ubuntu/managementevents/backend
# Environment
Environment="JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64"
Environment="SPRING_PROFILES_ACTIVE=prod"
EnvironmentFile=/home/ubuntu/managementevents/backend/.env.prod
# Esecuzione con JAR precompilato
ExecStart=/usr/bin/java -jar target/management-events-backend.jar
# Restart policy
Restart=on-failure
RestartSec=10s
StartLimitInterval=5min
StartLimitBurst=3
# Resource limits
LimitNOFILE=65536
LimitNPROC=4096
# Logging
StandardOutput=journal
StandardError=journal
SyslogIdentifier=play-the-event-backend
# Security
NoNewPrivileges=true
PrivateTmp=true
# Graceful shutdown
TimeoutStopSec=30s
KillMode=mixed
KillSignal=SIGTERM
[Install]
WantedBy=multi-user.target
[Unit]
Description=Play the Event - Frontend Angular
After=network.target
[Service]
Type=simple
User=federicocalo
WorkingDirectory=/home/ubuntu/managementevents/frontend
# Environment
Environment="NODE_ENV=production"
# Angular serve (SSR o static)
ExecStart=/usr/bin/npm start
# Restart policy
Restart=on-failure
RestartSec=10s
StartLimitInterval=5min
StartLimitBurst=3
# Logging
StandardOutput=journal
StandardError=journal
SyslogIdentifier=play-the-event-frontend
# Security
NoNewPrivileges=true
PrivateTmp=true
# Graceful shutdown
TimeoutStopSec=15s
KillMode=mixed
KillSignal=SIGTERM
[Install]
WantedBy=multi-user.target
Aspetti importanti della configurazione systemd:
- Dipendenze: il backend dichiara
After=mysql.serviceeWants=mysql.service, assicurando che MySQL sia avviato prima dell'applicazione Spring Boot - Restart automatico:
Restart=on-failureconRestartSec=10sriavvia automaticamente il servizio dopo un crash, con un limite di 3 tentativi in 5 minuti per evitare loop infiniti - Variabili d'ambiente: le configurazioni sensibili sono caricate da
.env.prodtramiteEnvironmentFile, mantenendo le credenziali fuori dal codice sorgente - Sicurezza:
NoNewPrivileges=trueimpedisce l'escalation dei privilegi,PrivateTmp=trueisola la directory temporanea del servizio - Graceful shutdown:
KillSignal=SIGTERMconKillMode=mixedinvia prima un segnale di terminazione al processo principale, poi forza l'arresto dei processi figli dopo il timeout
Script di Deploy Automatizzato
Il deploy di Play The Event è gestito da una suite di 18+ script Bash che automatizzano ogni aspetto del ciclo di vita dell'applicazione sulla VPS OVHcloud.
Script di Deploy
deploy-all.shdeploy-backend.shdeploy-frontend.shdeploy-analytics.shrestart-all.shstart-all.shstop-all.sh
Script di Setup e Manutenzione
setup-nginx.shsetup-ssl.shsetup-mysql-databases.shsetup-analytics.shupdate-nginx-ssr.shupdate-vps-config.shcleanup-logs-vps.shwatch-logs.sh
Il Deploy Orchestrato: deploy-all.sh
Lo script principale deploy-all.sh orchestra il deploy di tutti i servizi
con supporto per esecuzione sequenziale o parallela, skip selettivo dei servizi e
report dettagliato con tempi di esecuzione.
# Deploy completo (sequenziale)
./scripts/deploy-all.sh
# Deploy parallelo (più veloce)
./scripts/deploy-all.sh --parallel
# Solo frontend e analytics (salta backend)
./scripts/deploy-all.sh --skip-be
# Continua anche se un deploy fallisce
./scripts/deploy-all.sh --continue
Il flusso del deploy-all.sh include:
- Parsing argomenti: supporto per
--parallel,--skip-be,--skip-fe,--skip-ai,--continue - Deploy sequenziale o parallelo: in modalità parallela i tre servizi vengono avviati come processi background, con attesa del completamento di tutti
- Health check: dopo il deploy, verifica che ogni servizio risponda correttamente tramite i rispettivi endpoint di health
- Report finale: mostra lo stato di ogni servizio (SUCCESS, ERROR, SKIPPED) con i tempi di esecuzione
Il Deploy del Backend
Lo script deploy-backend.sh gestisce l'intero ciclo di vita del deploy backend
in 8 step automatizzati:
# Step 1: Verifica prerequisiti (Java 21, Maven, MySQL)
# Step 2: Navigazione alla directory backend
# Step 3: Caricamento variabili da .env.prod + test connessione DB
# Step 4: Build Maven (mvnw clean package -DskipTests)
# Step 5: Verifica database e migrazioni Flyway
# Step 6: Creazione/aggiornamento servizio systemd
# Step 7: Restart servizio con verifica stato
# Step 8: Health check con retry (max 15 tentativi, 2s intervallo)
# Comandi utili post-deploy:
sudo systemctl status management-events-backend
sudo journalctl -u management-events-backend -f
curl http://localhost:8080/api/health
Gestione della VPS OVHcloud
La piattaforma gira su una VPS OVHcloud con Ubuntu 24.04. Gli script start-all.sh,
stop-all.sh e restart-all.sh gestiscono l'intero ciclo di vita
dei servizi sulla VPS.
# Ordine di avvio dei servizi:
# [1/5] Verifica e avvio MySQL
systemctl start mysql
mysql -u root -e "USE management_events_system;"
# [2/5] Stop servizi esistenti (pulizia)
systemctl stop management-events-backend
systemctl stop management-events-frontend
# [3/5] Avvio backend Spring Boot
systemctl start management-events-backend
# Attesa health check su localhost:8080/api/health
# [4/5] Avvio frontend Angular
systemctl start management-events-frontend
# Attesa health check su localhost:4200
# [5/5] Verifica e reload Nginx
systemctl reload nginx
# Verifica proxy funzionante
Ordine di Avvio Critico
L'ordine di avvio è fondamentale: MySQL deve essere completamente operativo prima che
il backend Spring Boot tenti di connettersi, altrimenti Flyway fallirà nell'eseguire
le migrazioni. Per questo motivo start-all.sh verifica non solo che MySQL sia
attivo, ma anche che il database specifico sia raggiungibile, prima di procedere con il backend.
Migrazioni Database con Flyway
Lo schema del database MySQL di Play The Event è gestito tramite 199 migrazioni Flyway versionate. Ogni modifica allo schema è una migrazione SQL numerata che viene eseguita automaticamente all'avvio del backend Spring Boot.
backend/src/main/resources/db/migration/
├── V1__create_users_table.sql
├── V2__create_events_table.sql
├── V3__create_participants_table.sql
├── ...
├── V98__create_analytics_tables.sql
├── V99__create_tipologie_luogo_table.sql
├── V100__create_luoghi_table.sql
├── V101__create_festival_table.sql
├── V102__create_giornate_festival_table.sql
└── ... (199 migrazioni totali)
Flyway tiene traccia delle migrazioni già eseguite nella tabella flyway_schema_history.
All'avvio, il backend confronta le migrazioni presenti nel classpath con quelle già eseguite
e applica solo le nuove. Questo approccio garantisce:
- Evoluzione incrementale: lo schema evolve gradualmente senza mai perdere dati
- Riproducibilità: qualsiasi istanza del database può raggiungere lo stato attuale eseguendo tutte le migrazioni in ordine
- Tracciabilità: ogni modifica allo schema è un file SQL nel repository Git, con autore, data e motivo della modifica
- Sicurezza: le migrazioni sono idempotenti e non possono essere modificate dopo l'esecuzione (Flyway verifica il checksum)
Redis: Cache e Gestione Sessioni
Redis svolge un ruolo critico nell'architettura di Play The Event, gestendo sia la cache delle query frequenti sia le sessioni utente. La configurazione è ottimizzata per un ambiente con memoria limitata.
# Avvio Redis con configurazione personalizzata
redis-server \
--appendonly yes \
--maxmemory 256mb \
--maxmemory-policy allkeys-lru
# appendonly yes → Persistenza AOF su disco
# maxmemory 256mb → Limite memoria massima
# maxmemory-policy → Eviction delle chiavi meno usate
La policy allkeys-lru (Least Recently Used) è stata scelta perché in un contesto di event management, i dati più recenti sono generalmente i più rilevanti: gli eventi attivi, le sessioni correnti e le query più frequenti hanno la priorità sulla cache di dati vecchi o poco consultati.
Utilizzi di Redis nella Piattaforma
- Cache query: i risultati delle query più frequenti (lista eventi pubblici, dettagli evento) vengono cachati per ridurre il carico su MySQL
- Sessioni utente: i dati di sessione sono memorizzati in Redis per supportare la scalabilità orizzontale del backend
- Rate limiting: i contatori per il rate limiting delle API sono gestiti in Redis con TTL automatico
- Dati temporanei: token di verifica email, codici OTP e dati di checkout Stripe con scadenza automatica
Gestione Log
La suite di script include strumenti dedicati alla gestione dei log, essenziali per il debugging in produzione e per il mantenimento dello spazio disco sulla VPS.
Watch Log in Tempo Reale
Lo script watch-logs.sh offre un menu interattivo per lo streaming dei log
in tempo reale, con 9 opzioni che coprono tutti i servizi:
Seleziona quale log visualizzare:
1) Backend (systemd journal)
2) Backend (application log)
3) Backend (error log)
4) Frontend (systemd journal)
5) Frontend (application log)
6) Frontend (error log)
7) Nginx (access log)
8) Nginx (error log)
9) Tutti i backend logs (multipli)
L'opzione 9 utilizza multitail (se disponibile) per visualizzare simultaneamente
log systemd, log applicativo e log errori con prefissi colorati. In assenza di multitail,
uno script di fallback combina più processi tail -f con prefissi
[SYSTEMD], [APP] e [ERROR].
Pulizia Automatica dei Log
Lo script cleanup-logs-vps.sh automatizza la pulizia dei log sulla VPS,
scansionando le directory di log, eliminando i file e ripulendo i journal systemd
più vecchi di 7 giorni.
# Directory monitorate per la pulizia
LOG_DIRS=(
"/var/log/management-events"
"/home/ubuntu/managementevents/logs"
"/opt/management-events/logs"
)
# Per ogni directory: conta file, calcola dimensione, elimina
# Pulisce anche journalctl logs > 7 giorni
sudo journalctl --vacuum-time=7d
# Mostra spazio disco rimanente
df -h /
Setup SSL con Let's Encrypt
Lo script setup-ssl.sh automatizza l'intera configurazione HTTPS per il dominio
playtheevent.com. Il processo include la verifica DNS, l'installazione di Certbot,
la generazione dei certificati e la configurazione del rinnovo automatico.
# Configurazione
DOMAIN="playtheevent.com"
WWW_DOMAIN="www.playtheevent.com"
# Step 1: Verifica DNS
# - Recupera IP della VPS (curl ifconfig.me)
# - Verifica che il dominio punti all'IP corretto (dig +short)
# - Controlla sia @ che www
# Step 2: Installazione Certbot
sudo apt install -y certbot python3-certbot-nginx
# Step 3: Generazione certificati
sudo certbot --nginx \
-d playtheevent.com \
-d www.playtheevent.com \
--email admin@playtheevent.com \
--agree-tos
# Step 4: Verifica rinnovo automatico (cron)
sudo certbot renew --dry-run
Monitoraggio e Health Check
Il sistema di monitoraggio di Play The Event verifica la salute di tutti i servizi dopo ogni deploy e può essere eseguito su richiesta.
# Health check integrato nel deploy-all.sh:
# Backend - verifica risposta HTTP 200
curl -s -o /dev/null -w "%{http_code}" \
http://localhost:8080/api/health
# Frontend SSR - verifica risposta HTTP 200/301/302
curl -s -o /dev/null -w "%{http_code}" \
http://localhost:4200
# Analytics - verifica risposta HTTP 200
curl -s -o /dev/null -w "%{http_code}" \
http://localhost:8001/health
# Nginx - verifica proxy funzionante
curl -s https://playtheevent.com/health
Il report finale del deploy mostra una vista chiara dello stato:
╔════════════════════════════════════════════╗
║ REPORT DEPLOY ║
╚════════════════════════════════════════════╝
Stato Servizi:
✓ Backend SUCCESS (2m 34s)
✓ Frontend SUCCESS (1m 12s)
✓ Analytics SUCCESS (45s)
Tempo totale: 4m 31s
URL di accesso:
• Frontend: https://playtheevent.com
• API: https://playtheevent.com/api
• Analytics: http://localhost:8001/docs
Riepilogo dell'Infrastruttura
Stack Infrastrutturale Completo
- VPS: OVHcloud Ubuntu 24.04 LTS
- Containerizzazione: Docker Compose per lo sviluppo (MySQL 8.4.3, Redis 7.4.1, phpMyAdmin, Redis Commander)
- Web Server: Nginx come reverse proxy con SSL Let's Encrypt, rate limiting e compressione gzip
- Process Manager: systemd per avvio automatico e restart on-failure di backend e frontend
- Database: MySQL 8.4.3 con 199 migrazioni Flyway versionate
- Cache: Redis 7.4.1 con 256MB, policy allkeys-lru, persistenza AOF
- Automazione: 18+ script Bash per deploy, setup, manutenzione e monitoraggio
- SSL: Let's Encrypt con rinnovo automatico tramite Certbot
L'infrastruttura di Play The Event dimostra come anche un progetto gestito da un singolo sviluppatore possa avere un livello di automazione e affidabilità paragonabile a team più grandi, grazie a script ben strutturati, servizi systemd e una configurazione Nginx solida.
Il codice sorgente è disponibile su GitHub.







