From 1a94121d1468ae1b634db94e0e49a55a6c137698 Mon Sep 17 00:00:00 2001 From: Alexander Borg Date: Fri, 12 Sep 2025 21:39:21 +0200 Subject: [PATCH] Fix jwt-token --- ssl/certbot-manager.sh | 12 ++ ssl/complete-setup.sh | 259 +++++++++++++++++++++++++++++ ssl/nginx-ssl-setup.sh | 360 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 631 insertions(+) create mode 100644 ssl/complete-setup.sh create mode 100644 ssl/nginx-ssl-setup.sh diff --git a/ssl/certbot-manager.sh b/ssl/certbot-manager.sh index 7f70780..983764f 100644 --- a/ssl/certbot-manager.sh +++ b/ssl/certbot-manager.sh @@ -145,6 +145,18 @@ reload_nginx() { if nginx -t; then systemctl reload nginx || service nginx reload || nginx -s reload log "Nginx reloaded successfully" + + # Auto-configure nginx with SSL if setup script exists + local ssl_setup_script="$(dirname "$0")/nginx-ssl-setup.sh" + if [[ -f "$ssl_setup_script" ]] && [[ ! -f "/etc/nginx/sites-available/$DOMAIN" ]]; then + log "SSL configuration not found - setting up nginx SSL configuration..." + if bash "$ssl_setup_script" setup; then + log "✅ Nginx SSL configuration completed automatically" + else + log "⚠️ Nginx SSL auto-configuration failed - please run manually:" + log " sudo $ssl_setup_script" + fi + fi else log "ERROR: nginx configuration test failed - not reloading" return 1 diff --git a/ssl/complete-setup.sh b/ssl/complete-setup.sh new file mode 100644 index 0000000..d5478be --- /dev/null +++ b/ssl/complete-setup.sh @@ -0,0 +1,259 @@ +#!/bin/bash + +# Complete SSL + Nginx Setup Script +# This script handles the entire SSL certificate and nginx configuration process + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +DOMAIN="${DOMAIN:-dev.uggla.uamils.com}" + +log() { + echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" +} + +show_help() { + echo "Complete SSL + Nginx Setup" + echo "==========================" + echo "" + echo "This script will:" + echo "1. Setup SSL certificate management" + echo "2. Obtain/renew SSL certificates" + echo "3. Configure nginx with SSL" + echo "4. Setup automatic renewal" + echo "" + echo "Usage: $0 [options]" + echo "" + echo "Options:" + echo " --domain DOMAIN Set domain (default: dev.uggla.uamils.com)" + echo " --email EMAIL Set email for Let's Encrypt" + echo " --skip-cert Skip certificate generation" + echo " --skip-nginx Skip nginx configuration" + echo " --help Show this help" + echo "" + echo "Environment variables (or use .env file):" + echo " DOMAIN Domain name" + echo " EMAIL Email for Let's Encrypt" + echo " LOOPIA_USER Loopia username (for DNS challenge)" + echo " LOOPIA_PASSWORD Loopia password (for DNS challenge)" +} + +check_root() { + if [[ $EUID -ne 0 ]]; then + log "ERROR: This script must be run as root (use sudo)" + exit 1 + fi +} + +load_environment() { + if [[ -f "$SCRIPT_DIR/.env" ]]; then + log "Loading environment from .env file..." + source "$SCRIPT_DIR/.env" + fi +} + +setup_ssl_management() { + log "Setting up SSL certificate management..." + + # Run the setup script + if [[ -f "$SCRIPT_DIR/setup.sh" ]]; then + bash "$SCRIPT_DIR/setup.sh" + else + log "ERROR: setup.sh not found" + exit 1 + fi +} + +obtain_certificates() { + log "Obtaining SSL certificates for $DOMAIN..." + + if [[ -f "$SCRIPT_DIR/certbot-manager.sh" ]]; then + bash "$SCRIPT_DIR/certbot-manager.sh" renew + else + log "ERROR: certbot-manager.sh not found" + exit 1 + fi +} + +configure_nginx() { + log "Configuring nginx with SSL..." + + if [[ -f "$SCRIPT_DIR/nginx-ssl-setup.sh" ]]; then + DOMAIN="$DOMAIN" bash "$SCRIPT_DIR/nginx-ssl-setup.sh" setup + else + log "ERROR: nginx-ssl-setup.sh not found" + exit 1 + fi +} + +setup_auto_renewal() { + log "Setting up automatic certificate renewal..." + + # Option 1: Try systemd timer (preferred) + if command -v systemctl >/dev/null 2>&1; then + log "Setting up systemd timer for automatic renewal..." + + # Copy service files + cp "$SCRIPT_DIR/ssl-renewal.service" /etc/systemd/system/ + cp "$SCRIPT_DIR/ssl-renewal.timer" /etc/systemd/system/ + + # Update paths in service file + sed -i "s|/path/to/your/project/ssl|$SCRIPT_DIR|g" /etc/systemd/system/ssl-renewal.service + + # Enable and start timer + systemctl daemon-reload + systemctl enable ssl-renewal.timer + systemctl start ssl-renewal.timer + + log "✅ Systemd timer configured" + systemctl status ssl-renewal.timer --no-pager + else + # Option 2: Fallback to cron + log "Setting up cron job for automatic renewal..." + + # Add cron job + (crontab -l 2>/dev/null || true; echo "0 2 * * * cd $SCRIPT_DIR && source .env && ./certbot-manager.sh auto >> /var/log/letsencrypt/cron.log 2>&1") | crontab - + + log "✅ Cron job added" + fi +} + +verify_setup() { + log "Verifying SSL setup..." + + # Check if certificates exist + if [[ -f "/etc/letsencrypt/live/$DOMAIN/fullchain.pem" ]]; then + log "✅ SSL certificates found" + + # Show certificate info + bash "$SCRIPT_DIR/certbot-manager.sh" status + else + log "❌ SSL certificates not found" + exit 1 + fi + + # Check nginx configuration + if nginx -t >/dev/null 2>&1; then + log "✅ Nginx configuration is valid" + else + log "❌ Nginx configuration has errors" + exit 1 + fi + + # Check if site is accessible + log "Testing HTTPS connectivity..." + if curl -k -s "https://$DOMAIN/health" >/dev/null 2>&1; then + log "✅ HTTPS site is accessible" + else + log "⚠️ HTTPS site test failed (this may be normal if backend is not running)" + fi +} + +show_completion_summary() { + echo "" + echo "🎉 SSL + Nginx Setup Complete!" + echo "===============================" + echo "" + echo "🌐 Your site is now available at:" + echo " https://$DOMAIN" + echo "" + echo "🔐 Multi-tenant subdomains work too:" + echo " https://tenant1.$DOMAIN" + echo " https://any-name.$DOMAIN" + echo "" + echo "🔄 Automatic renewal is configured:" + if systemctl is-enabled ssl-renewal.timer >/dev/null 2>&1; then + echo " ✅ Systemd timer: systemctl status ssl-renewal.timer" + else + echo " ✅ Cron job: crontab -l" + fi + echo "" + echo "📊 Check status anytime:" + echo " cd $SCRIPT_DIR" + echo " ./certbot-manager.sh status" + echo "" + echo "🔧 Configuration files:" + echo " SSL: /etc/nginx/sites-available/$DOMAIN" + echo " Certs: /etc/letsencrypt/live/$DOMAIN/" + echo "" + echo "🚀 Next: Start your Docker containers:" + echo " cd .. && docker-compose up -d" + echo "===============================" +} + +# Parse command line arguments +SKIP_CERT=false +SKIP_NGINX=false + +while [[ $# -gt 0 ]]; do + case $1 in + --domain) + DOMAIN="$2" + shift 2 + ;; + --email) + EMAIL="$2" + shift 2 + ;; + --skip-cert) + SKIP_CERT=true + shift + ;; + --skip-nginx) + SKIP_NGINX=true + shift + ;; + --help) + show_help + exit 0 + ;; + *) + log "Unknown option: $1" + show_help + exit 1 + ;; + esac +done + +# Main execution +main() { + log "Starting complete SSL + Nginx setup for $DOMAIN" + + check_root + load_environment + + # Validate required variables + if [[ -z "$DOMAIN" ]]; then + log "ERROR: DOMAIN not set" + exit 1 + fi + + # Step 1: Setup SSL management + setup_ssl_management + + # Step 2: Obtain certificates (unless skipped) + if [[ "$SKIP_CERT" != "true" ]]; then + obtain_certificates + else + log "Skipping certificate generation" + fi + + # Step 3: Configure nginx (unless skipped) + if [[ "$SKIP_NGINX" != "true" ]]; then + configure_nginx + else + log "Skipping nginx configuration" + fi + + # Step 4: Setup auto-renewal + setup_auto_renewal + + # Step 5: Verify everything works + verify_setup + + # Step 6: Show completion summary + show_completion_summary +} + +# Run main function +main "$@" diff --git a/ssl/nginx-ssl-setup.sh b/ssl/nginx-ssl-setup.sh new file mode 100644 index 0000000..6b4e9e3 --- /dev/null +++ b/ssl/nginx-ssl-setup.sh @@ -0,0 +1,360 @@ +#!/bin/bash + +# Nginx SSL Configuration Script +# Automatically configures nginx with SSL certificates for dev.uggla.uamils.com + +set -e + +# Configuration +DOMAIN="${DOMAIN:-dev.uggla.uamils.com}" +CERT_PATH="/etc/letsencrypt/live/$DOMAIN" +SITES_AVAILABLE="/etc/nginx/sites-available" +SITES_ENABLED="/etc/nginx/sites-enabled" +CONFIG_NAME="$DOMAIN" + +# Backend and frontend ports (from docker-compose) +BACKEND_PORT="${BACKEND_PORT:-3002}" +FRONTEND_PORT="${FRONTEND_PORT:-3001}" + +log() { + echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" +} + +check_prerequisites() { + log "Checking prerequisites..." + + # Check if running as root + if [[ $EUID -ne 0 ]]; then + log "ERROR: This script must be run as root (use sudo)" + exit 1 + fi + + # Check if nginx is installed + if ! command -v nginx >/dev/null 2>&1; then + log "ERROR: Nginx is not installed. Install with: sudo apt install nginx" + exit 1 + fi + + # Check if certificates exist + if [[ ! -f "$CERT_PATH/fullchain.pem" || ! -f "$CERT_PATH/privkey.pem" ]]; then + log "ERROR: SSL certificates not found at $CERT_PATH" + log "Please run SSL certificate generation first:" + log " cd ssl && ./certbot-manager.sh renew" + exit 1 + fi + + log "Prerequisites check passed" +} + +create_nginx_config() { + log "Creating nginx configuration for $DOMAIN..." + + cat > "$SITES_AVAILABLE/$CONFIG_NAME" << EOF +# Nginx configuration for $DOMAIN +# Multi-tenant drone detection system with SSL + +# HTTP to HTTPS redirect +server { + listen 80; + server_name $DOMAIN *.$DOMAIN; + + # ACME challenge location for Let's Encrypt + location /.well-known/acme-challenge/ { + root /var/www/html; + try_files \$uri =404; + } + + # Redirect all other traffic to HTTPS + location / { + return 301 https://\$server_name\$request_uri; + } +} + +# HTTPS server for main domain +server { + listen 443 ssl http2; + server_name $DOMAIN; + + # SSL Configuration + ssl_certificate $CERT_PATH/fullchain.pem; + ssl_certificate_key $CERT_PATH/privkey.pem; + + # SSL Security Settings + 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:ECDHE-RSA-AES256-SHA384; + ssl_prefer_server_ciphers off; + ssl_session_cache shared:SSL:10m; + ssl_session_timeout 10m; + ssl_stapling on; + ssl_stapling_verify on; + + # Security Headers + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + add_header X-Frame-Options DENY 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; + + # Root location - serve frontend + location / { + proxy_pass http://127.0.0.1:$FRONTEND_PORT; + 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; + + # Timeouts + proxy_connect_timeout 30s; + proxy_send_timeout 30s; + proxy_read_timeout 30s; + } + + # API routes - proxy to backend + location /api/ { + proxy_pass http://127.0.0.1:$BACKEND_PORT; + 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; + + # Timeouts + proxy_connect_timeout 30s; + proxy_send_timeout 30s; + proxy_read_timeout 30s; + } + + # Health check endpoint + location /health { + proxy_pass http://127.0.0.1:$BACKEND_PORT; + 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; + } + + # WebSocket support for real-time features + location /ws { + proxy_pass http://127.0.0.1:$BACKEND_PORT; + 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; + } + + # Static files (if served directly by nginx) + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)\$ { + proxy_pass http://127.0.0.1:$FRONTEND_PORT; + expires 1y; + add_header Cache-Control "public, immutable"; + } +} + +# HTTPS server for wildcard subdomains (multi-tenant) +server { + listen 443 ssl http2; + server_name *.$DOMAIN; + + # SSL Configuration (same certificates work for wildcard) + ssl_certificate $CERT_PATH/fullchain.pem; + ssl_certificate_key $CERT_PATH/privkey.pem; + + # SSL Security Settings (same as main domain) + 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:ECDHE-RSA-AES256-SHA384; + ssl_prefer_server_ciphers off; + ssl_session_cache shared:SSL:10m; + ssl_session_timeout 10m; + ssl_stapling on; + ssl_stapling_verify on; + + # Security Headers + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + add_header X-Frame-Options DENY 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; + + # Multi-tenant routing - pass subdomain to backend + location / { + proxy_pass http://127.0.0.1:$FRONTEND_PORT; + 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_set_header X-Tenant-Domain \$host; + proxy_cache_bypass \$http_upgrade; + + # Timeouts + proxy_connect_timeout 30s; + proxy_send_timeout 30s; + proxy_read_timeout 30s; + } + + # API routes for multi-tenant + location /api/ { + proxy_pass http://127.0.0.1:$BACKEND_PORT; + 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_set_header X-Tenant-Domain \$host; + proxy_cache_bypass \$http_upgrade; + + # Timeouts + proxy_connect_timeout 30s; + proxy_send_timeout 30s; + proxy_read_timeout 30s; + } + + # Health check for subdomains + location /health { + proxy_pass http://127.0.0.1:$BACKEND_PORT; + 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_set_header X-Tenant-Domain \$host; + } + + # WebSocket support for multi-tenant + location /ws { + proxy_pass http://127.0.0.1:$BACKEND_PORT; + 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_set_header X-Tenant-Domain \$host; + } +} +EOF + + log "Nginx configuration created at $SITES_AVAILABLE/$CONFIG_NAME" +} + +enable_site() { + log "Enabling nginx site..." + + # Remove default site if it exists + if [[ -f "$SITES_ENABLED/default" ]]; then + log "Removing default nginx site" + rm -f "$SITES_ENABLED/default" + fi + + # Enable our site + ln -sf "$SITES_AVAILABLE/$CONFIG_NAME" "$SITES_ENABLED/" + log "Site enabled" +} + +test_and_reload() { + log "Testing nginx configuration..." + + if nginx -t; then + log "✅ Nginx configuration is valid" + + log "Reloading nginx..." + systemctl reload nginx + log "✅ Nginx reloaded successfully" + else + log "❌ Nginx configuration has errors" + log "Configuration file: $SITES_AVAILABLE/$CONFIG_NAME" + exit 1 + fi +} + +show_results() { + log "SSL Configuration Complete! 🎉" + echo "" + echo "======================================" + echo "Nginx SSL Configuration Summary" + echo "======================================" + echo "" + echo "🌐 Your site is now available at:" + echo " https://$DOMAIN" + echo "" + echo "🔐 Multi-tenant subdomains:" + echo " https://tenant1.$DOMAIN" + echo " https://tenant2.$DOMAIN" + echo " https://any-name.$DOMAIN" + echo "" + echo "🔗 API endpoints:" + echo " https://$DOMAIN/api/health" + echo " https://$DOMAIN/api/" + echo "" + echo "🔒 SSL Features enabled:" + echo " ✅ HTTP to HTTPS redirect" + echo " ✅ SSL/TLS encryption" + echo " ✅ Security headers" + echo " ✅ Wildcard certificate support" + echo " ✅ Multi-tenant routing" + echo "" + echo "📝 Configuration file:" + echo " $SITES_AVAILABLE/$CONFIG_NAME" + echo "" + echo "🔄 Auto-renewal:" + echo " SSL certificates will auto-renew via cron/systemd" + echo "======================================" +} + +# Main execution +main() { + log "Starting Nginx SSL configuration for $DOMAIN" + + check_prerequisites + create_nginx_config + enable_site + test_and_reload + show_results +} + +# Handle command line arguments +case "${1:-setup}" in + "setup"|"configure") + main + ;; + "test") + nginx -t + ;; + "reload") + systemctl reload nginx + ;; + "status") + systemctl status nginx + ;; + *) + echo "Nginx SSL Configuration Script" + echo "=============================" + echo "" + echo "Usage: $0 [command]" + echo "" + echo "Commands:" + echo " setup Setup SSL configuration (default)" + echo " test Test nginx configuration" + echo " reload Reload nginx" + echo " status Show nginx status" + echo "" + echo "Environment variables:" + echo " DOMAIN Domain name (default: dev.uggla.uamils.com)" + echo " BACKEND_PORT Backend port (default: 3002)" + echo " FRONTEND_PORT Frontend port (default: 3001)" + ;; +esac