# /etc/nginx/sites-available/odoo # Nginx Reverse Proxy Configuration for Odoo # Version: 2.1 | Last Updated: September 2025 # Created by: Aria Shaw # # Instructions: # 1. Replace YOUR_DOMAIN.COM with your actual domain # 2. Update SSL certificate paths # 3. Adjust upstream servers if using multiple Odoo instances # 4. Enable in sites-enabled: sudo ln -s /etc/nginx/sites-available/odoo /etc/nginx/sites-enabled/ # 5. Test configuration: sudo nginx -t # 6. Reload nginx: sudo systemctl reload nginx # ============================================================================== # UPSTREAM CONFIGURATION # ============================================================================== # Odoo Application Servers upstream odoo { # Primary Odoo server server 127.0.0.1:8069; # Additional servers for load balancing (uncomment if needed) # server 127.0.0.1:8070; # server 127.0.0.1:8071; } # Odoo Longpolling Servers (for real-time features) upstream odoochat { server 127.0.0.1:8072; # Additional longpolling servers (uncomment if needed) # server 127.0.0.1:8073; # server 127.0.0.1:8074; } # ============================================================================== # RATE LIMITING CONFIGURATION # ============================================================================== # Define rate limiting zones limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m; limit_req_zone $binary_remote_addr zone=api:10m rate=30r/m; limit_req_zone $binary_remote_addr zone=general:10m rate=60r/m; # ============================================================================== # SSL CONFIGURATION # ============================================================================== # SSL Configuration 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; # OCSP Stapling ssl_stapling on; ssl_stapling_verify on; # ============================================================================== # HTTP TO HTTPS REDIRECT # ============================================================================== server { listen 80; listen [::]:80; server_name YOUR_DOMAIN.COM www.YOUR_DOMAIN.COM; # Security headers for HTTP requests add_header X-Content-Type-Options nosniff always; add_header X-Frame-Options DENY always; add_header X-XSS-Protection "1; mode=block" always; # Redirect all HTTP requests to HTTPS return 301 https://$server_name$request_uri; } # ============================================================================== # HTTPS MAIN SERVER CONFIGURATION # ============================================================================== server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name YOUR_DOMAIN.COM www.YOUR_DOMAIN.COM; # ============================================================================== # SSL CERTIFICATE CONFIGURATION # ============================================================================== # SSL Certificate (Update paths to your certificates) ssl_certificate /etc/letsencrypt/live/YOUR_DOMAIN.COM/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/YOUR_DOMAIN.COM/privkey.pem; # If using custom certificates, uncomment and update: # ssl_certificate /path/to/your/certificate.crt; # ssl_certificate_key /path/to/your/private.key; # ============================================================================== # SECURITY HEADERS # ============================================================================== # Security Headers add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always; add_header X-Content-Type-Options nosniff always; add_header X-Frame-Options DENY always; add_header X-XSS-Protection "1; mode=block" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always; add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' wss:; frame-ancestors 'none';" always; # ============================================================================== # PROXY CONFIGURATION # ============================================================================== # Proxy Settings proxy_read_timeout 720s; proxy_connect_timeout 720s; proxy_send_timeout 720s; # Set Headers for Odoo proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forward-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Host $server_name; # ============================================================================== # LOGGING CONFIGURATION # ============================================================================== # Access and Error Logs access_log /var/log/nginx/odoo.access.log; error_log /var/log/nginx/odoo.error.log; # ============================================================================== # GZIP COMPRESSION # ============================================================================== # Enable compression gzip on; gzip_vary on; gzip_min_length 1024; gzip_proxied expired no-cache no-store private auth; gzip_types text/plain text/css text/xml text/javascript application/json application/javascript application/xml application/xml+rss application/x-javascript image/svg+xml; # ============================================================================== # STATIC FILES CACHING # ============================================================================== # Static files caching location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { expires 1y; add_header Cache-Control "public, immutable"; access_log off; # Try to serve static files directly, fallback to Odoo try_files $uri @odoo; } # ============================================================================== # SPECIAL LOCATIONS # ============================================================================== # Longpolling requests (WebSocket and polling) location /longpolling { proxy_pass http://odoochat; # WebSocket support proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; # Proxy headers proxy_set_header Host $http_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; # Longer timeout for long-polling proxy_read_timeout 3600s; proxy_send_timeout 3600s; } # Database manager (block in production) location /web/database/manager { deny all; return 403; } # Login rate limiting location /web/login { limit_req zone=login burst=10 nodelay; limit_req_status 429; proxy_pass http://odoo; } # API rate limiting location ~ ^/web/(dataset|action) { limit_req zone=api burst=20 nodelay; limit_req_status 429; proxy_pass http://odoo; } # ============================================================================== # SECURITY RESTRICTIONS # ============================================================================== # Block access to sensitive files location ~ /\. { deny all; access_log off; log_not_found off; } # Block access to backup files location ~ ~$ { deny all; access_log off; log_not_found off; } # Block access to configuration files location ~ \.(conf|config|bak|backup|old|orig|save)$ { deny all; access_log off; log_not_found off; } # ============================================================================== # MAIN PROXY LOCATION # ============================================================================== # Default location - proxy all requests to Odoo location / { # Rate limiting for general requests limit_req zone=general burst=30 nodelay; limit_req_status 429; # Proxy to Odoo proxy_pass http://odoo; # Proxy headers proxy_set_header Host $http_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 $server_name; # Handle large request bodies (for file uploads) client_max_body_size 100M; # Proxy timeouts proxy_read_timeout 720s; proxy_connect_timeout 720s; proxy_send_timeout 720s; # Proxy buffering proxy_buffering on; proxy_buffer_size 16k; proxy_buffers 8 16k; proxy_busy_buffers_size 32k; } # Named location for static file fallback location @odoo { proxy_pass http://odoo; proxy_set_header Host $http_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; } # ============================================================================== # HEALTH CHECK ENDPOINT # ============================================================================== # Health check endpoint for load balancers location /nginx-health { access_log off; return 200 "healthy\n"; add_header Content-Type text/plain; } } # ============================================================================== # MONITORING AND MAINTENANCE # ============================================================================== # Server block for monitoring (optional) # Uncomment if you need a separate monitoring interface # server { # listen 8080; # server_name localhost; # # location /nginx_status { # stub_status on; # access_log off; # allow 127.0.0.1; # deny all; # } # } # ============================================================================== # CONFIGURATION NOTES AND RECOMMENDATIONS # ============================================================================== # Performance Tuning Notes: # 1. Adjust worker_processes in main nginx.conf to match CPU cores # 2. Tune worker_connections based on expected load # 3. Monitor nginx access and error logs for optimization opportunities # 4. Consider enabling HTTP/2 push for critical resources # 5. Use nginx caching for static content if needed # Security Recommendations: # 1. Keep nginx updated to latest stable version # 2. Regularly rotate SSL certificates # 3. Monitor rate limiting effectiveness # 4. Review security headers periodically # 5. Consider implementing fail2ban for repeated offenders # SSL Certificate Management: # For Let's Encrypt certificates: # - Install certbot: sudo apt install certbot python3-certbot-nginx # - Obtain certificate: sudo certbot --nginx -d YOUR_DOMAIN.COM # - Auto-renewal: sudo crontab -e, add: 0 12 * * * /usr/bin/certbot renew --quiet # Testing Configuration: # 1. Test syntax: sudo nginx -t # 2. Check SSL: https://www.ssllabs.com/ssltest/ # 3. Monitor logs: sudo tail -f /var/log/nginx/odoo.error.log # 4. Performance test: ab -n 1000 -c 10 https://YOUR_DOMAIN.COM/ # For support and updates, visit: https://ariashaw.github.io