replaced everything with ws
This commit is contained in:
765
DEPLOYMENT_GUIDE.md
Normal file
765
DEPLOYMENT_GUIDE.md
Normal file
@@ -0,0 +1,765 @@
|
||||
# VPS Deployment Guide for Lottery Application
|
||||
|
||||
This guide will help you deploy the Lottery application to a VPS (Ubuntu) using Docker, Docker Compose, and Nginx.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Ubuntu VPS (tested on Ubuntu 20.04+)
|
||||
- Root or sudo access
|
||||
- Domain name pointing to your VPS IP (for HTTPS)
|
||||
- Basic knowledge of Linux commands
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
```
|
||||
Internet
|
||||
↓
|
||||
Nginx (HTTPS, Port 443)
|
||||
↓
|
||||
├─→ Frontend (Static files from /opt/app/frontend/dist)
|
||||
├─→ Backend API (/api/* → Docker container on port 8080)
|
||||
├─→ WebSocket (/ws → Docker container)
|
||||
└─→ Avatars (/avatars/* → /opt/app/data/avatars)
|
||||
```
|
||||
|
||||
## Step 1: Initial VPS Setup
|
||||
|
||||
### 1.1 Update System
|
||||
|
||||
```bash
|
||||
sudo apt update
|
||||
sudo apt upgrade -y
|
||||
```
|
||||
|
||||
### 1.2 Install Required Software
|
||||
|
||||
```bash
|
||||
# Install Docker
|
||||
curl -fsSL https://get.docker.com -o get-docker.sh
|
||||
sudo sh get-docker.sh
|
||||
sudo usermod -aG docker $USER
|
||||
|
||||
# Docker Compose v2+ is included with Docker (as a plugin)
|
||||
# Verify it's installed:
|
||||
docker compose version
|
||||
|
||||
# If not installed, install Docker Compose plugin:
|
||||
# For Ubuntu/Debian:
|
||||
sudo apt-get update
|
||||
sudo apt-get install docker-compose-plugin
|
||||
|
||||
# Or if you need the standalone version (older method):
|
||||
# sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
|
||||
# sudo chmod +x /usr/local/bin/docker-compose
|
||||
|
||||
# Install Nginx
|
||||
sudo apt install nginx -y
|
||||
|
||||
# Install Certbot for SSL certificates
|
||||
sudo apt install certbot python3-certbot-nginx -y
|
||||
|
||||
# Log out and log back in for Docker group to take effect
|
||||
exit
|
||||
```
|
||||
|
||||
## Step 2: Create Directory Structure
|
||||
|
||||
```bash
|
||||
# Create main application directory
|
||||
sudo mkdir -p /opt/app
|
||||
sudo chown $USER:$USER /opt/app
|
||||
|
||||
# Create subdirectories
|
||||
mkdir -p /opt/app/backend
|
||||
mkdir -p /opt/app/frontend
|
||||
mkdir -p /opt/app/nginx
|
||||
mkdir -p /opt/app/data/avatars
|
||||
mkdir -p /opt/app/mysql/data
|
||||
|
||||
# Set proper permissions
|
||||
sudo chmod -R 755 /opt/app
|
||||
sudo chown -R $USER:$USER /opt/app/data
|
||||
```
|
||||
|
||||
## Step 3: Deploy Backend
|
||||
|
||||
### 3.1 Copy Backend Files
|
||||
|
||||
From your local machine, copy the backend repository to the VPS:
|
||||
|
||||
```bash
|
||||
# On your local machine, use scp or rsync
|
||||
scp -r lottery-be/* user@your-vps-ip:/opt/app/backend/
|
||||
|
||||
# Or use git (recommended)
|
||||
# On VPS:
|
||||
cd /opt/app/backend
|
||||
git clone <your-backend-repo-url> .
|
||||
```
|
||||
|
||||
### 3.2 Plan Database Configuration
|
||||
|
||||
**Important:** MySQL runs as a Docker container (no separate MySQL installation needed). Before creating the secret file, you need to decide on your database credentials:
|
||||
|
||||
1. **Database Name**: `lottery_db` (default, can be changed)
|
||||
2. **Database Username**: `root` (default, can be changed)
|
||||
3. **Database Password**: Choose a strong, secure password
|
||||
4. **Database URL**: `jdbc:mysql://db:3306/lottery_db`
|
||||
|
||||
**Understanding the Database URL (`SPRING_DATASOURCE_URL`):**
|
||||
|
||||
The URL format is: `jdbc:mysql://<hostname>:<port>/<database-name>`
|
||||
|
||||
**For this deployment, use: `jdbc:mysql://db:3306/lottery_db`**
|
||||
|
||||
Breaking it down:
|
||||
- `jdbc:mysql://` - JDBC protocol for MySQL
|
||||
- `db` - This is the **service name** in `docker-compose.prod.yml` (acts as hostname in Docker network)
|
||||
- `3306` - Default MySQL port (internal to Docker network)
|
||||
- `lottery_db` - Database name (must match `MYSQL_DATABASE` in docker-compose)
|
||||
|
||||
**Why `db` as hostname?**
|
||||
- In Docker Compose, services communicate using their **service names** as hostnames
|
||||
- The MySQL service is named `db` in `docker-compose.prod.yml` (line 4: `services: db:`)
|
||||
- Both containers are on the same Docker network (`lottery-network`)
|
||||
- The backend container connects to MySQL using `db:3306` (not `localhost` or the VPS IP)
|
||||
- This is an **internal Docker network connection** - MySQL is not exposed to the host
|
||||
|
||||
**Quick Reference:**
|
||||
- ✅ Correct: `jdbc:mysql://db:3306/lottery_db` (uses service name)
|
||||
- ❌ Wrong: `jdbc:mysql://localhost:3306/lottery_db` (won't work - localhost refers to the container itself)
|
||||
- ❌ Wrong: `jdbc:mysql://127.0.0.1:3306/lottery_db` (won't work - same reason)
|
||||
|
||||
**Example credentials (use your own secure password!):**
|
||||
- Database URL: `jdbc:mysql://db:3306/lottery_db`
|
||||
- Database Name: `lottery_db`
|
||||
- Username: `root`
|
||||
- Password: `MySecurePassword123!`
|
||||
|
||||
**Note:** These credentials will be used in:
|
||||
- The secret file (`SPRING_DATASOURCE_URL`, `SPRING_DATASOURCE_USERNAME`, `SPRING_DATASOURCE_PASSWORD`)
|
||||
- MySQL container environment variables (`DB_PASSWORD`, `DB_ROOT_PASSWORD`)
|
||||
|
||||
The MySQL container will be created automatically when you run `docker-compose`, and the database will be initialized with these credentials.
|
||||
|
||||
### 3.3 Create Secret Configuration File
|
||||
|
||||
The application uses a mounted secret file instead of environment variables for security. Create the secret file:
|
||||
|
||||
**Option 1: Copy from template (if template file exists)**
|
||||
|
||||
```bash
|
||||
# Create the secrets directory (if it doesn't exist)
|
||||
sudo mkdir -p /run/secrets
|
||||
|
||||
# Navigate to backend directory
|
||||
cd /opt/app/backend
|
||||
|
||||
# Check if template file exists
|
||||
ls -la lottery-config.properties.template
|
||||
|
||||
# If it exists, copy it
|
||||
sudo cp lottery-config.properties.template /run/secrets/lottery-config.properties
|
||||
```
|
||||
|
||||
**Option 2: Create the file directly (if template wasn't copied)**
|
||||
|
||||
If the template file doesn't exist in `/opt/app/backend/`, create the secret file directly:
|
||||
|
||||
```bash
|
||||
# Create the secrets directory (if it doesn't exist)
|
||||
sudo mkdir -p /run/secrets
|
||||
|
||||
# Create the secret file
|
||||
sudo nano /run/secrets/lottery-config.properties
|
||||
```
|
||||
|
||||
Then paste the following content (replace placeholder values):
|
||||
|
||||
```properties
|
||||
# Lottery Application Configuration
|
||||
# Replace all placeholder values with your actual configuration
|
||||
|
||||
# ============================================
|
||||
# Database Configuration
|
||||
# ============================================
|
||||
# SPRING_DATASOURCE_URL format: jdbc:mysql://<hostname>:<port>/<database-name>
|
||||
#
|
||||
# How to determine the URL:
|
||||
# - Hostname: 'db' (this is the MySQL service name in docker-compose.prod.yml)
|
||||
# * In Docker Compose, services communicate using their service names
|
||||
# * The MySQL service is named 'db', so use 'db' as the hostname
|
||||
# * Both containers are on the same Docker network, so 'db' resolves to the MySQL container
|
||||
# - Port: '3306' (default MySQL port, internal to Docker network)
|
||||
# - Database name: 'lottery_db' (must match MYSQL_DATABASE in docker-compose.prod.yml)
|
||||
#
|
||||
# Example: jdbc:mysql://db:3306/lottery_db
|
||||
# └─┬─┘ └┬┘ └─┬──┘ └───┬────┘
|
||||
# │ │ │ └─ Database name
|
||||
# │ │ └─ Port (3306 is MySQL default)
|
||||
# │ └─ Service name in docker-compose (acts as hostname)
|
||||
# └─ JDBC protocol for MySQL
|
||||
SPRING_DATASOURCE_URL=jdbc:mysql://db:3306/lottery_db
|
||||
SPRING_DATASOURCE_USERNAME=root
|
||||
SPRING_DATASOURCE_PASSWORD=your_secure_database_password_here
|
||||
|
||||
# ============================================
|
||||
# Telegram Bot Configuration
|
||||
# ============================================
|
||||
TELEGRAM_BOT_TOKEN=your_telegram_bot_token_here
|
||||
TELEGRAM_CHANNEL_CHECKER_BOT_TOKEN=your_channel_checker_bot_token_here
|
||||
TELEGRAM_FOLLOW_TASK_CHANNEL_ID=@your_channel_name
|
||||
|
||||
# ============================================
|
||||
# Frontend Configuration
|
||||
# ============================================
|
||||
FRONTEND_URL=https://yourdomain.com
|
||||
|
||||
# ============================================
|
||||
# Avatar Storage Configuration
|
||||
# ============================================
|
||||
APP_AVATAR_STORAGE_PATH=/app/data/avatars
|
||||
APP_AVATAR_PUBLIC_BASE_URL=
|
||||
APP_AVATAR_MAX_SIZE_BYTES=2097152
|
||||
APP_AVATAR_MAX_DIMENSION=512
|
||||
|
||||
# ============================================
|
||||
# Session Configuration (Optional - defaults shown)
|
||||
# ============================================
|
||||
APP_SESSION_MAX_ACTIVE_PER_USER=5
|
||||
APP_SESSION_CLEANUP_BATCH_SIZE=5000
|
||||
APP_SESSION_CLEANUP_MAX_BATCHES=20
|
||||
|
||||
# ============================================
|
||||
# GeoIP Configuration (Optional)
|
||||
# ============================================
|
||||
GEOIP_DB_PATH=
|
||||
```
|
||||
|
||||
**Edit the secret file with your actual values:**
|
||||
|
||||
```bash
|
||||
sudo nano /run/secrets/lottery-config.properties
|
||||
```
|
||||
|
||||
**Important:** Replace all placeholder values with your actual configuration:
|
||||
|
||||
```properties
|
||||
# Database Configuration
|
||||
SPRING_DATASOURCE_URL=jdbc:mysql://db:3306/lottery_db
|
||||
SPRING_DATASOURCE_USERNAME=root
|
||||
SPRING_DATASOURCE_PASSWORD=your_secure_database_password_here
|
||||
|
||||
# Telegram Bot Configuration
|
||||
TELEGRAM_BOT_TOKEN=your_telegram_bot_token_here
|
||||
TELEGRAM_CHANNEL_CHECKER_BOT_TOKEN=your_channel_checker_bot_token_here
|
||||
TELEGRAM_FOLLOW_TASK_CHANNEL_ID=@your_channel_name
|
||||
|
||||
# Frontend Configuration
|
||||
FRONTEND_URL=https://yourdomain.com
|
||||
|
||||
# Avatar Storage Configuration
|
||||
APP_AVATAR_STORAGE_PATH=/app/data/avatars
|
||||
APP_AVATAR_PUBLIC_BASE_URL=
|
||||
|
||||
# Optional: Session Configuration (defaults shown)
|
||||
APP_SESSION_MAX_ACTIVE_PER_USER=5
|
||||
APP_SESSION_CLEANUP_BATCH_SIZE=5000
|
||||
APP_SESSION_CLEANUP_MAX_BATCHES=20
|
||||
|
||||
# Optional: GeoIP Configuration
|
||||
GEOIP_DB_PATH=
|
||||
```
|
||||
|
||||
**Set secure permissions:**
|
||||
|
||||
```bash
|
||||
# Make the file readable only by root and the docker group
|
||||
sudo chmod 640 /run/secrets/lottery-config.properties
|
||||
sudo chown root:docker /run/secrets/lottery-config.properties
|
||||
```
|
||||
|
||||
**Important Notes:**
|
||||
- The database credentials you set here (`SPRING_DATASOURCE_*`) must match the MySQL container environment variables (see Step 3.4)
|
||||
- The MySQL container will be created automatically when you run `docker-compose`
|
||||
- The database `lottery_db` will be created automatically on first startup
|
||||
- Data will persist in a Docker volume (`mysql_data`)
|
||||
|
||||
### 3.4 Set MySQL Container Environment Variables
|
||||
|
||||
The MySQL container needs the database password as environment variables. These must match the credentials in your secret file.
|
||||
|
||||
**Option 1: Read from secret file automatically (recommended - more secure and consistent)**
|
||||
|
||||
Use the provided script that reads the password from the secret file:
|
||||
|
||||
```bash
|
||||
cd /opt/app/backend
|
||||
|
||||
# Make sure the script is executable
|
||||
chmod +x scripts/load-db-password.sh
|
||||
|
||||
# Source the script to load the password (this exports DB_PASSWORD and DB_ROOT_PASSWORD)
|
||||
source scripts/load-db-password.sh
|
||||
```
|
||||
|
||||
**What this does:**
|
||||
- Reads `SPRING_DATASOURCE_PASSWORD` from `/run/secrets/lottery-config.properties`
|
||||
- Exports `DB_PASSWORD` and `DB_ROOT_PASSWORD` with the same value
|
||||
- Ensures MySQL container credentials match the backend credentials automatically
|
||||
|
||||
**Verify it worked:**
|
||||
```bash
|
||||
# Check that the variables are set
|
||||
echo "DB_PASSWORD is set: $([ -n "$DB_PASSWORD" ] && echo "yes" || echo "no")"
|
||||
```
|
||||
|
||||
**Option 2: Set environment variables manually (simpler but less secure)**
|
||||
|
||||
If you prefer to set them manually (not recommended):
|
||||
|
||||
```bash
|
||||
# Export the password (must match SPRING_DATASOURCE_PASSWORD from your secret file)
|
||||
# Replace with the actual password you set in the secret file
|
||||
export DB_PASSWORD=your_secure_database_password_here
|
||||
export DB_ROOT_PASSWORD=your_secure_database_password_here
|
||||
|
||||
# Verify it's set
|
||||
echo $DB_PASSWORD
|
||||
```
|
||||
|
||||
**Important Notes:**
|
||||
- The `DB_PASSWORD` and `DB_ROOT_PASSWORD` must match `SPRING_DATASOURCE_PASSWORD` from your secret file
|
||||
- These environment variables are only used by the MySQL container
|
||||
- The backend application reads credentials from the secret file, not from environment variables
|
||||
- **Option 1 is recommended** because it ensures consistency and reduces the chance of mismatched passwords
|
||||
|
||||
### 3.5 Build and Start Backend
|
||||
|
||||
**Before starting:** Make sure you have:
|
||||
- ✅ Secret file created at `/run/secrets/lottery-config.properties` with database credentials
|
||||
- ✅ Environment variables `DB_PASSWORD` and `DB_ROOT_PASSWORD` set (use `source scripts/load-db-password.sh` from Step 3.4)
|
||||
|
||||
```bash
|
||||
cd /opt/app/backend
|
||||
|
||||
# Make sure DB_PASSWORD and DB_ROOT_PASSWORD are set (if not already done in Step 3.4)
|
||||
# If you haven't sourced the script yet, do it now:
|
||||
source scripts/load-db-password.sh
|
||||
|
||||
# Build and start services
|
||||
docker compose -f docker-compose.prod.yml up -d --build
|
||||
|
||||
# Check logs (press Ctrl+C to exit)
|
||||
docker compose -f docker-compose.prod.yml logs -f
|
||||
```
|
||||
|
||||
**What happens when you start:**
|
||||
|
||||
1. **MySQL container starts first** (`lottery-mysql`)
|
||||
- Creates the database `lottery_db` automatically (if it doesn't exist)
|
||||
- Sets up the root user with your password from `DB_PASSWORD`
|
||||
- Waits until healthy before backend starts
|
||||
|
||||
2. **Backend container starts** (`lottery-backend`)
|
||||
- Loads configuration from `/run/secrets/lottery-config.properties`
|
||||
- Connects to MySQL using credentials from secret file
|
||||
- Runs Flyway migrations to create all database tables
|
||||
- Starts the Spring Boot application
|
||||
|
||||
**Wait for the database to be ready and migrations to complete.** You should see:
|
||||
- `lottery-mysql` container running
|
||||
- `lottery-backend` container running
|
||||
- Log message: "📁 Loading configuration from mounted secret file: /run/secrets/lottery-config.properties"
|
||||
- Database migration messages (Flyway creating tables)
|
||||
- No errors in logs
|
||||
|
||||
**Verify everything is working:**
|
||||
|
||||
```bash
|
||||
# Check that both containers are running
|
||||
docker ps | grep lottery
|
||||
|
||||
# Check backend logs for secret file loading
|
||||
docker compose -f docker-compose.prod.yml logs backend | grep "Loading configuration"
|
||||
|
||||
# Check backend logs for database connection
|
||||
docker compose -f docker-compose.prod.yml logs backend | grep -i "database\|mysql\|flyway"
|
||||
|
||||
# Check for any errors
|
||||
docker compose -f docker-compose.prod.yml logs backend | grep -i error
|
||||
```
|
||||
|
||||
You should see:
|
||||
- `📁 Loading configuration from mounted secret file: /run/secrets/lottery-config.properties`
|
||||
- `Flyway migration` messages showing tables being created
|
||||
- No connection errors
|
||||
|
||||
**If you see connection errors:**
|
||||
- Verify `SPRING_DATASOURCE_PASSWORD` in secret file matches `DB_PASSWORD` environment variable
|
||||
- Re-run the password loading script: `source scripts/load-db-password.sh`
|
||||
- Check that MySQL container is healthy: `docker ps | grep mysql`
|
||||
- Check MySQL logs: `docker compose -f docker-compose.prod.yml logs db`
|
||||
|
||||
## Step 4: Build and Deploy Frontend
|
||||
|
||||
### 4.1 Build Frontend Locally (Recommended)
|
||||
|
||||
On your local machine:
|
||||
|
||||
```bash
|
||||
cd lottery-fe
|
||||
|
||||
# Build for production (uses relative API URLs by default)
|
||||
npm install
|
||||
npm run build
|
||||
|
||||
# The dist/ folder will be created
|
||||
```
|
||||
|
||||
### 4.2 Copy Frontend Build to VPS
|
||||
|
||||
```bash
|
||||
# On your local machine
|
||||
scp -r lottery-fe/dist/* user@your-vps-ip:/opt/app/frontend/dist/
|
||||
|
||||
# Or use rsync
|
||||
rsync -avz lottery-fe/dist/ user@your-vps-ip:/opt/app/frontend/dist/
|
||||
```
|
||||
|
||||
### 4.3 Alternative: Build on VPS
|
||||
|
||||
If you prefer to build on the VPS:
|
||||
|
||||
```bash
|
||||
# Install Node.js on VPS
|
||||
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
|
||||
sudo apt install -y nodejs
|
||||
|
||||
# Copy frontend source
|
||||
scp -r lottery-fe/* user@your-vps-ip:/opt/app/frontend-source/
|
||||
|
||||
# Build
|
||||
cd /opt/app/frontend-source
|
||||
npm install
|
||||
npm run build
|
||||
|
||||
# Copy dist to frontend directory
|
||||
cp -r dist/* /opt/app/frontend/dist/
|
||||
```
|
||||
|
||||
## Step 5: Configure Nginx
|
||||
|
||||
### 5.1 Copy Nginx Configuration
|
||||
|
||||
```bash
|
||||
# Copy the template
|
||||
cp /opt/app/backend/nginx.conf.template /opt/app/nginx/nginx.conf
|
||||
|
||||
# Edit the configuration
|
||||
nano /opt/app/nginx/nginx.conf
|
||||
```
|
||||
|
||||
**Update the following:**
|
||||
1. Replace `server_name _;` with your domain name (e.g., `server_name yourdomain.com;`)
|
||||
2. Update SSL certificate paths if using Let's Encrypt (see Step 6)
|
||||
3. Verify paths match your directory structure
|
||||
|
||||
### 5.2 Link Nginx Configuration
|
||||
|
||||
```bash
|
||||
# Remove default Nginx config
|
||||
sudo rm /etc/nginx/sites-enabled/default
|
||||
|
||||
# Create symlink to your config
|
||||
sudo ln -s /opt/app/nginx/nginx.conf /etc/nginx/sites-available/lottery
|
||||
sudo ln -s /etc/nginx/sites-available/lottery /etc/nginx/sites-enabled/
|
||||
|
||||
# Test Nginx configuration
|
||||
sudo nginx -t
|
||||
|
||||
# If test passes, reload Nginx
|
||||
sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
## Step 6: Setup SSL Certificate (HTTPS)
|
||||
|
||||
### 6.1 Obtain SSL Certificate
|
||||
|
||||
```bash
|
||||
# Stop Nginx temporarily
|
||||
sudo systemctl stop nginx
|
||||
|
||||
# Obtain certificate (replace with your domain and email)
|
||||
sudo certbot certonly --standalone -d yourdomain.com -d www.yourdomain.com --email your-email@example.com --agree-tos
|
||||
|
||||
# Start Nginx
|
||||
sudo systemctl start nginx
|
||||
```
|
||||
|
||||
### 6.2 Update Nginx Config with Certificate Paths
|
||||
|
||||
Edit `/opt/app/nginx/nginx.conf` and update:
|
||||
|
||||
```nginx
|
||||
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
|
||||
```
|
||||
|
||||
### 6.3 Setup Auto-Renewal
|
||||
|
||||
```bash
|
||||
# Test renewal
|
||||
sudo certbot renew --dry-run
|
||||
|
||||
# Certbot will automatically renew certificates
|
||||
```
|
||||
|
||||
## Step 7: Configure Telegram Webhook
|
||||
|
||||
Update your Telegram bot webhook to point to your VPS:
|
||||
|
||||
```bash
|
||||
# Replace with your bot token, domain, and the same webhook token you set in APP_TELEGRAM_WEBHOOK_TOKEN
|
||||
curl -X POST "https://api.telegram.org/bot<YOUR_BOT_TOKEN>/setWebhook" \
|
||||
-d "url=https://yourdomain.com/api/telegram/webhook/<YOUR_WEBHOOK_TOKEN>"
|
||||
```
|
||||
|
||||
Verify webhook:
|
||||
|
||||
```bash
|
||||
curl "https://api.telegram.org/bot<YOUR_BOT_TOKEN>/getWebhookInfo"
|
||||
```
|
||||
|
||||
## Step 8: Final Verification
|
||||
|
||||
### 8.1 Check Services
|
||||
|
||||
```bash
|
||||
# Check Docker containers
|
||||
docker ps
|
||||
|
||||
# Should show:
|
||||
# - lottery-mysql
|
||||
# - lottery-backend
|
||||
|
||||
# Check Nginx
|
||||
sudo systemctl status nginx
|
||||
```
|
||||
|
||||
### 8.2 Test Endpoints
|
||||
|
||||
```bash
|
||||
# Test backend health
|
||||
curl http://localhost:8080/actuator/health
|
||||
|
||||
# Test frontend (should return HTML)
|
||||
curl https://yourdomain.com/
|
||||
|
||||
# Test API (should return JSON or error with auth)
|
||||
curl https://yourdomain.com/api/health
|
||||
```
|
||||
|
||||
### 8.3 Check Logs
|
||||
|
||||
```bash
|
||||
# Backend logs
|
||||
cd /opt/app/backend
|
||||
docker-compose -f docker-compose.prod.yml logs -f
|
||||
|
||||
# Nginx logs
|
||||
sudo tail -f /var/log/nginx/access.log
|
||||
sudo tail -f /var/log/nginx/error.log
|
||||
```
|
||||
|
||||
### 8.4 Browser Testing
|
||||
|
||||
1. Open `https://yourdomain.com` in a browser
|
||||
2. Test the Telegram Mini App
|
||||
3. Verify API calls work (check browser console)
|
||||
4. Test WebSocket connection (game updates)
|
||||
|
||||
## Step 9: Maintenance Commands
|
||||
|
||||
### 9.1 Restart Services
|
||||
|
||||
```bash
|
||||
# Restart backend
|
||||
cd /opt/app/backend
|
||||
docker compose -f docker-compose.prod.yml restart
|
||||
|
||||
# Restart Nginx
|
||||
sudo systemctl restart nginx
|
||||
```
|
||||
|
||||
### 9.2 Update Application
|
||||
|
||||
```bash
|
||||
# Backend update
|
||||
cd /opt/app/backend
|
||||
git pull # or copy new files
|
||||
docker compose -f docker-compose.prod.yml up -d --build
|
||||
|
||||
# Frontend update
|
||||
# Rebuild and copy dist/ folder
|
||||
```
|
||||
|
||||
### 9.3 Backup Database
|
||||
|
||||
```bash
|
||||
# Create backup
|
||||
docker exec lottery-mysql mysqldump -u root -p${DB_PASSWORD} lottery_db > backup_$(date +%Y%m%d).sql
|
||||
|
||||
# Restore backup
|
||||
docker exec -i lottery-mysql mysql -u root -p${DB_PASSWORD} lottery_db < backup_20240101.sql
|
||||
```
|
||||
|
||||
### 9.4 View Logs
|
||||
|
||||
```bash
|
||||
# Backend logs
|
||||
cd /opt/app/backend
|
||||
docker-compose -f docker-compose.prod.yml logs -f backend
|
||||
|
||||
# Database logs
|
||||
docker-compose -f docker-compose.prod.yml logs -f db
|
||||
|
||||
# Nginx logs
|
||||
sudo tail -f /var/log/nginx/error.log
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Backend Not Starting
|
||||
|
||||
```bash
|
||||
# Check logs
|
||||
docker compose -f docker-compose.prod.yml logs backend
|
||||
|
||||
# Common issues:
|
||||
# - Database not ready: wait for health check
|
||||
# - Missing configuration: check secret file at /run/secrets/lottery-config.properties
|
||||
# - Secret file not found: ensure file exists and is mounted correctly
|
||||
# - Port conflict: ensure port 8080 is not exposed to host
|
||||
```
|
||||
|
||||
### Frontend Not Loading
|
||||
|
||||
```bash
|
||||
# Check Nginx error log
|
||||
sudo tail -f /var/log/nginx/error.log
|
||||
|
||||
# Verify files exist
|
||||
ls -la /opt/app/frontend/dist/
|
||||
|
||||
# Check Nginx config
|
||||
sudo nginx -t
|
||||
```
|
||||
|
||||
### Database Connection Issues
|
||||
|
||||
```bash
|
||||
# Check database container
|
||||
docker ps | grep mysql
|
||||
|
||||
# Check database logs
|
||||
docker compose -f docker-compose.prod.yml logs db
|
||||
|
||||
# Test connection
|
||||
docker exec -it lottery-mysql mysql -u root -p
|
||||
```
|
||||
|
||||
### SSL Certificate Issues
|
||||
|
||||
```bash
|
||||
# Check certificate
|
||||
sudo certbot certificates
|
||||
|
||||
# Renew certificate
|
||||
sudo certbot renew
|
||||
|
||||
# Check Nginx SSL config
|
||||
sudo nginx -t
|
||||
```
|
||||
|
||||
### WebSocket Not Working
|
||||
|
||||
```bash
|
||||
# Check backend logs for WebSocket errors
|
||||
docker compose -f docker-compose.prod.yml logs backend | grep -i websocket
|
||||
|
||||
# Verify Nginx WebSocket configuration
|
||||
grep -A 10 "/ws" /opt/app/nginx/nginx.conf
|
||||
```
|
||||
|
||||
## Security Checklist
|
||||
|
||||
- [ ] Strong database passwords set
|
||||
- [ ] Secret file has restricted permissions (`chmod 640`, owned by `root:docker`)
|
||||
- [ ] Secret file contains all required configuration values
|
||||
- [ ] SSL certificate installed and auto-renewal configured
|
||||
- [ ] Firewall configured (UFW recommended)
|
||||
- [ ] Backend port 8080 not exposed to host
|
||||
- [ ] MySQL port 3306 not exposed to host
|
||||
- [ ] Regular backups scheduled
|
||||
- [ ] Logs monitored for suspicious activity
|
||||
|
||||
## Firewall Setup (Optional but Recommended)
|
||||
|
||||
```bash
|
||||
# Install UFW
|
||||
sudo apt install ufw -y
|
||||
|
||||
# Allow SSH (IMPORTANT - do this first!)
|
||||
sudo ufw allow 22/tcp
|
||||
|
||||
# Allow HTTP and HTTPS
|
||||
sudo ufw allow 80/tcp
|
||||
sudo ufw allow 443/tcp
|
||||
|
||||
# Enable firewall
|
||||
sudo ufw enable
|
||||
|
||||
# Check status
|
||||
sudo ufw status
|
||||
```
|
||||
|
||||
## Directory Structure Summary
|
||||
|
||||
```
|
||||
/opt/app/
|
||||
├── backend/
|
||||
│ ├── Dockerfile
|
||||
│ ├── docker-compose.prod.yml
|
||||
│ ├── lottery-config.properties.template
|
||||
│ ├── pom.xml
|
||||
│ └── src/
|
||||
├── frontend/
|
||||
│ └── dist/ (Vite production build)
|
||||
├── nginx/
|
||||
│ └── nginx.conf
|
||||
├── data/
|
||||
│ └── avatars/ (persistent uploads)
|
||||
└── mysql/
|
||||
└── data/ (persistent DB storage)
|
||||
|
||||
/run/secrets/
|
||||
└── lottery-config.properties (mounted secret configuration file)
|
||||
```
|
||||
|
||||
## Support
|
||||
|
||||
If you encounter issues:
|
||||
1. Check logs first (backend, Nginx, Docker)
|
||||
2. Verify secret file exists at `/run/secrets/lottery-config.properties` and has correct values
|
||||
3. Verify secret file permissions (`chmod 640`, owned by `root:docker`)
|
||||
4. Check backend logs for "Loading configuration from mounted secret file" message
|
||||
5. Ensure all directories exist and have proper permissions
|
||||
6. Verify network connectivity between containers
|
||||
7. Check SSL certificate validity
|
||||
|
||||
---
|
||||
|
||||
**Last Updated:** 2026-01-24
|
||||
**Version:** 1.0
|
||||
|
||||
Reference in New Issue
Block a user