Fix jwt-token

This commit is contained in:
2025-09-12 12:43:20 +02:00
parent 3d10d0e894
commit a13d5a3397
5 changed files with 775 additions and 0 deletions

60
.env.production Normal file
View File

@@ -0,0 +1,60 @@
# Production Environment Configuration for Multi-Tenant Domain Setup
# Copy this to .env and update the values
# Domain Configuration
BASE_URL=https://dev.uggla.uamils.com
DOMAIN_NAME=dev.uggla.uamils.com
CORS_ORIGIN=https://dev.uggla.uamils.com,https://*.dev.uggla.uamils.com
# Multi-Tenant Configuration
ENABLE_MULTI_TENANT=true
DEFAULT_TENANT_SUBDOMAIN=app
TENANT_SUBDOMAIN_PATTERN=*.dev.uggla.uamils.com
# SSL/TLS Configuration
SSL_EMAIL=admin@uamils.com
ACME_CA_SERVER=https://acme-v02.api.letsencrypt.org/directory
# Database Configuration
DB_HOST=postgres
DB_PORT=5432
DB_NAME=drone_detection
DB_USER=postgres
DB_PASSWORD=postgres123
# Redis Configuration
REDIS_HOST=redis
REDIS_PORT=6379
# Session Configuration
SESSION_SECRET=your-super-secret-session-key-change-in-production-must-be-32-chars
SESSION_DOMAIN=.dev.uggla.uamils.com
# JWT Configuration
JWT_SECRET=your-super-secret-jwt-key-change-in-production
# SAML Configuration (for enterprise tenants)
SAML_CALLBACK_URL=https://dev.uggla.uamils.com/auth/saml/callback
SAML_LOGOUT_URL=https://dev.uggla.uamils.com/auth/saml/logout
# OAuth Configuration
OAUTH_CALLBACK_URL=https://dev.uggla.uamils.com/auth/oauth/callback
# LDAP Configuration
LDAP_CALLBACK_URL=https://dev.uggla.uamils.com/auth/ldap/callback
# API Configuration
API_DEBUG=false
STORE_HEARTBEATS=false
STORE_DRONE_TYPE0=false
LOG_ALL_DETECTIONS=false
STORE_RAW_PAYLOAD=false
# Rate Limiting
RATE_LIMIT_WINDOW_MS=900000
RATE_LIMIT_MAX_REQUESTS=1000
# Twilio Configuration (optional)
TWILIO_ACCOUNT_SID=
TWILIO_AUTH_TOKEN=
TWILIO_PHONE_NUMBER=

311
DOMAIN_MIGRATION_GUIDE.md Normal file
View File

@@ -0,0 +1,311 @@
# Complete Domain Migration Process for Multi-Tenant Setup
## Overview
This guide walks you through migrating from your current domain to `dev.uggla.uamils.com` with full multi-tenant support and SSL certificates.
## Prerequisites
- Server with Docker and Docker Compose
- Domain access for DNS configuration
- Access to your current drone detection system
## Phase 1: DNS Configuration (Do this first!)
### Step 1: Set up DNS Records
```bash
# In your DNS provider (Cloudflare, Route53, etc.), add:
# Main domain A record
dev.uggla.uamils.com A [YOUR_SERVER_IP]
# Wildcard CNAME record for all subdomains
*.dev.uggla.uamils.com CNAME dev.uggla.uamils.com
# Wait for DNS propagation (can take up to 48 hours)
# Test with: dig dev.uggla.uamils.com
# Test wildcard: dig test.dev.uggla.uamils.com
```
### Step 2: Verify DNS Propagation
```bash
# Test main domain
nslookup dev.uggla.uamils.com
# Test subdomain
nslookup tenant1.dev.uggla.uamils.com
# Both should resolve to your server IP
```
## Phase 2: Update Configuration Files
### Step 3: Copy and Configure Environment
```bash
# On your server, copy the environment template
cp .env.production .env
# Edit the .env file with your specific values:
nano .env
# Update these critical values:
BASE_URL=https://dev.uggla.uamils.com
DOMAIN_NAME=dev.uggla.uamils.com
SSL_EMAIL=your-email@uamils.com
SESSION_SECRET=generate-a-32-character-random-string
JWT_SECRET=generate-another-random-string
```
### Step 4: Database Migration
```bash
# First, stop current containers
docker-compose down
# Run the database migration to add multi-tenant support
docker-compose run --rm backend npm run db:migrate
# This creates the tenants table and updates user schema
```
## Phase 3: SSL Certificate Setup
### Step 5: Generate SSL Certificates
```bash
# Make the SSL setup script executable
chmod +x ./scripts/setup-ssl.sh
# Run the SSL setup (this will be interactive)
./scripts/setup-ssl.sh
# IMPORTANT: During this process, you'll need to:
# 1. Add DNS TXT records when prompted
# 2. Wait for DNS propagation between records
# 3. Complete the manual verification process
```
### Step 6: Manual DNS TXT Record Process
```bash
# When certbot prompts you, you'll see something like:
# Please add the following TXT record to your DNS:
# Name: _acme-challenge.dev.uggla.uamils.com
# Value: abcd1234...
# Add this TXT record in your DNS provider:
_acme-challenge.dev.uggla.uamils.com TXT "abcd1234efgh5678..."
# For wildcard, you'll get a second record:
_acme-challenge.dev.uggla.uamils.com TXT "ijkl9012mnop3456..."
# IMPORTANT: You need BOTH TXT records for wildcard certificates
# Wait 5-10 minutes for DNS propagation before pressing Enter in certbot
```
## Phase 4: Production Deployment
### Step 7: Start Production Environment
```bash
# Start the production environment with SSL
docker-compose -f docker-compose.production.yml up -d
# Check logs to ensure everything starts correctly
docker-compose -f docker-compose.production.yml logs -f
```
### Step 8: Verify SSL and Multi-Tenant Setup
```bash
# Test main domain
curl -I https://dev.uggla.uamils.com
# Test API endpoint
curl -I https://dev.uggla.uamils.com/api/health
# Test tenant subdomain
curl -I https://tenant1.dev.uggla.uamils.com
# All should return 200 OK with SSL certificates
```
## Phase 5: Configure Tenants
### Step 9: Create Default Tenant
```bash
# Access the backend container
docker-compose -f docker-compose.production.yml exec backend sh
# Create default tenant (run this inside container)
node -e "
const { Tenant } = require('./models');
Tenant.create({
name: 'Default Tenant',
subdomain: 'app',
domain: 'dev.uggla.uamils.com',
is_active: true,
auth_config: {
providers: ['local'],
local: { enabled: true }
}
}).then(tenant => {
console.log('Default tenant created:', tenant.toJSON());
process.exit(0);
}).catch(err => {
console.error('Error:', err);
process.exit(1);
});
"
```
### Step 10: Create Additional Tenants
```bash
# Example: Create a tenant for subdomain 'acme'
# This would be accessible at: https://acme.dev.uggla.uamils.com
node -e "
const { Tenant } = require('./models');
Tenant.create({
name: 'ACME Corporation',
subdomain: 'acme',
domain: 'dev.uggla.uamils.com',
is_active: true,
subscription_tier: 'enterprise',
auth_config: {
providers: ['local', 'saml'],
local: { enabled: true },
saml: {
enabled: true,
entryPoint: 'https://acme.com/saml/sso',
issuer: 'acme-drone-detection',
cert: '-----BEGIN CERTIFICATE-----...'
}
}
}).then(tenant => {
console.log('ACME tenant created:', tenant.toJSON());
process.exit(0);
});
"
```
## Phase 6: Update Frontend Configuration
### Step 11: Update React App Configuration
```bash
# Update your client environment variables
# Create client/.env.production
REACT_APP_API_URL=https://dev.uggla.uamils.com/api
REACT_APP_SOCKET_URL=https://dev.uggla.uamils.com
REACT_APP_MULTI_TENANT=true
REACT_APP_DEFAULT_TENANT=app
# Rebuild frontend with new configuration
docker-compose -f docker-compose.production.yml build frontend
```
## Phase 7: Set Up Monitoring and Maintenance
### Step 12: Configure Certificate Auto-Renewal
```bash
# Add to crontab for automatic renewal every 12 hours
# Edit crontab: crontab -e
# Add this line:
0 0,12 * * * cd /path/to/your/project && ./scripts/renew-certs.sh >/dev/null 2>&1
```
### Step 13: Set Up Monitoring
```bash
# Test SSL certificate expiry
echo | openssl s_client -servername dev.uggla.uamils.com -connect dev.uggla.uamils.com:443 2>/dev/null | openssl x509 -noout -dates
# Set up monitoring script
cat > ./scripts/monitor.sh << 'EOF'
#!/bin/bash
# Check if services are running
docker-compose -f docker-compose.production.yml ps
# Check SSL certificate validity
echo "Checking SSL certificate..."
echo | openssl s_client -servername dev.uggla.uamils.com -connect dev.uggla.uamils.com:443 2>/dev/null | openssl x509 -noout -dates
# Test API health
curl -f https://dev.uggla.uamils.com/api/health || echo "API health check failed"
EOF
chmod +x ./scripts/monitor.sh
```
## Phase 8: Migration Verification Checklist
### Step 14: Complete Verification
- [ ] DNS resolves correctly for main domain and wildcard
- [ ] SSL certificates are valid and trusted
- [ ] Main application loads at https://dev.uggla.uamils.com
- [ ] Default tenant works at https://app.dev.uggla.uamils.com
- [ ] API endpoints respond correctly
- [ ] WebSocket/Socket.IO connections work
- [ ] Database migration completed successfully
- [ ] Multi-tenant authentication flows work
- [ ] SSL auto-renewal is configured
### Step 15: Update Documentation and Users
- [ ] Update any hardcoded URLs in your application
- [ ] Notify users of the domain change
- [ ] Update any external integrations
- [ ] Update monitoring/alerting systems
- [ ] Update backup scripts if they reference the old domain
## Troubleshooting Common Issues
### SSL Certificate Issues
```bash
# If certificate generation fails:
# 1. Check DNS TXT records are properly set
# 2. Wait for DNS propagation (up to 24 hours)
# 3. Try staging certificates first (STAGING=1 in setup-ssl.sh)
# Debug DNS TXT records:
dig TXT _acme-challenge.dev.uggla.uamils.com
# Check certificate details:
openssl x509 -in ./certbot/conf/live/dev.uggla.uamils.com/fullchain.pem -text -noout
```
### Multi-Tenant Routing Issues
```bash
# Check Nginx configuration syntax:
docker-compose -f docker-compose.production.yml exec nginx nginx -t
# Check Nginx logs:
docker-compose -f docker-compose.production.yml logs nginx
# Test tenant detection:
curl -H "Host: tenant1.dev.uggla.uamils.com" https://dev.uggla.uamils.com/api/health
```
### Database Connection Issues
```bash
# Check database logs:
docker-compose -f docker-compose.production.yml logs postgres
# Test database connection:
docker-compose -f docker-compose.production.yml exec backend npm run db:migrate
# Check if tenants table exists:
docker-compose -f docker-compose.production.yml exec postgres psql -U postgres -d drone_detection -c "\dt"
```
## Security Considerations
1. **Strong Secrets**: Ensure JWT_SECRET and SESSION_SECRET are cryptographically secure
2. **Rate Limiting**: Configure appropriate rate limits in Nginx
3. **CORS**: Restrict CORS origins to your specific domains
4. **Firewall**: Configure server firewall to only allow necessary ports (80, 443, 22)
5. **Database**: Restrict database access to backend containers only
6. **Monitoring**: Set up log monitoring for security events
## Rollback Plan
If you need to rollback:
1. Update DNS to point back to old domain
2. Restart old environment with original configuration
3. Database should remain compatible (migrations are additive)
4. Wait for DNS propagation
This completes the domain migration process!

View File

@@ -0,0 +1,138 @@
# Multi-Tenant Nginx Configuration with Let's Encrypt Support
# This configuration supports:
# - Wildcard SSL certificates via Let's Encrypt
# - Multi-tenant routing based on subdomains
# - Automatic SSL renewal
# - WebSocket support for Socket.IO
version: '3.8'
services:
# Nginx Reverse Proxy with SSL
nginx:
image: nginx:alpine
container_name: drone-detection-nginx
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/conf.d:/etc/nginx/conf.d
- ./nginx/ssl:/etc/nginx/ssl
- ./certbot/conf:/etc/letsencrypt
- ./certbot/www:/var/www/certbot
- ./client/dist:/usr/share/nginx/html
depends_on:
- backend
- frontend
networks:
- drone-network
command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'"
# Certbot for Let's Encrypt SSL
certbot:
image: certbot/certbot
container_name: drone-detection-certbot
restart: "no"
volumes:
- ./certbot/conf:/etc/letsencrypt
- ./certbot/www:/var/www/certbot
entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"
# PostgreSQL Database
postgres:
image: postgres:15-alpine
container_name: drone-detection-db
restart: unless-stopped
environment:
POSTGRES_DB: drone_detection
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres123
PGDATA: /var/lib/postgresql/data/pgdata
volumes:
- postgres_data:/var/lib/postgresql/data
- ./server/scripts/init-db.sql:/docker-entrypoint-initdb.d/init-db.sql
ports:
- "5433:5432"
networks:
- drone-network
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres -d drone_detection"]
interval: 30s
timeout: 10s
retries: 3
# Redis for session management and caching
redis:
image: redis:7-alpine
container_name: drone-detection-redis
restart: unless-stopped
command: redis-server --appendonly yes
volumes:
- redis_data:/data
ports:
- "6380:6379"
networks:
- drone-network
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 30s
timeout: 10s
retries: 3
# Backend API Server
backend:
build:
context: ./server
dockerfile: Dockerfile
container_name: drone-detection-backend
restart: unless-stopped
env_file:
- .env.production
environment:
NODE_ENV: production
PORT: 3001
DB_HOST: postgres
DB_PORT: 5432
DB_NAME: drone_detection
DB_USER: postgres
DB_PASSWORD: postgres123
REDIS_HOST: redis
REDIS_PORT: 6379
volumes:
- ./server/logs:/app/logs
- ./debug_logs:/app/debug_logs
networks:
- drone-network
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3001/api/health"]
interval: 30s
timeout: 10s
retries: 3
# Frontend (React Build)
frontend:
build:
context: ./client
dockerfile: Dockerfile
args:
REACT_APP_API_URL: https://dev.uggla.uamils.com/api
REACT_APP_SOCKET_URL: https://dev.uggla.uamils.com
REACT_APP_MULTI_TENANT: "true"
container_name: drone-detection-frontend
restart: unless-stopped
networks:
- drone-network
volumes:
postgres_data:
redis_data:
networks:
drone-network:
driver: bridge

165
nginx/conf.d/default.conf Normal file
View File

@@ -0,0 +1,165 @@
# Multi-Tenant Nginx Configuration
# Supports wildcard SSL and subdomain-based tenant routing
# Rate limiting zones
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=auth:10m rate=5r/s;
# Upstream backend
upstream backend {
server backend:3001;
}
# HTTP redirect to HTTPS
server {
listen 80;
server_name dev.uggla.uamils.com *.dev.uggla.uamils.com;
# Let's Encrypt challenge
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
# Redirect all other traffic to HTTPS
location / {
return 301 https://$host$request_uri;
}
}
# Main HTTPS server for multi-tenant setup
server {
listen 443 ssl http2;
server_name dev.uggla.uamils.com *.dev.uggla.uamils.com;
# SSL Configuration
ssl_certificate /etc/letsencrypt/live/dev.uggla.uamils.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/dev.uggla.uamils.com/privkey.pem;
# SSL Security
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;
# 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;
# Client settings
client_max_body_size 100M;
# Extract tenant from subdomain
set $tenant "default";
if ($host ~ ^([^.]+)\.dev\.uggla\.uamils\.com$) {
set $tenant $1;
}
# API routes with rate limiting
location /api/ {
limit_req zone=api burst=20 nodelay;
# Add tenant header for backend
proxy_set_header X-Tenant-Subdomain $tenant;
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_pass http://backend;
proxy_redirect off;
# Timeouts
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
# Authentication routes with stricter rate limiting
location /auth/ {
limit_req zone=auth burst=10 nodelay;
proxy_set_header X-Tenant-Subdomain $tenant;
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_pass http://backend;
proxy_redirect off;
}
# Socket.IO with WebSocket support
location /socket.io/ {
proxy_set_header X-Tenant-Subdomain $tenant;
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
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://backend;
proxy_redirect off;
# WebSocket timeouts
proxy_connect_timeout 7d;
proxy_send_timeout 7d;
proxy_read_timeout 7d;
}
# Static files (React app)
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ /index.html;
# Cache static assets
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
# Add tenant info to HTML
location = /index.html {
add_header X-Tenant-Subdomain $tenant always;
expires 0;
add_header Cache-Control "no-cache, no-store, must-revalidate";
}
}
# Health check
location /nginx-health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
}
# Specific configuration for main domain (app subdomain)
server {
listen 443 ssl http2;
server_name app.dev.uggla.uamils.com;
# SSL Configuration (same as above)
ssl_certificate /etc/letsencrypt/live/dev.uggla.uamils.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/dev.uggla.uamils.com/privkey.pem;
# Include all the same configurations as above
include /etc/nginx/conf.d/common-ssl.conf;
# Set default tenant
set $tenant "app";
# Include common proxy configurations
include /etc/nginx/conf.d/common-proxy.conf;
}

101
scripts/setup-ssl.sh Normal file
View File

@@ -0,0 +1,101 @@
#!/bin/bash
# SSL Certificate Setup Script for Multi-Tenant Domain
# This script sets up Let's Encrypt wildcard certificates
set -e
DOMAIN="dev.uggla.uamils.com"
EMAIL="admin@uamils.com"
STAGING=1 # Set to 0 for production certificates
echo "Setting up SSL certificates for domain: $DOMAIN"
# Create required directories
mkdir -p ./certbot/conf
mkdir -p ./certbot/www
mkdir -p ./nginx/ssl
# Function to get certificate
get_certificate() {
local domain=$1
local email=$2
local staging=$3
if [ $staging -eq 1 ]; then
local staging_flag="--staging"
echo "Getting STAGING certificate (for testing)..."
else
local staging_flag=""
echo "Getting PRODUCTION certificate..."
fi
echo "Requesting wildcard certificate for $domain and *.$domain"
docker-compose -f docker-compose.production.yml run --rm certbot \
certonly \
--manual \
--preferred-challenges=dns \
--email $email \
--server https://acme-v02.api.letsencrypt.org/directory \
--agree-tos \
--no-eff-email \
$staging_flag \
-d $domain \
-d "*.$domain"
}
# Check if certificate already exists
if [ -d "./certbot/conf/live/$DOMAIN" ]; then
echo "Certificate already exists for $DOMAIN"
read -p "Do you want to renew it? (y/n): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
echo "Renewing certificate..."
docker-compose -f docker-compose.production.yml run --rm certbot renew
fi
else
echo "No certificate found. Creating new certificate..."
echo "IMPORTANT: You need to manually add DNS TXT records during this process!"
echo "The certbot will pause and show you the TXT records to add."
echo ""
echo "You'll need to add DNS TXT records like:"
echo " _acme-challenge.$DOMAIN TXT \"[value-shown-by-certbot]\""
echo " _acme-challenge.$DOMAIN TXT \"[another-value-for-wildcard]\""
echo ""
read -p "Press Enter when you're ready to continue..."
get_certificate $DOMAIN $EMAIL $STAGING
fi
# Set up certificate renewal cron job
echo "Setting up automatic certificate renewal..."
# Create renewal script
cat > ./scripts/renew-certs.sh << 'EOF'
#!/bin/bash
cd /path/to/your/project
docker-compose -f docker-compose.production.yml run --rm certbot renew
docker-compose -f docker-compose.production.yml exec nginx nginx -s reload
EOF
chmod +x ./scripts/renew-certs.sh
echo ""
echo "SSL certificate setup completed!"
echo ""
echo "NEXT STEPS:"
echo "1. Add this to your crontab for automatic renewal:"
echo " 0 12 * * * /path/to/your/project/scripts/renew-certs.sh"
echo ""
echo "2. Update your .env.production file with correct domain settings"
echo ""
echo "3. Start the production environment:"
echo " docker-compose -f docker-compose.production.yml up -d"
echo ""
if [ $STAGING -eq 1 ]; then
echo "NOTE: You're using STAGING certificates (for testing)."
echo "Change STAGING=0 in this script and run again for production certificates."
fi