From bd375b52a1283ddd20b2741d3a175c8de1a4f35d Mon Sep 17 00:00:00 2001 From: Alexander Borg Date: Sun, 17 Aug 2025 05:49:39 +0200 Subject: [PATCH] Fix jwt-token --- client/Dockerfile | 2 + client/vite.config.js | 1 + docker-compose.simple.yml | 1 + docker-compose.yml | 1 + nginx/drones.cqers.com | 186 +++++++++++++ nginx/selfservice-with-drones.cqers.com | 334 ++++++++++++++++++++++++ scripts/setup-nginx.sh | 71 +++++ scripts/troubleshoot.sh | 104 ++++++++ 8 files changed, 700 insertions(+) create mode 100644 nginx/drones.cqers.com create mode 100644 nginx/selfservice-with-drones.cqers.com create mode 100644 scripts/setup-nginx.sh create mode 100644 scripts/troubleshoot.sh diff --git a/client/Dockerfile b/client/Dockerfile index c673077..8901379 100644 --- a/client/Dockerfile +++ b/client/Dockerfile @@ -19,10 +19,12 @@ COPY . . # Build arguments for environment variables ARG VITE_API_URL=http://localhost:3001/api ARG VITE_WS_URL=ws://localhost:3001 +ARG NODE_ENV=production # Set environment variables for build ENV VITE_API_URL=$VITE_API_URL ENV VITE_WS_URL=$VITE_WS_URL +ENV NODE_ENV=$NODE_ENV # Build the application RUN npm run build diff --git a/client/vite.config.js b/client/vite.config.js index 858a438..3630376 100644 --- a/client/vite.config.js +++ b/client/vite.config.js @@ -3,6 +3,7 @@ import react from '@vitejs/plugin-react' export default defineConfig({ plugins: [react()], + base: process.env.NODE_ENV === 'production' ? '/drones/' : '/', server: { port: 3000, proxy: { diff --git a/docker-compose.simple.yml b/docker-compose.simple.yml index 7969bc0..4208f74 100644 --- a/docker-compose.simple.yml +++ b/docker-compose.simple.yml @@ -88,6 +88,7 @@ services: args: VITE_API_URL: http://localhost:3002/api VITE_WS_URL: ws://localhost:3002 + NODE_ENV: production container_name: drone-detection-frontend restart: unless-stopped ports: diff --git a/docker-compose.yml b/docker-compose.yml index 2a79432..d1d6020 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -89,6 +89,7 @@ services: args: VITE_API_URL: http://localhost:3002/api VITE_WS_URL: ws://localhost:3002 + NODE_ENV: production container_name: drone-detection-frontend restart: unless-stopped ports: diff --git a/nginx/drones.cqers.com b/nginx/drones.cqers.com new file mode 100644 index 0000000..9b737cb --- /dev/null +++ b/nginx/drones.cqers.com @@ -0,0 +1,186 @@ +# Nginx configuration to proxy to Docker drone detection application +# Copy this file to /etc/nginx/sites-enabled/ on your server + +upstream drone_frontend { + server localhost:3001; # Frontend container port +} + +upstream drone_backend { + server localhost:3002; # Backend API container port +} + +# HTTP configuration for drone detection system +server { + listen 80; + server_name drones.local drones.cqers.com; # Change to your preferred domain + + # Main application - proxy to React frontend + location / { + proxy_pass http://drone_frontend; + 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-Forwarded-Host $host; + proxy_set_header X-Forwarded-Port $server_port; + + # WebSocket support for real-time updates + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + + # Timeouts + proxy_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + + # Handle large payloads + client_max_body_size 10M; + } + + # API routing - proxy to Node.js backend + location /api/ { + proxy_pass http://drone_backend; + 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-Forwarded-Host $host; + proxy_set_header X-Forwarded-Port $server_port; + + # API specific headers + proxy_set_header Content-Type application/json; + + # Timeouts for API calls + proxy_connect_timeout 30s; + proxy_send_timeout 30s; + proxy_read_timeout 60s; + + # Handle large API payloads + client_max_body_size 10M; + } + + # Health check endpoint + location /health { + proxy_pass http://drone_backend; + 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 endpoint for real-time updates + location /socket.io/ { + proxy_pass http://drone_backend; + 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 specific headers + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_cache_bypass $http_upgrade; + + # Longer timeouts for persistent connections + proxy_connect_timeout 60s; + proxy_send_timeout 300s; + proxy_read_timeout 300s; + } + + # Static assets caching (optional optimization) + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { + proxy_pass http://drone_frontend; + proxy_set_header Host $host; + + # Cache static assets + expires 1y; + add_header Cache-Control "public, immutable"; + + # CORS headers for assets + add_header Access-Control-Allow-Origin "*"; + } + + # Security headers + add_header X-Frame-Options "SAMEORIGIN" 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; +} + +# HTTPS configuration (optional - uncomment and configure SSL) +# server { +# listen 443 ssl http2; +# server_name drones.local drones.cqers.com; +# +# # SSL certificate configuration (adjust paths to your certificates) +# ssl_certificate /path/to/your/certificate.crt; +# ssl_certificate_key /path/to/your/private.key; +# +# # 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; +# ssl_prefer_server_ciphers off; +# ssl_session_cache shared:SSL:10m; +# ssl_session_timeout 10m; +# +# # Same location blocks as HTTP configuration above +# location / { +# proxy_pass http://drone_frontend; +# 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-Forwarded-Host $host; +# proxy_set_header X-Forwarded-Port $server_port; +# +# proxy_http_version 1.1; +# proxy_set_header Upgrade $http_upgrade; +# proxy_set_header Connection "upgrade"; +# +# proxy_connect_timeout 60s; +# proxy_send_timeout 60s; +# proxy_read_timeout 60s; +# client_max_body_size 10M; +# } +# +# location /api/ { +# proxy_pass http://drone_backend; +# 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-Forwarded-Host $host; +# proxy_set_header X-Forwarded-Port $server_port; +# +# proxy_connect_timeout 30s; +# proxy_send_timeout 30s; +# proxy_read_timeout 60s; +# client_max_body_size 10M; +# } +# +# location /socket.io/ { +# proxy_pass http://drone_backend; +# 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_http_version 1.1; +# proxy_set_header Upgrade $http_upgrade; +# proxy_set_header Connection "upgrade"; +# proxy_cache_bypass $http_upgrade; +# +# proxy_connect_timeout 60s; +# proxy_send_timeout 300s; +# proxy_read_timeout 300s; +# } +# +# # Security headers for HTTPS +# add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; +# add_header X-Frame-Options "SAMEORIGIN" 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; +# } diff --git a/nginx/selfservice-with-drones.cqers.com b/nginx/selfservice-with-drones.cqers.com new file mode 100644 index 0000000..d0c51b9 --- /dev/null +++ b/nginx/selfservice-with-drones.cqers.com @@ -0,0 +1,334 @@ +# Nginx configuration to proxy to Docker workflow application +# Add this to your main nginx configuration or create a new site configuration + +upstream selfservice_docker { + server localhost:9080; +} + +upstream selfservice_docker_ssl { + server localhost:9443; +} + +# Drone Detection System upstreams +upstream drone_frontend { + server localhost:3001; # Frontend container port +} + +upstream drone_backend { + server localhost:3002; # Backend API container port +} + +# HTTP configuration +server { + listen 80; + server_name selfservice.local selfservice.cqers.com; # Change to your domain + + # Redirect HTTP to HTTPS (optional) + # return 301 https://$server_name$request_uri; + + # Drone Detection System routes + location /drones/ { + proxy_pass http://drone_frontend/; + 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-Forwarded-Host $host; + proxy_set_header X-Forwarded-Port $server_port; + + # WebSocket support for real-time updates + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + + # Timeouts + proxy_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + + # Handle large payloads + client_max_body_size 10M; + } + + # Drone static assets (CSS, JS, images) - handle /drones/assets/ paths + location /drones/assets/ { + proxy_pass http://drone_frontend/assets/; + proxy_set_header Host $host; + + # Cache static assets + expires 1y; + add_header Cache-Control "public, immutable"; + + # CORS headers for assets + add_header Access-Control-Allow-Origin "*"; + } + + # Drone favicon from /drones/ path + location /drones/favicon.ico { + proxy_pass http://drone_frontend/favicon.ico; + proxy_set_header Host $host; + + # Cache favicon + expires 1y; + add_header Cache-Control "public, immutable"; + } + + # Legacy asset routes (in case some assets still use absolute paths) + location /assets/ { + proxy_pass http://drone_frontend/assets/; + proxy_set_header Host $host; + + # Cache static assets + expires 1y; + add_header Cache-Control "public, immutable"; + + # CORS headers for assets + add_header Access-Control-Allow-Origin "*"; + } + + # Legacy favicon route + location /favicon.ico { + proxy_pass http://drone_frontend/favicon.ico; + proxy_set_header Host $host; + + # Cache favicon + expires 1y; + add_header Cache-Control "public, immutable"; + } + + # Drone API routes + location /drones/api/ { + proxy_pass http://drone_backend/api/; + 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-Forwarded-Host $host; + proxy_set_header X-Forwarded-Port $server_port; + + # API specific headers + proxy_set_header Content-Type application/json; + + # Timeouts for API calls + proxy_connect_timeout 30s; + proxy_send_timeout 30s; + proxy_read_timeout 60s; + + # Handle large API payloads + client_max_body_size 10M; + } + + # Drone health check + location /drones/health { + proxy_pass http://drone_backend/health; + 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; + } + + # Drone WebSocket endpoint for real-time updates + location /drones/socket.io/ { + proxy_pass http://drone_backend/socket.io/; + 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 specific headers + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_cache_bypass $http_upgrade; + + # Longer timeouts for persistent connections + proxy_connect_timeout 60s; + proxy_send_timeout 300s; + proxy_read_timeout 300s; + } + + # Original selfservice application - proxy directly to Docker container + location / { + proxy_pass http://selfservice_docker; + 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-Forwarded-Host $host; + proxy_set_header X-Forwarded-Port $server_port; + + # WebSocket support (if needed) + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + + # Timeouts + proxy_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + } + + # API specific routing (optional optimization) for selfservice + location /api/ { + proxy_pass http://selfservice_docker; + 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; + } +} + +# HTTPS configuration (optional) +server { + listen 443 ssl http2; + server_name selfservice.local selfservice.cqers.com; # Change to your domain + + # SSL certificate configuration (adjust paths to your certificates) + # ssl_certificate /path/to/your/certificate.crt; + # ssl_certificate_key /path/to/your/private.key; + + # Drone Detection System routes (HTTPS) + location /drones/ { + proxy_pass http://drone_frontend/; + 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-Forwarded-Host $host; + proxy_set_header X-Forwarded-Port $server_port; + + # WebSocket support for real-time updates + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + + # Timeouts + proxy_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + + # Handle large payloads + client_max_body_size 10M; + } + + # Drone static assets (CSS, JS, images) - handle /drones/assets/ paths (HTTPS) + location /drones/assets/ { + proxy_pass http://drone_frontend/assets/; + proxy_set_header Host $host; + + # Cache static assets + expires 1y; + add_header Cache-Control "public, immutable"; + + # CORS headers for assets + add_header Access-Control-Allow-Origin "*"; + } + + # Drone favicon from /drones/ path (HTTPS) + location /drones/favicon.ico { + proxy_pass http://drone_frontend/favicon.ico; + proxy_set_header Host $host; + + # Cache favicon + expires 1y; + add_header Cache-Control "public, immutable"; + } + + # Legacy asset routes (HTTPS) + location /assets/ { + proxy_pass http://drone_frontend/assets/; + proxy_set_header Host $host; + + # Cache static assets + expires 1y; + add_header Cache-Control "public, immutable"; + + # CORS headers for assets + add_header Access-Control-Allow-Origin "*"; + } + + # Legacy favicon route (HTTPS) + location /favicon.ico { + proxy_pass http://drone_frontend/favicon.ico; + proxy_set_header Host $host; + + # Cache favicon + expires 1y; + add_header Cache-Control "public, immutable"; + } + + # Drone API routes (HTTPS) + location /drones/api/ { + proxy_pass http://drone_backend/api/; + 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-Forwarded-Host $host; + proxy_set_header X-Forwarded-Port $server_port; + + # API specific headers + proxy_set_header Content-Type application/json; + + # Timeouts for API calls + proxy_connect_timeout 30s; + proxy_send_timeout 30s; + proxy_read_timeout 60s; + + # Handle large API payloads + client_max_body_size 10M; + } + + # Drone health check (HTTPS) + location /drones/health { + proxy_pass http://drone_backend/health; + 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; + } + + # Drone WebSocket endpoint (HTTPS) + location /drones/socket.io/ { + proxy_pass http://drone_backend/socket.io/; + 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 specific headers + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_cache_bypass $http_upgrade; + + # Longer timeouts for persistent connections + proxy_connect_timeout 60s; + proxy_send_timeout 300s; + proxy_read_timeout 300s; + } + + # Original selfservice application - proxy to Docker container's HTTPS + location / { + proxy_pass https://selfservice_docker_ssl; + 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-Forwarded-Host $host; + proxy_set_header X-Forwarded-Port $server_port; + + # SSL verification for upstream (adjust as needed) + proxy_ssl_verify off; + + # WebSocket support + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + + # Timeouts + proxy_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + } +} diff --git a/scripts/setup-nginx.sh b/scripts/setup-nginx.sh new file mode 100644 index 0000000..25e219e --- /dev/null +++ b/scripts/setup-nginx.sh @@ -0,0 +1,71 @@ +#!/bin/bash + +# Drone Detection System - Nginx Setup Script +# This script sets up the Nginx configuration for the drone detection system + +set -e + +echo "🚁 Setting up Nginx configuration for Drone Detection System..." + +# Configuration variables +NGINX_CONFIG_FILE="drones.cqers.com" +SITES_AVAILABLE="/etc/nginx/sites-available" +SITES_ENABLED="/etc/nginx/sites-enabled" +DOMAIN="drones.cqers.com" + +# Check if running as root +if [[ $EUID -ne 0 ]]; then + echo "❌ This script must be run as root (use sudo)" + exit 1 +fi + +# Check if nginx is installed +if ! command -v nginx &> /dev/null; then + echo "❌ Nginx is not installed. Please install nginx first:" + echo " sudo apt update && sudo apt install nginx" + exit 1 +fi + +# Copy the configuration file +echo "📋 Copying nginx configuration..." +cp nginx/$NGINX_CONFIG_FILE $SITES_AVAILABLE/ + +# Create symlink to enable the site +echo "🔗 Enabling the site..." +ln -sf $SITES_AVAILABLE/$NGINX_CONFIG_FILE $SITES_ENABLED/ + +# Test nginx configuration +echo "🔍 Testing nginx configuration..." +if nginx -t; then + echo "✅ Nginx configuration is valid" +else + echo "❌ Nginx configuration has errors" + exit 1 +fi + +# Reload nginx +echo "🔄 Reloading nginx..." +systemctl reload nginx + +echo "" +echo "🎉 Nginx configuration setup complete!" +echo "================================================" +echo "Your drone detection system is now available at:" +echo "🌐 HTTP: http://$DOMAIN" +echo "🔒 HTTPS: https://$DOMAIN (if SSL configured)" +echo "" +echo "Local access URLs:" +echo "🌐 HTTP: http://localhost" +echo "📊 API: http://localhost/api" +echo "💚 Health: http://localhost/health" +echo "" +echo "Next steps:" +echo "1. Make sure your Docker containers are running:" +echo " docker-compose up -d" +echo "" +echo "2. Test the endpoints:" +echo " curl http://localhost/health" +echo " curl http://localhost/api/health" +echo "" +echo "3. (Optional) Configure SSL certificates for HTTPS" +echo "================================================" diff --git a/scripts/troubleshoot.sh b/scripts/troubleshoot.sh new file mode 100644 index 0000000..109cf98 --- /dev/null +++ b/scripts/troubleshoot.sh @@ -0,0 +1,104 @@ +#!/bin/bash + +# Drone Detection System - Troubleshooting Script +# This script helps diagnose common issues with the drone detection system + +echo "🔧 Drone Detection System - Troubleshooting" +echo "============================================" + +# Check Docker status +echo "" +echo "📋 Checking Docker containers..." +if command -v docker &> /dev/null; then + docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" + echo "" + + # Check specific containers + echo "🔍 Checking drone detection containers..." + if docker ps | grep -q "drone-detection"; then + echo "✅ Drone detection containers are running" + else + echo "❌ Drone detection containers not found. Run: docker-compose up -d" + fi +else + echo "❌ Docker is not installed or not running" +fi + +# Check port availability +echo "" +echo "🌐 Checking port availability..." +ports=(3001 3002 5433 6380) +for port in "${ports[@]}"; do + if ss -tulpn | grep -q ":$port "; then + echo "✅ Port $port is in use" + else + echo "⚠️ Port $port is not in use" + fi +done + +# Check Nginx status +echo "" +echo "🌍 Checking Nginx status..." +if command -v nginx &> /dev/null; then + if systemctl is-active --quiet nginx; then + echo "✅ Nginx is running" + else + echo "❌ Nginx is not running. Start with: sudo systemctl start nginx" + fi + + # Check nginx configuration + if nginx -t &>/dev/null; then + echo "✅ Nginx configuration is valid" + else + echo "❌ Nginx configuration has errors. Check with: sudo nginx -t" + fi +else + echo "❌ Nginx is not installed" +fi + +# Check site configuration +echo "" +echo "📄 Checking site configuration..." +if [ -f "/etc/nginx/sites-enabled/drones.cqers.com" ]; then + echo "✅ Drone detection nginx config is enabled" +else + echo "❌ Drone detection nginx config not found" + echo " Run the setup script: sudo ./scripts/setup-nginx.sh" +fi + +# Test endpoints +echo "" +echo "🔗 Testing endpoints..." +endpoints=( + "http://localhost:3001" + "http://localhost:3002/health" + "http://localhost/health" +) + +for endpoint in "${endpoints[@]}"; do + if curl -s -f "$endpoint" >/dev/null; then + echo "✅ $endpoint is responding" + else + echo "❌ $endpoint is not responding" + fi +done + +# Check logs +echo "" +echo "📊 Recent Docker logs (last 10 lines)..." +if command -v docker &> /dev/null; then + echo "--- Backend logs ---" + docker logs --tail 10 drone-detection-backend 2>/dev/null || echo "No backend container logs" + echo "" + echo "--- Frontend logs ---" + docker logs --tail 10 drone-detection-frontend 2>/dev/null || echo "No frontend container logs" +fi + +echo "" +echo "🏁 Troubleshooting complete!" +echo "" +echo "Common solutions:" +echo "1. Restart containers: docker-compose restart" +echo "2. Rebuild containers: docker-compose up -d --build" +echo "3. Check logs: docker-compose logs -f" +echo "4. Reload nginx: sudo systemctl reload nginx"