Die Infrastruktur hinter der Plattform
Eine Plattform wie Play The Event zu bauen bedeutet nicht nur, Anwendungscode zu schreiben: es bedeutet auch, eine Infrastruktur zu entwerfen, die Zuverlässigkeit, Reproduzierbarkeit und einfaches Deployment garantiert. Von der lokalen Entwicklungsumgebung bis zur Produktions-VPS wurde jede Infrastrukturkomponente darauf ausgelegt, die Deployment-Zeiten zu reduzieren, manuelle Fehler zu minimieren und sicherzustellen, dass die Dienste immer verfügbar sind.
Dieser Artikel untersucht den gesamten DevOps-Stack von Play The Event: von der Containerisierung mit Docker Compose über die Nginx-Konfiguration mit SSL, von systemd-Diensten bis zu Automatisierungsskripten, bis hin zur Verwaltung der Datenbankmigrationen und des Redis-Caches.
Was Sie in diesem Artikel finden
- Docker Compose für die Entwicklungsumgebung mit MySQL, Redis, phpMyAdmin und Redis Commander
- Nginx als Reverse Proxy mit SSL Let's Encrypt, Rate Limiting und Security Headers
- Systemd-Dienste für automatischen Start von Backend und Frontend
- 18+ Bash-Skripte für Deployment, Start, Stop, Neustart und Wartung
- 199 Flyway-Migrationen für die Entwicklung des MySQL-Schemas
- Redis mit 256MB-Konfiguration und allkeys-lru Policy
- Log-Verwaltung und Service-Health-Monitoring
Docker Compose: Die Entwicklungsumgebung
Die Entwicklungsumgebung von Play The Event ist vollständig mit Docker Compose containerisiert. Vier orchestrierte Dienste garantieren, dass jeder Entwickler den gesamten Stack mit einem einzigen Befehl starten kann, ohne sich um die manuelle Installation und Konfiguration von MySQL, Redis oder Verwaltungstools kümmern zu müssen.
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
Einige wichtige Aspekte der Docker-Konfiguration:
- Health Checks: Sowohl MySQL als auch Redis haben integrierte Health Checks. Abhängige Dienste (phpMyAdmin, Redis Commander) warten, bis die Basisdienste bereit sind, bevor sie starten
- Persistente Volumes:
mysql_dataundredis_datastellen sicher, dass die Daten einen Container-Neustart überleben - Optimiertes MySQL:
utf8mb4für vollständige Unicode-Unterstützung,innodb_buffer_pool_size=1Gfür optimale Leistung, bis zu 200 gleichzeitige Verbindungen - Redis mit AOF:
appendonly yesaktiviert die Persistenz auf der Festplatte. Die Policyallkeys-lruverhindert Speichererschöpfung, indem die am wenigsten kürzlich verwendeten Schlüssel entfernt werden
Ports der Entwicklungsdienste
- 3306 - MySQL 8.4.3 (Hauptdatenbank)
- 6379 - Redis 7.4.1 (Cache und Sessions)
- 8080 - Backend Spring Boot (REST API)
- 4200 - Frontend Angular (Dev-Server)
- 8081 - phpMyAdmin (Datenbankverwaltung)
- 8082 - Redis Commander (Cache-Verwaltung)
Nginx: Reverse Proxy mit SSL
In der Produktion fungiert Nginx als Reverse Proxy vor allen Diensten von Play The Event. Es verwaltet die SSL-Terminierung, das Request-Routing, die gzip-Komprimierung, das Caching statischer Assets und den Schutz durch 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";
}
}
Sicherheit auf Netzwerkebene
Die Nginx-Konfiguration implementiert verschiedene Schutzstrategien:
- Rate Limiting auf zwei Ebenen: Allgemeine APIs sind auf 100 Anfragen pro Minute pro IP begrenzt, während Authentifizierungsendpunkte ein viel restriktiveres Limit von 10 Anfragen pro Minute haben, mit HTTP 429-Antwort bei Überschreitung
- SSL mit Let's Encrypt: Kostenlose Zertifikate mit automatischer Erneuerung über Certbot. Das Skript
setup-ssl.shautomatisiert die DNS-Verifizierung, Certbot-Installation und Zertifikatsgenerierung - Security Headers: Schutz gegen Clickjacking (
X-Frame-Options), MIME-Sniffing (X-Content-Type-Options) und XSS (X-XSS-Protection) - Blockierung sensibler Dateien: Jede Anfrage an Dateien, die mit
.beginnen (wie.env,.git), wird automatisch blockiert
Health Check Endpoint
Nginx bietet einen dedizierten /health-Endpoint für externes Monitoring. Dieser Endpoint
gibt eine einfache Antwort zurück, ohne das Backend zu berühren, und ermöglicht es Monitoring-Systemen,
zu überprüfen, ob der Reverse Proxy aktiv ist.
# 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: Dienste mit automatischem Start
Das Spring Boot Backend und das Angular Frontend werden als systemd-Dienste auf der Ubuntu 24.04 VPS verwaltet. Dies garantiert, dass die Dienste nach einem Absturz oder einem Server-Neustart automatisch neu gestartet werden.
[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
Wichtige Aspekte der systemd-Konfiguration:
- Abhängigkeiten: Das Backend deklariert
After=mysql.serviceundWants=mysql.service, um sicherzustellen, dass MySQL vor der Spring Boot-Anwendung gestartet wird - Automatischer Neustart:
Restart=on-failuremitRestartSec=10sstartet den Dienst nach einem Absturz automatisch neu, mit einem Limit von 3 Versuchen in 5 Minuten, um Endlosschleifen zu vermeiden - Umgebungsvariablen: Sensible Konfigurationen werden aus
.env.prodüberEnvironmentFilegeladen, um Anmeldedaten aus dem Quellcode herauszuhalten - Sicherheit:
NoNewPrivileges=trueverhindert Rechteerweiterung,PrivateTmp=trueisoliert das temporäre Verzeichnis des Dienstes - Graceful Shutdown:
KillSignal=SIGTERMmitKillMode=mixedsendet zuerst ein Beendigungssignal an den Hauptprozess und erzwingt dann das Beenden der Kindprozesse nach dem Timeout
Automatisiertes Deployment-Skript
Das Deployment von Play The Event wird von einer Suite von 18+ Bash-Skripten verwaltet, die jeden Aspekt des Anwendungslebenszyklus auf der OVHcloud-VPS automatisieren.
Deployment-Skripte
deploy-all.shdeploy-backend.shdeploy-frontend.shdeploy-analytics.shrestart-all.shstart-all.shstop-all.sh
Setup- und Wartungsskripte
setup-nginx.shsetup-ssl.shsetup-mysql-databases.shsetup-analytics.shupdate-nginx-ssr.shupdate-vps-config.shcleanup-logs-vps.shwatch-logs.sh
Das orchestrierte Deployment: deploy-all.sh
Das Hauptskript deploy-all.sh orchestriert das Deployment aller Dienste
mit Unterstützung für sequentielle oder parallele Ausführung, selektives Überspringen von Diensten und
detailliertes Reporting mit Ausführungszeiten.
# 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
Der Ablauf von deploy-all.sh umfasst:
- Argument-Parsing: Unterstützung für
--parallel,--skip-be,--skip-fe,--skip-ai,--continue - Sequentielles oder paralleles Deployment: Im parallelen Modus werden die drei Dienste als Hintergrundprozesse gestartet, wobei auf den Abschluss aller gewartet wird
- Health Check: Nach dem Deployment wird überprüft, dass jeder Dienst über die entsprechenden Health-Endpoints korrekt antwortet
- Abschlussbericht: Zeigt den Status jedes Dienstes (SUCCESS, ERROR, SKIPPED) mit den Ausführungszeiten
Das Backend-Deployment
Das Skript deploy-backend.sh verwaltet den gesamten Lebenszyklus des Backend-Deployments
in 8 automatisierten Schritten:
# 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
VPS-Verwaltung bei OVHcloud
Die Plattform läuft auf einer OVHcloud VPS mit Ubuntu 24.04. Die Skripte start-all.sh,
stop-all.sh und restart-all.sh verwalten den gesamten Lebenszyklus
der Dienste auf der 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
Kritische Startreihenfolge
Die Startreihenfolge ist fundamental: MySQL muss vollständig betriebsbereit sein, bevor
das Spring Boot Backend versucht, eine Verbindung herzustellen, da Flyway sonst beim Ausführen
der Migrationen fehlschlägt. Aus diesem Grund überprüft start-all.sh nicht nur, dass MySQL
aktiv ist, sondern auch, dass die spezifische Datenbank erreichbar ist, bevor mit dem Backend fortgefahren wird.
Datenbankmigrationen mit Flyway
Das MySQL-Datenbankschema von Play The Event wird über 199 versionierte Flyway-Migrationen verwaltet. Jede Schema-Änderung ist eine nummerierte SQL-Migration, die automatisch beim Start des Spring Boot Backends ausgeführt wird.
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 verfolgt die bereits ausgeführten Migrationen in der Tabelle flyway_schema_history.
Beim Start vergleicht das Backend die im Classpath vorhandenen Migrationen mit den bereits ausgeführten
und wendet nur die neuen an. Dieser Ansatz garantiert:
- Inkrementelle Entwicklung: Das Schema entwickelt sich schrittweise, ohne jemals Daten zu verlieren
- Reproduzierbarkeit: Jede Datenbankinstanz kann den aktuellen Zustand erreichen, indem alle Migrationen der Reihe nach ausgeführt werden
- Nachvollziehbarkeit: Jede Schema-Änderung ist eine SQL-Datei im Git-Repository, mit Autor, Datum und Grund der Änderung
- Sicherheit: Die Migrationen sind idempotent und können nach der Ausführung nicht geändert werden (Flyway überprüft die Prüfsumme)
Redis: Cache und Session-Verwaltung
Redis spielt eine kritische Rolle in der Architektur von Play The Event und verwaltet sowohl den Cache häufiger Abfragen als auch die Benutzersitzungen. Die Konfiguration ist für eine Umgebung mit begrenztem Speicher optimiert.
# 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
Die allkeys-lru Policy (Least Recently Used) wurde gewählt, weil im Kontext des Event Managements die neuesten Daten generell am relevantesten sind: aktive Events, aktuelle Sitzungen und die häufigsten Abfragen haben Priorität gegenüber dem Cache alter oder selten aufgerufener Daten.
Verwendung von Redis in der Plattform
- Query-Cache: Die Ergebnisse der häufigsten Abfragen (öffentliche Eventliste, Eventdetails) werden gecacht, um die Last auf MySQL zu reduzieren
- Benutzersitzungen: Sitzungsdaten werden in Redis gespeichert, um die horizontale Skalierbarkeit des Backends zu unterstützen
- Rate Limiting: Die Zähler für das API-Rate-Limiting werden in Redis mit automatischem TTL verwaltet
- Temporäre Daten: E-Mail-Verifizierungstoken, OTP-Codes und Stripe-Checkout-Daten mit automatischem Ablauf
Log-Verwaltung
Die Skript-Suite enthält dedizierte Tools für die Log-Verwaltung, die für das Debugging in der Produktion und die Verwaltung des Festplattenspeichers auf der VPS unerlässlich sind.
Echtzeit-Log-Überwachung
Das Skript watch-logs.sh bietet ein interaktives Menü für das Echtzeit-Streaming der Logs
mit 9 Optionen, die alle Dienste abdecken:
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)
Option 9 verwendet multitail (falls verfügbar), um gleichzeitig
systemd-Log, Anwendungslog und Fehlerlog mit farbigen Präfixen anzuzeigen. Falls multitail nicht vorhanden,
kombiniert ein Fallback-Skript mehrere tail -f-Prozesse mit
[SYSTEMD]-, [APP]- und [ERROR]-Präfixen.
Automatische Log-Bereinigung
Das Skript cleanup-logs-vps.sh automatisiert die Log-Bereinigung auf der VPS,
durchsucht die Log-Verzeichnisse, löscht Dateien und bereinigt die systemd-Journals,
die älter als 7 Tage sind.
# 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 /
SSL-Setup mit Let's Encrypt
Das Skript setup-ssl.sh automatisiert die gesamte HTTPS-Konfiguration für die Domain
playtheevent.com. Der Prozess umfasst die DNS-Verifizierung, die Certbot-Installation,
die Zertifikatsgenerierung und die Konfiguration der automatischen Erneuerung.
# 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
Monitoring und Health Check
Das Monitoring-System von Play The Event überprüft die Gesundheit aller Dienste nach jedem Deployment und kann bei Bedarf ausgeführt werden.
# 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
Der abschließende Deployment-Bericht zeigt eine klare Übersicht des Status:
╔════════════════════════════════════════════╗
║ 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
Zusammenfassung der Infrastruktur
Vollständiger Infrastruktur-Stack
- VPS: OVHcloud Ubuntu 24.04 LTS
- Containerisierung: Docker Compose für die Entwicklung (MySQL 8.4.3, Redis 7.4.1, phpMyAdmin, Redis Commander)
- Webserver: Nginx als Reverse Proxy mit SSL Let's Encrypt, Rate Limiting und gzip-Komprimierung
- Prozessmanager: systemd für automatischen Start und Restart-on-failure von Backend und Frontend
- Datenbank: MySQL 8.4.3 mit 199 versionierten Flyway-Migrationen
- Cache: Redis 7.4.1 mit 256MB, allkeys-lru Policy, AOF-Persistenz
- Automatisierung: 18+ Bash-Skripte für Deployment, Setup, Wartung und Monitoring
- SSL: Let's Encrypt mit automatischer Erneuerung über Certbot
Die Infrastruktur von Play The Event zeigt, wie auch ein von einem einzelnen Entwickler verwaltetes Projekt ein Niveau an Automatisierung und Zuverlässigkeit erreichen kann, das größeren Teams vergleichbar ist, dank gut strukturierter Skripte, systemd-Diensten und einer soliden Nginx-Konfiguration.
Der Quellcode ist verfügbar auf GitHub.







