From 83d6bcb9053473828869f9c229fc55700dbdbe3e Mon Sep 17 00:00:00 2001 From: hex Date: Mon, 19 May 2025 21:53:30 -0700 Subject: [PATCH] Improve deployment scripts with better error handling and SSL setup --- deploy.sh | 103 +++++++++++++++++++++++++++-------- init-letsencrypt.sh | 127 ++++++++++++++++++++++++++++++++++++-------- 2 files changed, 184 insertions(+), 46 deletions(-) diff --git a/deploy.sh b/deploy.sh index 8f2809b..21f8d9d 100755 --- a/deploy.sh +++ b/deploy.sh @@ -1,27 +1,61 @@ #!/bin/bash -# Game Tracker Deployment Script +# Game Tracker Deployment Script with improved error handling -echo "=== Game Tracker Deployment ===" +set -e # Exit on error + +# Bold text function +bold() { + echo -e "\033[1m$1\033[0m" +} + +# Print section header +header() { + echo + bold "=== $1 ===" +} + +# Print error message and exit +error() { + echo -e "\033[31mERROR: $1\033[0m" >&2 + exit 1 +} + +# Check if a command exists +command_exists() { + command -v "$1" >/dev/null 2>&1 +} + +header "Game Tracker Deployment" + +# Check requirements +echo "Checking requirements..." + +if ! command_exists docker; then + error "Docker is not installed. Please install Docker first." +fi + +if ! command_exists docker-compose; then + error "Docker Compose is not installed. Please install Docker Compose first." +fi # Default settings DEPLOY_MODE=${DEPLOY_MODE:-local} # Check if .env file exists +echo "Checking environment..." 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 + error "'.env' file not found! Please create a .env file with your IGDB credentials:\nIGDB_CLIENT_ID=your_client_id_here\nIGDB_CLIENT_SECRET=your_client_secret_here" fi -# Make sure database directory exists +# Make sure necessary directories exist +echo "Creating required directories..." mkdir -p instance +mkdir -p nginx # Check deployment mode if [ "$1" = "--ssl" ] || [ "$DEPLOY_MODE" = "ssl" ]; then - echo "Deploying with SSL (for production use)..." + header "SSL Deployment (Production Mode)" # Check for domain name if [ -z "$DOMAIN" ]; then @@ -35,10 +69,25 @@ if [ "$1" = "--ssl" ] || [ "$DEPLOY_MODE" = "ssl" ]; then export EMAIL fi + # Verify domain + echo "Verifying domain '$DOMAIN' is properly configured..." + host_ip=$(dig +short "$DOMAIN" 2>/dev/null || echo "") + + if [ -z "$host_ip" ]; then + echo "WARNING: Could not resolve domain '$DOMAIN'. DNS might not be configured correctly." + read -p "Continue anyway? (y/n): " answer + if [[ "$answer" != [Yy]* ]]; then + error "Deployment cancelled. Please configure DNS correctly and try again." + fi + else + echo "Domain '$DOMAIN' resolves to IP: $host_ip" + fi + # Run the SSL setup script + echo "Running SSL setup script..." ./init-letsencrypt.sh - echo "=== SSL Deployment Complete ===" + header "SSL Deployment Complete" echo "Your Game Tracker is now running at: https://$DOMAIN" echo "" echo "SSL certificates will auto-renew every 90 days" @@ -46,28 +95,36 @@ if [ "$1" = "--ssl" ] || [ "$DEPLOY_MODE" = "ssl" ]; then echo "To stop the server: docker-compose down" else - echo "Deploying locally (for development/testing)..." + header "Local Deployment (Development Mode)" # Create a simpler nginx config for local deployment - mkdir -p nginx + echo "Generating local nginx configuration..." 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; - } - } +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; + proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto \$scheme; + } +} EOF # Build and start Docker containers echo "Building and starting Docker containers..." + docker-compose down 2>/dev/null || true # Ignore errors if no containers are running docker-compose up --build -d - echo "=== Local Deployment Complete ===" + # Check if containers started successfully + if ! docker-compose ps | grep -q "Up"; then + error "Failed to start containers. Check logs with 'docker-compose logs'." + fi + + header "Local Deployment Complete" echo "Your Game Tracker is now running at: http://localhost" echo "" echo "To view logs: docker-compose logs -f" diff --git a/init-letsencrypt.sh b/init-letsencrypt.sh index 703289b..4f4ee29 100755 --- a/init-letsencrypt.sh +++ b/init-letsencrypt.sh @@ -1,6 +1,23 @@ #!/bin/bash # Initialize Let's Encrypt SSL certificates with Certbot +# This improved version handles the chicken-and-egg problem with SSL files + +set -e + +# Bold text function +bold() { + echo -e "\033[1m$1\033[0m" +} + +# Print section header +header() { + echo + bold "=== $1 ===" +} + +# Check requirements +header "Checking requirements" if ! [ -x "$(command -v docker-compose)" ]; then echo 'Error: docker-compose is not installed.' >&2 @@ -22,56 +39,120 @@ if [ -z "$email" ]; then read -p "Enter your email (for Let's Encrypt notifications): " email fi +header "Setting up SSL for domain: $domains" + # Create required directories mkdir -p ./data/certbot/conf mkdir -p ./data/certbot/www +mkdir -p ./nginx + +# Create dummy certificates to bootstrap nginx +echo "Creating dummy certificates..." + +rsa_key_size=4096 +dummy_cert_path="./data/certbot/conf/live/$domains" + +# Make sure the directory is empty and exists +rm -rf "$dummy_cert_path" +mkdir -p "$dummy_cert_path" + +# Generate dummy certificates +openssl req -x509 -nodes -newkey rsa:$rsa_key_size -days 1 \ + -keyout "$dummy_cert_path/privkey.pem" \ + -out "$dummy_cert_path/fullchain.pem" \ + -subj "/CN=localhost" + +# Create required files for Nginx +echo "Creating required SSL configurations..." + +# Create options-ssl-nginx.conf +cat > ./data/certbot/conf/options-ssl-nginx.conf << EOF +ssl_protocols TLSv1.2 TLSv1.3; +ssl_prefer_server_ciphers on; +ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; +ssl_session_timeout 1d; +ssl_session_cache shared:SSL:10m; +ssl_session_tickets off; +ssl_stapling on; +ssl_stapling_verify on; +EOF + +# Create ssl-dhparams.pem +cat > ./data/certbot/conf/ssl-dhparams.pem << EOF +-----BEGIN DH PARAMETERS----- +MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz ++8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a +87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7 +YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi +7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD +ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg== +-----END DH PARAMETERS----- +EOF # Generate Nginx config using template +header "Configuring Nginx" +echo "Generating Nginx configuration..." + export DOMAIN_NAME=$domains envsubst < ./nginx/app.conf.template > ./nginx/app.conf # Stop any existing services +echo "Stopping any existing services..." docker-compose down -echo "### Starting Nginx..." -docker-compose up --force-recreate -d nginx -echo +header "Starting services with dummy certificates" -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 +# Start services with dummy certificates +echo "Starting Nginx and web containers..." +docker-compose up --force-recreate -d + +# Give Nginx time to start +echo "Waiting for Nginx to start..." +sleep 5 + +# Check if Nginx is running +docker-compose ps nginx | grep Up +if [ $? -ne 0 ]; then + echo "Nginx failed to start! Checking logs:" + docker-compose logs nginx + exit 1 fi -echo -echo "### Requesting Let's Encrypt certificate..." +header "Obtaining real certificates from Let's Encrypt" + +# Prepare staging argument for Certbot staging_arg="" if [ "$staging" = 1 ]; then staging_arg="--staging" + echo "Running in staging mode (test certificates)" fi -# Get certificates +# Get real certificates domain_args="-d $domains" +echo "Requesting certificates for: $domains" + docker-compose run --rm --entrypoint "\ certbot certonly --webroot -w /var/www/certbot \ $staging_arg \ --email $email \ --agree-tos \ --no-eff-email \ + --force-renewal \ $domain_args" certbot -echo -echo "### Reloading nginx..." +# Check if certificates were obtained successfully +if [ ! -d "./data/certbot/conf/live/$domains" ]; then + echo "Certificate issuance failed! Check logs above." + exit 1 +fi + +# Reload Nginx to use the new certificates +echo "Reloading Nginx to use new certificates..." 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. -" +header "HTTPS Setup Completed Successfully!" +echo "Your app is now available at: https://$domains" +echo "" +echo "The certificates will auto-renew every 90 days." +echo "To view logs: docker-compose logs -f" +echo "To stop the server: docker-compose down"