Add Docker deployment with SSL/Certbot support

This commit is contained in:
hex
2025-05-19 21:31:36 -07:00
parent bd976a6deb
commit 79bbf99b94
6 changed files with 259 additions and 0 deletions

13
.dockerignore Normal file
View File

@@ -0,0 +1,13 @@
.git
.gitignore
venv/
__pycache__/
*.pyc
*.pyo
*.pyd
instance/
.env
README.md
.dockerignore
Dockerfile
docker-compose.yml

18
Dockerfile Normal file
View File

@@ -0,0 +1,18 @@
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
RUN pip install gunicorn
COPY . .
ENV FLASK_APP=run.py
ENV FLASK_ENV=production
ENV PYTHONUNBUFFERED=1
EXPOSE 8000
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "run:app", "--workers=2", "--access-logfile=-"]

76
deploy.sh Executable file
View File

@@ -0,0 +1,76 @@
#!/bin/bash
# Game Tracker Deployment Script
echo "=== Game Tracker Deployment ==="
# Default settings
DEPLOY_MODE=${DEPLOY_MODE:-local}
# Check if .env file exists
if [ ! -f .env ]; then
echo "ERROR: .env file not found!"
echo "Please create a .env file with your IGDB credentials:"
echo "IGDB_CLIENT_ID=your_client_id_here"
echo "IGDB_CLIENT_SECRET=your_client_secret_here"
exit 1
fi
# Make sure database directory exists
mkdir -p instance
# Check deployment mode
if [ "$1" = "--ssl" ] || [ "$DEPLOY_MODE" = "ssl" ]; then
echo "Deploying with SSL (for production use)..."
# Check for domain name
if [ -z "$DOMAIN" ]; then
read -p "Enter your domain name (e.g., gametracker.example.com): " DOMAIN
export DOMAIN
fi
# Check for email
if [ -z "$EMAIL" ]; then
read -p "Enter your email (for Let's Encrypt notifications): " EMAIL
export EMAIL
fi
# Run the SSL setup script
./init-letsencrypt.sh
echo "=== SSL Deployment Complete ==="
echo "Your Game Tracker is now running at: https://$DOMAIN"
echo ""
echo "SSL certificates will auto-renew every 90 days"
echo "To view logs: docker-compose logs -f"
echo "To stop the server: docker-compose down"
else
echo "Deploying locally (for development/testing)..."
# Create a simpler nginx config for local deployment
mkdir -p nginx
cat > nginx/app.conf << EOF
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://web:8000;
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
}
}
EOF
# Build and start Docker containers
echo "Building and starting Docker containers..."
docker-compose up --build -d
echo "=== Local Deployment Complete ==="
echo "Your Game Tracker is now running at: http://localhost"
echo ""
echo "To view logs: docker-compose logs -f"
echo "To stop the server: docker-compose down"
echo "To deploy with SSL: ./deploy.sh --ssl"
fi

44
docker-compose.yml Normal file
View File

@@ -0,0 +1,44 @@
version: '3'
services:
web:
build: .
expose:
- "8000"
volumes:
- ./instance:/app/instance
env_file:
- .env
restart: unless-stopped
networks:
- app-network
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/app.conf:/etc/nginx/conf.d/default.conf
- ./data/certbot/conf:/etc/letsencrypt
- ./data/certbot/www:/var/www/certbot
depends_on:
- web
restart: unless-stopped
networks:
- app-network
command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'"
certbot:
image: certbot/certbot
volumes:
- ./data/certbot/conf:/etc/letsencrypt
- ./data/certbot/www:/var/www/certbot
restart: unless-stopped
entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"
networks:
- app-network
networks:
app-network:
driver: bridge

77
init-letsencrypt.sh Executable file
View File

@@ -0,0 +1,77 @@
#!/bin/bash
# Initialize Let's Encrypt SSL certificates with Certbot
if ! [ -x "$(command -v docker-compose)" ]; then
echo 'Error: docker-compose is not installed.' >&2
exit 1
fi
# Default domain and email settings
domains=${DOMAIN:-}
email=${EMAIL:-}
staging=${STAGING:-0} # Set to 1 if you're testing your setup
# Ask for domain if not provided
if [ -z "$domains" ]; then
read -p "Enter your domain name (e.g., gametracker.example.com): " domains
fi
# Ask for email if not provided
if [ -z "$email" ]; then
read -p "Enter your email (for Let's Encrypt notifications): " email
fi
# Create required directories
mkdir -p ./data/certbot/conf
mkdir -p ./data/certbot/www
# Generate Nginx config using template
export DOMAIN_NAME=$domains
envsubst < ./nginx/app.conf.template > ./nginx/app.conf
# Stop any existing services
docker-compose down
echo "### Starting Nginx..."
docker-compose up --force-recreate -d nginx
echo
echo "### Deleting any existing certificates for domain..."
if [ -d "./data/certbot/conf/live/$domains" ]; then
docker-compose run --rm --entrypoint "\
rm -rf /etc/letsencrypt/live/$domains && \
rm -rf /etc/letsencrypt/archive/$domains && \
rm -rf /etc/letsencrypt/renewal/$domains.conf" certbot
fi
echo
echo "### Requesting Let's Encrypt certificate..."
staging_arg=""
if [ "$staging" = 1 ]; then
staging_arg="--staging"
fi
# Get certificates
domain_args="-d $domains"
docker-compose run --rm --entrypoint "\
certbot certonly --webroot -w /var/www/certbot \
$staging_arg \
--email $email \
--agree-tos \
--no-eff-email \
$domain_args" certbot
echo
echo "### Reloading nginx..."
docker-compose exec nginx nginx -s reload
# Start all services
docker-compose up -d
echo "
HTTPS setup completed!
Your app is now available at: https://$domains
The certificates will auto-renew, but make sure to keep the containers running.
"

31
nginx/app.conf.template Normal file
View File

@@ -0,0 +1,31 @@
server {
listen 80;
server_name ${DOMAIN_NAME};
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
server_name ${DOMAIN_NAME};
ssl_certificate /etc/letsencrypt/live/${DOMAIN_NAME}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/${DOMAIN_NAME}/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
location / {
proxy_pass http://web:8000;
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;
}
}