This commit is contained in:
2025-07-19 12:21:46 +02:00
parent 12822dfdbf
commit 2e7957d0a0
86 changed files with 25573 additions and 0 deletions

94
docker/.dockerignore Normal file
View File

@@ -0,0 +1,94 @@
# Dependencies
node_modules
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Production builds
tournament-frontend/build
tournament-frontend/dist
# Environment files
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
# IDE files
.vscode
.idea
*.swp
*.swo
# OS files
.DS_Store
Thumbs.db
# Git
.git
.gitignore
# Docker
Dockerfile
docker-compose.yml
.dockerignore
# Logs
logs
*.log
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Dependency directories
jspm_packages/
# Optional npm cache directory
.npm
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# next.js build output
.next
# nuxt.js build output
.nuxt
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port

43
docker/Dockerfile Normal file
View File

@@ -0,0 +1,43 @@
# Use Node.js 20 as base image
FROM node:20-alpine
# Set working directory
WORKDIR /app
# Install system dependencies
RUN apk add --no-cache git
# Copy package files
COPY package*.json ./
COPY tournament-frontend/package*.json ./tournament-frontend/
# Install dependencies
RUN npm ci
RUN cd tournament-frontend && npm ci
# Copy application code
COPY . .
# Build the frontend
RUN cd tournament-frontend && npm run build
# Copy built frontend to backend public directory
RUN mkdir -p public && cp -r tournament-frontend/build/* public/
# Create non-root user
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nodejs -u 1001
# Change ownership of the app directory
RUN chown -R nodejs:nodejs /app
USER nodejs
# Expose port
EXPOSE 4000
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD node -e "require('http').get('http://localhost:4000/', (res) => { process.exit(res.statusCode === 200 ? 0 : 1) })"
# Start the application
CMD ["node", "index.js"]

137
docker/ENVIRONMENT.md Normal file
View File

@@ -0,0 +1,137 @@
# Environment Configuration Guide
## Development Environment
For development, use the default `docker-compose.yml`:
```bash
cd docker
docker-compose up -d
```
### Default Credentials (Development)
- **Admin Username**: `admin`
- **Admin Password**: `admin123`
- **Database**: `tournament`
- **Database User**: `tournament_user`
- **Database Password**: `tournament_password`
## Production Environment
For production deployment, use `docker-compose.prod.yml`:
```bash
cd docker
./deploy.sh
```
### Environment Variables (Production)
Create a `.env` file in the docker directory with the following variables:
```env
# Database Configuration
POSTGRES_PASSWORD=your_secure_postgres_password_here
# Application Configuration
JWT_SECRET=your_super_secure_jwt_secret_here_make_it_long_and_random
ADMIN_USERNAME=admin
ADMIN_PASSWORD=your_secure_admin_password_here
ADMIN_EMAIL=admin@yourdomain.com
# Optional: Custom domain for SSL
DOMAIN=yourdomain.com
```
### Security Checklist for Production
- [ ] Change `POSTGRES_PASSWORD` to a strong password
- [ ] Change `JWT_SECRET` to a long, random string
- [ ] Change `ADMIN_PASSWORD` to a secure password
- [ ] Update `ADMIN_EMAIL` to a valid email address
- [ ] Configure SSL certificates (optional)
- [ ] Set up proper firewall rules
- [ ] Configure backup strategy
- [ ] Set up monitoring and logging
### SSL Configuration
To enable HTTPS:
1. Create an `ssl` directory in the docker folder
2. Add your SSL certificates:
- `ssl/cert.pem` - SSL certificate
- `ssl/key.pem` - Private key
3. Uncomment the HTTPS section in `nginx.conf`
4. Update the domain name in `nginx.conf`
### Backup and Restore
#### Database Backup
```bash
docker-compose exec postgres pg_dump -U tournament_user tournament > backup.sql
```
#### Database Restore
```bash
docker-compose exec -T postgres psql -U tournament_user tournament < backup.sql
```
#### Full Application Backup
```bash
# Backup volumes
docker run --rm -v tournament_postgres_data:/data -v $(pwd):/backup alpine tar czf /backup/postgres_backup.tar.gz -C /data .
```
### Monitoring
#### Health Checks
- Application: `http://localhost/health`
- Database: Built into docker-compose
- Nginx: Built into docker-compose
#### Logs
```bash
# View all logs
docker-compose logs -f
# View specific service logs
docker-compose logs -f tournament-app
docker-compose logs -f postgres
docker-compose logs -f nginx
```
### Scaling
The application can be scaled horizontally:
```bash
docker-compose up -d --scale tournament-app=3
```
Note: You'll need to configure a load balancer (like nginx) to distribute traffic across multiple instances.
### Troubleshooting
#### Common Issues
1. **Port conflicts**: Change ports in docker-compose.yml
2. **Database connection issues**: Check if PostgreSQL is running and healthy
3. **Build failures**: Ensure all dependencies are properly installed
4. **Permission issues**: Check file permissions and ownership
#### Debug Commands
```bash
# Check container status
docker-compose ps
# Access application shell
docker-compose exec tournament-app sh
# Check database connection
docker-compose exec postgres psql -U tournament_user -d tournament
# View nginx configuration
docker-compose exec nginx nginx -t
```

165
docker/README.md Normal file
View File

@@ -0,0 +1,165 @@
# Tournament Application Docker Setup
This directory contains the Docker configuration for the Tournament Application.
## Files
- `Dockerfile` - Multi-stage build for the application
- `docker-compose.yml` - Complete stack with PostgreSQL and Nginx
- `nginx.conf` - Nginx reverse proxy configuration
- `.dockerignore` - Excludes unnecessary files from build context
## Quick Start
### Prerequisites
- Docker
- Docker Compose
### Running the Application
1. **Start the complete stack:**
```bash
cd docker
docker-compose up -d
```
2. **Access the application:**
- Frontend: http://localhost:80
- API: http://localhost:4000
- Database: localhost:5432
3. **View logs:**
```bash
docker-compose logs -f
```
4. **Stop the application:**
```bash
docker-compose down
```
## Services
### Tournament App (Port 4000)
- Node.js backend with Express
- React frontend (built and served by backend)
- Prisma ORM for database operations
- Socket.IO for real-time updates
### PostgreSQL (Port 5432)
- Database: `tournament`
- User: `tournament_user`
- Password: `tournament_password`
### Nginx (Port 80/443)
- Reverse proxy for the application
- Static file serving
- SSL termination (configured but disabled by default)
## Environment Variables
The application uses the following environment variables:
```env
DATABASE_URL=postgresql://tournament_user:tournament_password@postgres:5432/tournament
PORT=4000
JWT_SECRET=your-super-secret-jwt-key-change-in-production
ADMIN_USERNAME=admin
ADMIN_PASSWORD=admin123
ADMIN_EMAIL=admin@tournament.com
```
## Development
### Building the Image
```bash
cd docker
docker build -t tournament-app -f Dockerfile ..
```
### Running with Custom Environment
```bash
docker-compose -f docker-compose.yml -f docker-compose.override.yml up
```
## Production Deployment
### Security Considerations
1. **Change default passwords:**
- Update `ADMIN_PASSWORD` in docker-compose.yml
- Update `JWT_SECRET` to a strong random string
- Update PostgreSQL password
2. **Enable HTTPS:**
- Uncomment HTTPS section in nginx.conf
- Add SSL certificates to `./ssl/` directory
- Update domain name in nginx.conf
3. **Database Security:**
- Use external PostgreSQL instance in production
- Implement proper backup strategy
- Use connection pooling
### Scaling
The application can be scaled horizontally:
```bash
docker-compose up -d --scale tournament-app=3
```
## Troubleshooting
### Database Connection Issues
1. Check if PostgreSQL is running:
```bash
docker-compose ps postgres
```
2. Check database logs:
```bash
docker-compose logs postgres
```
### Application Issues
1. Check application logs:
```bash
docker-compose logs tournament-app
```
2. Access application shell:
```bash
docker-compose exec tournament-app sh
```
### Nginx Issues
1. Check nginx logs:
```bash
docker-compose logs nginx
```
2. Test nginx configuration:
```bash
docker-compose exec nginx nginx -t
```
## Data Persistence
The PostgreSQL data is persisted in a Docker volume named `postgres_data`. To backup:
```bash
docker-compose exec postgres pg_dump -U tournament_user tournament > backup.sql
```
To restore:
```bash
docker-compose exec -T postgres psql -U tournament_user tournament < backup.sql
```

36
docker/build.sh Executable file
View File

@@ -0,0 +1,36 @@
#!/bin/bash
# Tournament Application Docker Build Script
set -e
echo "🏗️ Building Tournament Application Docker Image..."
# Check if we're in the docker directory
if [ ! -f "docker-compose.yml" ]; then
echo "❌ Error: Please run this script from the docker directory"
exit 1
fi
# Build the application image
echo "📦 Building application image..."
docker build -t tournament-app -f Dockerfile ..
# Check if build was successful
if [ $? -eq 0 ]; then
echo "✅ Application image built successfully!"
else
echo "❌ Failed to build application image"
exit 1
fi
echo "🎉 Build completed successfully!"
echo ""
echo "To run the application:"
echo " docker-compose up -d"
echo ""
echo "To view logs:"
echo " docker-compose logs -f"
echo ""
echo "To stop the application:"
echo " docker-compose down"

55
docker/deploy.sh Executable file
View File

@@ -0,0 +1,55 @@
#!/bin/bash
# Tournament Application Production Deployment Script
set -e
echo "🚀 Deploying Tournament Application to Production..."
# Check if we're in the docker directory
if [ ! -f "docker-compose.prod.yml" ]; then
echo "❌ Error: Please run this script from the docker directory"
exit 1
fi
# Check if .env file exists
if [ ! -f ".env" ]; then
echo "⚠️ Warning: No .env file found. Using default values."
echo " Create a .env file with production values for security."
fi
# Stop existing containers
echo "🛑 Stopping existing containers..."
docker-compose -f docker-compose.prod.yml down
# Build and start the application
echo "🏗️ Building and starting application..."
docker-compose -f docker-compose.prod.yml up -d --build
# Wait for services to be healthy
echo "⏳ Waiting for services to be ready..."
sleep 10
# Check if services are running
echo "🔍 Checking service status..."
docker-compose -f docker-compose.prod.yml ps
# Check application health
echo "🏥 Checking application health..."
if curl -f http://localhost/health > /dev/null 2>&1; then
echo "✅ Application is healthy!"
else
echo "⚠️ Application health check failed, but it might still be starting up..."
fi
echo ""
echo "🎉 Deployment completed!"
echo ""
echo "Application URLs:"
echo " Frontend: http://localhost"
echo " API: http://localhost:4000"
echo ""
echo "Useful commands:"
echo " View logs: docker-compose -f docker-compose.prod.yml logs -f"
echo " Stop app: docker-compose -f docker-compose.prod.yml down"
echo " Restart: docker-compose -f docker-compose.prod.yml restart"

View File

@@ -0,0 +1,95 @@
version: '3.8'
services:
# PostgreSQL Database
postgres:
image: postgres:15-alpine
container_name: tournament-postgres-prod
environment:
POSTGRES_DB: tournament
POSTGRES_USER: tournament_user
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-change_me_in_production}
volumes:
- postgres_data:/var/lib/postgresql/data
- ../prisma/migrations:/docker-entrypoint-initdb.d
ports:
- "127.0.0.1:5432:5432" # Only accessible from localhost
healthcheck:
test: ["CMD-SHELL", "pg_isready -U tournament_user -d tournament"]
interval: 10s
timeout: 5s
retries: 5
networks:
- tournament-network
restart: unless-stopped
# Tournament Application
tournament-app:
build:
context: ..
dockerfile: docker/Dockerfile
container_name: tournament-app-prod
environment:
- DATABASE_URL=postgresql://tournament_user:${POSTGRES_PASSWORD:-change_me_in_production}@postgres:5432/tournament
- PORT=4000
- JWT_SECRET=${JWT_SECRET:-change_me_in_production}
- ADMIN_USERNAME=${ADMIN_USERNAME:-admin}
- ADMIN_PASSWORD=${ADMIN_PASSWORD:-change_me_in_production}
- ADMIN_EMAIL=${ADMIN_EMAIL:-admin@tournament.com}
- NODE_ENV=production
ports:
- "127.0.0.1:4000:4000" # Only accessible from localhost
depends_on:
postgres:
condition: service_healthy
volumes:
- ../prisma:/app/prisma
networks:
- tournament-network
restart: unless-stopped
deploy:
resources:
limits:
memory: 512M
cpus: '0.5'
reservations:
memory: 256M
cpus: '0.25'
# Nginx Reverse Proxy
nginx:
image: nginx:alpine
container_name: tournament-nginx-prod
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./ssl:/etc/nginx/ssl:ro
- nginx_logs:/var/log/nginx
depends_on:
- tournament-app
networks:
- tournament-network
restart: unless-stopped
deploy:
resources:
limits:
memory: 128M
cpus: '0.25'
reservations:
memory: 64M
cpus: '0.1'
volumes:
postgres_data:
driver: local
nginx_logs:
driver: local
networks:
tournament-network:
driver: bridge
ipam:
config:
- subnet: 172.20.0.0/16

70
docker/docker-compose.yml Normal file
View File

@@ -0,0 +1,70 @@
version: '3.8'
services:
# PostgreSQL Database
postgres:
image: postgres:15-alpine
container_name: tournament-postgres
environment:
POSTGRES_DB: tournament
POSTGRES_USER: tournament_user
POSTGRES_PASSWORD: tournament_password
volumes:
- postgres_data:/var/lib/postgresql/data
- ./prisma/migrations:/docker-entrypoint-initdb.d
ports:
- "5432:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U tournament_user -d tournament"]
interval: 10s
timeout: 5s
retries: 5
networks:
- tournament-network
# Tournament Application
tournament-app:
build:
context: ..
dockerfile: docker/Dockerfile
container_name: tournament-app
environment:
- DATABASE_URL=postgresql://tournament_user:tournament_password@postgres:5432/tournament
- PORT=4000
- JWT_SECRET=your-super-secret-jwt-key-change-in-production
- ADMIN_USERNAME=admin
- ADMIN_PASSWORD=admin123
- ADMIN_EMAIL=admin@tournament.com
ports:
- "4000:4000"
depends_on:
postgres:
condition: service_healthy
volumes:
- ../prisma:/app/prisma
networks:
- tournament-network
restart: unless-stopped
# Nginx Reverse Proxy (Optional)
nginx:
image: nginx:alpine
container_name: tournament-nginx
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./ssl:/etc/nginx/ssl:ro
depends_on:
- tournament-app
networks:
- tournament-network
restart: unless-stopped
volumes:
postgres_data:
networks:
tournament-network:
driver: bridge

85
docker/nginx.conf Normal file
View File

@@ -0,0 +1,85 @@
events {
worker_connections 1024;
}
http {
upstream tournament_backend {
server tournament-app:4000;
}
server {
listen 80;
server_name localhost;
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;
# API routes
location /api/ {
proxy_pass http://tournament_backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
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;
proxy_cache_bypass $http_upgrade;
}
# WebSocket support for Socket.IO
location /socket.io/ {
proxy_pass http://tournament_backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
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;
}
# Serve static files (React build)
location / {
root /usr/share/nginx/html;
try_files $uri $uri/ /index.html;
# Cache static assets
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}
# Health check endpoint
location /health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
}
# HTTPS configuration (uncomment and configure SSL certificates)
# server {
# listen 443 ssl http2;
# server_name localhost;
#
# ssl_certificate /etc/nginx/ssl/cert.pem;
# ssl_certificate_key /etc/nginx/ssl/key.pem;
#
# # SSL configuration
# ssl_protocols TLSv1.2 TLSv1.3;
# ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384;
# ssl_prefer_server_ciphers off;
#
# # Same location blocks as above
# location /api/ {
# proxy_pass http://tournament_backend;
# # ... same proxy settings
# }
# }
}