플랫폼 뒤의 인프라
와 같은 플랫폼을 구축하다 이벤트를 플레이하세요 이는 단지 애플리케이션 코드 작성을 의미하는 것이 아니라 인프라 설계를 의미하기도 합니다. 보장하는 신뢰할 수 있음, 재현성 e 배포 용이성. 로컬 개발 환경부터 프로덕션 VPS까지, 각 인프라 구성 요소는 배포 시간을 줄이고 최소화하도록 설계되었습니다. 수동 오류를 방지하고 서비스가 항상 사용 가능한지 확인합니다.
이 문서에서는 Play The Event의 전체 DevOps 스택을 살펴봅니다. Docker Compose에서 SSL을 사용한 Nginx 설정, 시스템 서비스부터 자동화 스크립트까지, 데이터베이스 마이그레이션 및 Redis 캐시 관리까지.
이 기사에서 찾을 수 있는 내용
- MySQL, Redis, phpMyAdmin 및 Redis Commander를 사용한 개발 환경용 Docker Compose
- SSL Let's Encrypt, 속도 제한 및 보안 헤더를 사용하는 역방향 프록시인 Nginx
- 백엔드와 프런트엔드를 자동으로 시작하기 위한 systemd 서비스
- 배포, 시작, 중지, 다시 시작 및 유지 관리를 위한 18개 이상의 Bash 스크립트
- 199 MySQL 스키마 발전을 위한 이동 경로 마이그레이션
- 256MB 구성 및 allkeys-lru 정책을 갖춘 Redis
- 로그 관리 및 서비스 상태 모니터링
Docker Compose: 개발 환경
개발 환경 이벤트를 플레이하세요 Docker Compose를 통해 완전히 컨테이너화됩니다. 4가지 오케스트레이션된 서비스 모든 개발자가 단일 명령으로 전체 스택을 시작할 수 있도록 보장합니다. MySQL, Redis 또는 관리 도구를 수동으로 설치하고 구성하는 것에 대해 걱정할 필요가 없습니다.
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
Docker 구성의 몇 가지 주요 측면:
- 상태 확인: MySQL과 Redis에는 모두 상태 확인 기능이 내장되어 있습니다. 종속 서비스(phpMyAdmin, Redis Commander)는 시작하기 전에 기본 서비스가 준비될 때까지 기다립니다.
- 영구 볼륨:
mysql_dataeredis_data컨테이너를 다시 시작해도 데이터가 유지되는지 확인 - 최적화된 MySQL:
utf8mb4완전한 유니코드 지원을 위해innodb_buffer_pool_size=1G최적의 성능을 위해 최대 200개의 동시 연결 - AOF를 사용한 Redis:
appendonly yes디스크 지속성을 활성화합니다. 정책allkeys-lru가장 최근에 사용한 키를 삭제하여 메모리 부족 방지
개발 서비스 도어
- 3306 - MySQL 8.4.3(마스터 데이터베이스)
- 6379 - Redis 7.4.1(캐시 및 세션)
- 8080 - 스프링 부트 백엔드(REST API)
- 4200 - Angular 프론트엔드(서버 개발)
- 8081 - phpMyAdmin (데이터베이스 관리)
- 8082 - Redis Commander(캐시 관리)
Nginx: SSL을 사용한 역방향 프록시
프로덕션에서는 Nginx가 다음 역할을 합니다. 역방향 프록시 모든 서비스 앞에서 이벤트를 플레이하세요. SSL 종료, 요청 라우팅, gzip 압축, 캐싱 처리 정적 자산을 보호하고 속도 제한을 통해 보호합니다.
# 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";
}
}
네트워크 수준 보안
Nginx 구성은 여러 보호 전략을 구현합니다.
- 2단계 속도 제한: 일반 API는 IP당 분당 100개의 요청으로 제한되는 반면, 인증 엔드포인트는 분당 10개의 요청으로 훨씬 더 제한적이며 초과할 경우 HTTP 429 응답을 받습니다.
- Let's Encrypt를 사용한 SSL: Certbot을 통해 자동 갱신되는 무료 인증서. 스크립트
setup-ssl.shDNS 확인, Certbot 설치 및 인증서 생성을 자동화합니다. - 보안 헤더: 클릭재킹 방지(
X-Frame-Options), MIME 스니핑(X-Content-Type-Options) 및 XSS(X-XSS-Protection) - 민감한 파일 잠금: 다음으로 시작하는 파일에 대한 모든 요청
.(처럼.env,.git)은 자동으로 차단됩니다.
상태 확인 엔드포인트
Nginx는 엔드포인트를 노출합니다. /health 외부 모니터링 전용입니다. 이 엔드포인트
백엔드를 건드리지 않고 간단한 응답을 반환하므로 모니터링 시스템이 가능합니다.
역방향 프록시가 활성화되어 있는지 확인합니다.
# 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: 자동 시작 서비스
Spring Boot 백엔드와 Angular 프런트엔드는 VPS에서 시스템 서비스로 관리됩니다. 우분투 24.04. 이렇게 하면 충돌 후 서비스가 자동으로 다시 시작됩니다. 또는 서버 재부팅.
[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
시스템 구성의 중요한 측면:
- 종속성: 백엔드는 선언한다
After=mysql.serviceeWants=mysql.service, Spring Boot 애플리케이션 이전에 MySQL이 시작되었는지 확인 - 자동 재시작:
Restart=on-failure~와 함께RestartSec=10s무한 루프를 피하기 위해 5분 안에 3번의 시도로 제한되어 충돌 후 서비스를 자동으로 다시 시작합니다. - 환경 변수: 민감한 구성은 다음에서 로드됩니다.
.env.prod~을 통해EnvironmentFile, 소스 코드에서 자격 증명을 유지합니다. - 안전:
NoNewPrivileges=true권한 상승을 방지합니다.PrivateTmp=true서비스 임시 디렉터리를 격리합니다. - 정상 종료:
KillSignal=SIGTERM~와 함께KillMode=mixed먼저 상위 프로세스에 종료 신호를 보낸 다음 시간 초과 후 하위 프로세스를 강제로 중지합니다.
자동 배포 스크립트
Play The Event의 배포는 다음 제품군에 의해 관리됩니다. 18개 이상의 Bash 스크립트 OVHcloud VPS에서 애플리케이션 수명주기의 모든 측면을 자동화합니다.
배포 스크립트
deploy-all.shdeploy-backend.shdeploy-frontend.shdeploy-analytics.shrestart-all.shstart-all.shstop-all.sh
설정 및 유지 관리 스크립트
setup-nginx.shsetup-ssl.shsetup-mysql-databases.shsetup-analytics.shupdate-nginx-ssr.shupdate-vps-config.shcleanup-logs-vps.shwatch-logs.sh
오케스트레이션된 배포: 배포-all.sh
주요 스크립트 deploy-all.sh 모든 서비스의 배포를 조율합니다.
순차 또는 병렬 실행, 선택적 서비스 건너뛰기 및
실행 시간이 포함된 자세한 보고서입니다.
# 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
배포-all.sh 흐름에는 다음이 포함됩니다.
- 구문 분석 인수: 에 대한 지원
--parallel,--skip-be,--skip-fe,--skip-ai,--continue - 순차 또는 병렬 배포: 병렬 모드에서는 세 가지 서비스가 백그라운드 프로세스로 시작되어 모두 완료될 때까지 기다립니다.
- 상태 확인: 배포 후 각 서비스가 해당 상태 엔드포인트를 통해 올바르게 응답하는지 확인합니다.
- 최종 보고서: 각 서비스의 상태(SUCCESS, ERROR, SKIPPED)를 실행 시간과 함께 표시합니다.
백엔드 배포
스크립트 deploy-backend.sh 전체 백엔드 배포 수명주기를 관리합니다.
8가지 자동화 단계:
# 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
OVHcloud VPS 관리
플랫폼은 Ubuntu 24.04가 설치된 OVHcloud VPS에서 실행됩니다. 스크립트 start-all.sh,
stop-all.sh e restart-all.sh 전체 수명주기를 관리
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
중요한 부팅 순서
부팅 순서가 중요합니다. 그 전에 MySQL이 완전히 작동해야 합니다.
Spring Boot 백엔드가 연결을 시도합니다. 그렇지 않으면 Flyway가 실행되지 않습니다.
마이그레이션. 이러한 이유로 start-all.sh MySQL이
활성화되어 있지만 백엔드를 진행하기 전에 특정 데이터베이스에 연결할 수 있는지도 확인합니다.
Flyway를 사용한 데이터베이스 마이그레이션
MySQL 데이터베이스 스키마 이벤트를 플레이하세요 통해 관리됩니다 199 이동 경로 마이그레이션 버전이 지정되었습니다. 스키마에 대한 모든 변경 사항 백엔드가 시작될 때 자동으로 실행되는 번호가 매겨진 SQL 마이그레이션입니다. 스프링부트.
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는 테이블에서 이미 수행된 마이그레이션을 추적합니다. flyway_schema_history.
시작 시 백엔드는 클래스 경로에 있는 마이그레이션과 이미 수행된 마이그레이션을 비교합니다.
그리고 새로운 것만 적용하세요. 이 접근 방식은 다음을 보장합니다.
- 점진적인 진화: 데이터 손실 없이 체계가 점진적으로 발전합니다.
- 재현성: 모든 데이터베이스 인스턴스는 모든 마이그레이션을 순서대로 수행하여 현재 상태에 도달할 수 있습니다.
- 추적성: 각 스키마 변경은 작성자, 날짜 및 변경 이유가 포함된 Git 저장소의 SQL 파일입니다.
- 안전: 마이그레이션은 멱등성이 있으며 실행 후에는 수정할 수 없습니다(Flyway는 체크섬을 확인합니다).
Redis: 캐시 및 세션 관리
Redis는 Play The Event의 아키텍처에서 캐시와 캐시를 모두 관리하는 중요한 역할을 합니다. 빈번한 쿼리 및 사용자 세션. 구성은 다음에 최적화되어 있습니다. 메모리가 제한된 환경.
# 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
정책 allkeys-lru (가장 최근에 사용됨)이 선택된 이유는 다음과 같습니다. 이벤트 관리 측면에서는 일반적으로 최신 데이터가 가장 관련성이 높습니다. 활성 이벤트, 현재 세션 및 가장 자주 묻는 질문이 우선적으로 적용됩니다. 오래되었거나 거의 참조되지 않는 데이터의 캐시에 있습니다.
플랫폼에서 Redis 사용
- 쿼리 캐시: 가장 빈번한 쿼리의 결과(공개 이벤트 목록, 이벤트 세부 정보)가 캐시되어 MySQL의 로드가 줄어듭니다.
- 사용자 세션: 세션 데이터는 백엔드의 수평 확장을 지원하기 위해 Redis에 저장됩니다.
- 속도 제한: API 속도 제한 카운터는 Redis에서 자동 TTL로 처리됩니다.
- 임시 데이터: 이메일 확인 토큰, OTP 코드, 자동 만료되는 Stripe 체크아웃 데이터
로그 관리
스크립트 제품군에는 로그 관리 전용 도구가 포함되어 있습니다. 프로덕션 디버깅 및 VPS의 디스크 공간 유지를 위한 것입니다.
실시간 로그인 보기
스크립트 watch-logs.sh 로그 스트리밍을 위한 대화형 메뉴 제공
모든 서비스를 포괄하는 9가지 옵션을 실시간으로 제공합니다.
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)
옵션 9 사용 multitail (사용 가능한 경우) 동시에 보기
색상이 지정된 접두사가 있는 시스템 로그, 응용 프로그램 로그 및 오류 로그입니다. 멀티테일이 없을 경우,
대체 스크립트는 여러 프로세스를 결합합니다. tail -f 접두사가 있는
[SYSTEMD], [APP] e [ERROR].
자동 로그 정리
스크립트 cleanup-logs-vps.sh VPS에서 로그 정리를 자동화하고,
로그 디렉터리 검색, 파일 삭제, 시스템 저널 정리
7일이 넘었습니다.
# 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 /
Let's Encrypt를 사용한 SSL 설정
스크립트 setup-ssl.sh 도메인에 대한 전체 HTTPS 구성을 자동화합니다.
playtheevent.com. 프로세스에는 DNS 확인, Certbot 설치,
인증서 생성 및 자동 갱신 구성.
# 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
모니터링 및 상태 점검
Play The Event의 모니터링 시스템은 모든 서비스의 상태를 확인합니다. 각 배포 후에 필요에 따라 실행할 수 있습니다.
# 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
최종 배포 보고서에는 상태가 명확하게 표시됩니다.
╔════════════════════════════════════════════╗
║ 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
인프라 요약
완벽한 인프라 스택
- VPS: OVHcloud 우분투 24.04 LTS
- 컨테이너화: 개발용 Docker Compose(MySQL 8.4.3, Redis 7.4.1, phpMyAdmin, Redis Commander)
- 웹 서버: SSL Let's Encrypt, 속도 제한 및 gzip 압축을 사용하는 역방향 프록시인 Nginx
- 프로세스 관리자: 백엔드와 프론트엔드 실패 시 자동 시작 및 재시작을 위한 systemd
- 데이터베이스: 199개의 Flyway 마이그레이션 버전이 포함된 MySQL 8.4.3
- 은닉처: 256MB의 Redis 7.4.1, allkeys-lru 정책, AOF 지속성
- 오토메이션: 배포, 설정, 유지 관리 및 모니터링을 위한 18개 이상의 Bash 스크립트
- SSL: Certbot을 통한 자동 갱신으로 암호화하자
인프라 이벤트를 플레이하세요 단일 개발자가 관리하는 프로젝트에도 레벨이 있을 수 있음을 보여줍니다. 스크립트 덕분에 대규모 팀에 필적하는 자동화 및 안정성 잘 구조화되고 체계적인 서비스와 견고한 Nginx 설정.
소스 코드는 다음에서 확인할 수 있습니다. GitHub.







