A Infraestrutura por Trás da Plataforma
Construir uma plataforma como Play The Event não significa apenas escrever código aplicativo: significa também projetar uma infraestrutura que garanta fiabilidade, reprodutibilidade e facilidade de deploy. Desde o ambiente de desenvolvimento local até ao VPS de produção, cada componente de infraestrutura foi pensado para reduzir os tempos de deploy, minimizar os erros manuais e garantir que os serviços estejam sempre disponíveis.
Este artigo explora todo o stack DevOps do Play The Event: desde a containerização com Docker Compose até à configuração Nginx com SSL, dos serviços systemd aos scripts de automação, passando pela gestão das migrações de base de dados e da cache Redis.
O que Você Encontrará Neste Artigo
- Docker Compose para o ambiente de desenvolvimento com MySQL, Redis, phpMyAdmin e Redis Commander
- Nginx como reverse proxy com SSL Let's Encrypt, rate limiting e security headers
- Serviços systemd para arranque automático de backend e frontend
- 18+ scripts Bash para deploy, arranque, paragem, reinício e manutenção
- 199 migrações Flyway para a evolução do esquema MySQL
- Redis com configuração de 256MB e política allkeys-lru
- Gestão de logs e monitoramento da saúde dos serviços
Docker Compose: O Ambiente de Desenvolvimento
O ambiente de desenvolvimento do Play The Event está completamente containerizado através do Docker Compose. Quatro serviços orquestrados garantem que cada programador possa arrancar todo o stack com um único comando, sem se preocupar em instalar e configurar manualmente MySQL, Redis ou as ferramentas de administração.
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
Alguns aspectos principais da configuração do Docker:
- Health checks: Tanto MySQL como Redis têm health checks integrados. Os serviços dependentes (phpMyAdmin, Redis Commander) aguardam que os serviços base estejam prontos antes de arrancar
- Volumes persistentes:
mysql_dataeredis_datagarantem que os dados sobrevivam ao reinício dos contentores - MySQL otimizado:
utf8mb4para suporte Unicode completo,innodb_buffer_pool_size=1Gpara desempenho ótimo, até 200 conexões simultâneas - Redis com AOF:
appendonly yesativa a persistência em disco. A políticaallkeys-lruevita o esgotamento da memória eliminando as chaves menos recentemente utilizadas
Portas dos Serviços de Desenvolvimento
- 3306 - MySQL 8.4.3 (base de dados principal)
- 6379 - Redis 7.4.1 (cache e sessões)
- 8080 - Backend Spring Boot (API REST)
- 4200 - Frontend Angular (servidor de desenvolvimento)
- 8081 - phpMyAdmin (gestão de base de dados)
- 8082 - Redis Commander (gestão de cache)
Nginx: Reverse Proxy com SSL
Em produção, o Nginx funciona como reverse proxy à frente de todos os serviços do Play The Event. Gere a terminação SSL, o encaminhamento de pedidos, a compressão gzip, o caching de assets estáticos e a proteção através de 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";
}
}
Segurança ao Nível da Rede
A configuração Nginx implementa diversas estratégias de proteção:
- Rate limiting em dois níveis: As APIs gerais estão limitadas a 100 pedidos por minuto por IP, enquanto os endpoints de autenticação têm um limite muito mais restritivo de 10 pedidos por minuto, com resposta HTTP 429 em caso de excesso
- SSL com Let's Encrypt: Certificados gratuitos com renovação automática através do Certbot. O script
setup-ssl.shautomatiza a verificação DNS, a instalação do Certbot e a geração dos certificados - Security headers: Proteção contra clickjacking (
X-Frame-Options), MIME sniffing (X-Content-Type-Options) e XSS (X-XSS-Protection) - Bloqueio de ficheiros sensíveis: Qualquer pedido a ficheiros que começam por
.(como.env,.git) é automaticamente bloqueado
Endpoint de Health Check
O Nginx expõe um endpoint /health dedicado à monitorização externa. Este endpoint
devolve uma resposta simples sem tocar no backend, permitindo aos sistemas de monitorização
verificar que o reverse proxy está ativo.
# 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: Serviços com Arranque Automático
O backend Spring Boot e o frontend Angular são geridos como serviços systemd no VPS Ubuntu 24.04. Isto garante que os serviços reiniciem automaticamente após uma falha ou um reinício do servidor.
[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
Aspectos importantes da configuração do systemd:
- Dependências: O backend declara
After=mysql.serviceeWants=mysql.service, assegurando que o MySQL seja arrancado antes da aplicação Spring Boot - Reinício automático:
Restart=on-failurecomRestartSec=10sreinicia automaticamente o serviço após uma falha, com um limite de 3 tentativas em 5 minutos para evitar loops infinitos - Variáveis de ambiente: As configurações sensíveis são carregadas a partir de
.env.prodviaEnvironmentFile, mantendo as credenciais fora do código-fonte - Segurança:
NoNewPrivileges=trueimpede a escalada de privilégios,PrivateTmp=trueisola o diretório temporário do serviço - Paragem elegante:
KillSignal=SIGTERMcomKillMode=mixedenvia primeiro um sinal de terminação ao processo principal, depois força a paragem dos processos filhos após o timeout
Script de Deploy Automatizado
O deploy do Play The Event é gerido por uma suite de 18+ scripts Bash que automatizam cada aspeto do ciclo de vida da aplicação no VPS OVHcloud.
Scripts de Deploy
deploy-all.shdeploy-backend.shdeploy-frontend.shdeploy-analytics.shrestart-all.shstart-all.shstop-all.sh
Scripts de Setup e Manutenção
setup-nginx.shsetup-ssl.shsetup-mysql-databases.shsetup-analytics.shupdate-nginx-ssr.shupdate-vps-config.shcleanup-logs-vps.shwatch-logs.sh
O Deploy Orquestrado: deploy-all.sh
O script principal deploy-all.sh orquestra o deploy de todos os serviços
com suporte para execução sequencial ou paralela, omissão seletiva de serviços e
relatório detalhado com tempos de execução.
# 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
O fluxo do deploy-all.sh inclui:
- Parsing de argumentos: Suporte para
--parallel,--skip-be,--skip-fe,--skip-ai,--continue - Deploy sequencial ou paralelo: Em modo paralelo, os três serviços são lançados como processos em segundo plano, com espera pela conclusão de todos
- Health check: Após o deploy, verifica que cada serviço responde corretamente através dos respetivos endpoints de health
- Relatório final: Mostra o estado de cada serviço (SUCCESS, ERROR, SKIPPED) com os tempos de execução
O Deploy do Backend
O script deploy-backend.sh gere todo o ciclo de vida do deploy do backend
em 8 passos automatizados:
# 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
Gestão do VPS OVHcloud
A plataforma funciona num VPS OVHcloud com Ubuntu 24.04. Os scripts start-all.sh,
stop-all.sh e restart-all.sh gerem todo o ciclo de vida
dos serviços no 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
Ordem de Arranque Crítica
A ordem de arranque é fundamental: o MySQL deve estar completamente operacional antes que
o backend Spring Boot tente conectar-se, caso contrário o Flyway falhará ao executar
as migrações. Por este motivo, o start-all.sh verifica não só que o MySQL está
ativo, mas também que a base de dados específica está acessível, antes de prosseguir com o backend.
Migrações de Base de Dados com Flyway
O esquema da base de dados MySQL do Play The Event é gerido através de 199 migrações Flyway versionadas. Cada modificação ao esquema é uma migração SQL numerada que é executada automaticamente ao arrancar o 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)
O Flyway regista as migrações já executadas na tabela flyway_schema_history.
Ao arrancar, o backend compara as migrações presentes no classpath com as já executadas
e aplica apenas as novas. Esta abordagem garante:
- Evolução incremental: O esquema evolui gradualmente sem nunca perder dados
- Reprodutibilidade: Qualquer instância da base de dados pode atingir o estado atual executando todas as migrações por ordem
- Rastreabilidade: Cada modificação ao esquema é um ficheiro SQL no repositório Git, com autor, data e motivo da modificação
- Segurança: As migrações são idempotentes e não podem ser modificadas após a execução (o Flyway verifica o checksum)
Redis: Cache e Gestão de Sessões
O Redis desempenha um papel crítico na arquitetura do Play The Event, gerindo tanto a cache das consultas frequentes como as sessões de utilizador. A configuração está otimizada para um ambiente com memória limitada.
# 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
A política allkeys-lru (Least Recently Used) foi escolhida porque num contexto de gestão de eventos, os dados mais recentes são geralmente os mais relevantes: os eventos ativos, as sessões atuais e as consultas mais frequentes têm prioridade sobre a cache de dados antigos ou pouco consultados.
Utilizações do Redis na Plataforma
- Cache de consultas: Os resultados das consultas mais frequentes (lista de eventos públicos, detalhes do evento) são cacheados para reduzir a carga sobre o MySQL
- Sessões de utilizador: Os dados de sessão são armazenados no Redis para suportar a escalabilidade horizontal do backend
- Rate limiting: Os contadores para o rate limiting das APIs são geridos no Redis com TTL automático
- Dados temporários: Tokens de verificação de email, códigos OTP e dados de checkout do Stripe com expiração automática
Gestão de Logs
A suite de scripts inclui ferramentas dedicadas à gestão de logs, essenciais para o debugging em produção e para a manutenção do espaço em disco no VPS.
Monitorização de Logs em Tempo Real
O script watch-logs.sh oferece um menu interativo para o streaming de logs
em tempo real, com 9 opções que cobrem todos os serviços:
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)
A opção 9 utiliza multitail (se disponível) para visualizar simultaneamente
o log systemd, o log aplicativo e o log de erros com prefixos coloridos. Na ausência de multitail,
um script de fallback combina múltiplos processos tail -f com prefixos
[SYSTEMD], [APP] e [ERROR].
Limpeza Automática de Logs
O script cleanup-logs-vps.sh automatiza a limpeza de logs no VPS,
varrendo os diretórios de logs, eliminando os ficheiros e limpando os journals systemd
com mais de 7 dias.
# 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 /
Configuração SSL com Let's Encrypt
O script setup-ssl.sh automatiza toda a configuração HTTPS para o domínio
playtheevent.com. O processo inclui a verificação DNS, a instalação do Certbot,
a geração dos certificados e a configuração da renovação automática.
# 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
Monitorização e Health Check
O sistema de monitorização do Play The Event verifica a saúde de todos os serviços após cada deploy e pode ser executado a pedido.
# 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
O relatório final do deploy mostra uma vista clara do estado:
╔════════════════════════════════════════════╗
║ 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
Retomar da infraestrutura
PIB completo com infraestrutura
- VPS: OVHcloud Ubuntu 24.04 LTS
- Containerização: Docker Compose para desenvolvimento (MySQL 8.4.3, Redis 7.4.1, phpMyAdmin, Redis Commander)
- Servidor web: Nginx como reverse proxy com SSL Let's Encrypt, rate limiting e compressão gzip
- Gestor de processos: systemd para arranque automático e reinício em caso de falha de backend e frontend
- Base de dados: MySQL 8.4.3 com 199 migrações Flyway versionadas
- Cache: Redis 7.4.1 com 256MB, política allkeys-lru, persistência AOF
- Automação: 18+ scripts Bash para deploy, configuração, manutenção e monitorização
- SSL: Let's Encrypt com renovação automática através do Certbot
A infraestrutura do Play The Event demonstra como até um projeto gerido por um único programador pode ter um nível de automação e fiabilidade comparável ao de equipas maiores, graças a scripts bem estruturados, serviços systemd e uma configuração Nginx sólida.
O código-fonte está disponível no GitHub.







