Fix jwt-token
This commit is contained in:
60
.env.production
Normal file
60
.env.production
Normal 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
311
DOMAIN_MIGRATION_GUIDE.md
Normal 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!
|
||||||
138
docker-compose.production.yml
Normal file
138
docker-compose.production.yml
Normal 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
165
nginx/conf.d/default.conf
Normal 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
101
scripts/setup-ssl.sh
Normal 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
|
||||||
Reference in New Issue
Block a user