285 lines
9.1 KiB
Nginx Configuration File
285 lines
9.1 KiB
Nginx Configuration File
user nginx;
|
||
worker_processes auto;
|
||
|
||
error_log /var/log/nginx/error.log notice;
|
||
pid /var/run/nginx.pid;
|
||
|
||
events {
|
||
worker_connections 1024;
|
||
use epoll;
|
||
multi_accept on;
|
||
}
|
||
|
||
http {
|
||
include /etc/nginx/mime.types;
|
||
default_type application/octet-stream;
|
||
|
||
# Logging
|
||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||
'$status $body_bytes_sent "$http_referer" '
|
||
'"$http_user_agent" "$http_x_forwarded_for"';
|
||
access_log /var/log/nginx/access.log main;
|
||
|
||
# Basic Settings
|
||
sendfile on;
|
||
tcp_nopush on;
|
||
tcp_nodelay on;
|
||
keepalive_timeout 65;
|
||
types_hash_max_size 2048;
|
||
client_max_body_size 50M;
|
||
server_tokens off;
|
||
|
||
# Gzip Settings
|
||
gzip on;
|
||
gzip_vary on;
|
||
gzip_proxied any;
|
||
gzip_comp_level 6;
|
||
gzip_min_length 1000;
|
||
gzip_types
|
||
text/plain
|
||
text/css
|
||
text/xml
|
||
text/javascript
|
||
application/json
|
||
application/javascript
|
||
application/xml+rss
|
||
application/atom+xml
|
||
image/svg+xml;
|
||
|
||
# Rate Limiting
|
||
limit_req_zone $binary_remote_addr zone=api:10m rate=30r/s;
|
||
limit_req_zone $binary_remote_addr zone=auth:10m rate=10r/s;
|
||
limit_req_zone $binary_remote_addr zone=ws:10m rate=5r/s;
|
||
|
||
# Upstream Backend
|
||
upstream backend {
|
||
server backend:8000;
|
||
keepalive 32;
|
||
}
|
||
|
||
# Upstream Frontend
|
||
upstream frontend {
|
||
server frontend:80;
|
||
keepalive 32;
|
||
}
|
||
|
||
# Production HTTPS Server
|
||
server {
|
||
listen 443 ssl;
|
||
http2 on;
|
||
server_name test.byte-mate.xyz;
|
||
|
||
# SSL Configuration
|
||
ssl_certificate /etc/letsencrypt/live/test.byte-mate.xyz/fullchain.pem;
|
||
ssl_certificate_key /etc/letsencrypt/live/test.byte-mate.xyz/privkey.pem;
|
||
|
||
# Modern 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:ECDHE-RSA-AES256-SHA384;
|
||
ssl_prefer_server_ciphers off;
|
||
ssl_session_timeout 10m;
|
||
ssl_session_cache shared:SSL:10m;
|
||
ssl_session_tickets off;
|
||
|
||
# Security Headers - ИСПРАВЛЕНО для CSP с портами
|
||
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
|
||
add_header X-Content-Type-Options "nosniff" always;
|
||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||
add_header X-XSS-Protection "1; mode=block" always;
|
||
add_header Referrer-Policy "no-referrer-when-downgrade" always;
|
||
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.tailwindcss.com; style-src 'self' 'unsafe-inline' https://cdn.tailwindcss.com; connect-src 'self' https: ws: wss:; media-src 'self' blob:; img-src 'self' data: blob:;" always;
|
||
|
||
# WebSocket support for video calls
|
||
location /ws/ {
|
||
limit_req zone=ws burst=10 nodelay;
|
||
|
||
proxy_pass http://backend;
|
||
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 https;
|
||
proxy_set_header X-Forwarded-Host $server_name;
|
||
proxy_set_header X-Forwarded-Port 443;
|
||
|
||
# WebSocket specific timeouts
|
||
proxy_read_timeout 86400s;
|
||
proxy_send_timeout 86400s;
|
||
proxy_connect_timeout 60s;
|
||
|
||
# Disable buffering for WebSocket
|
||
proxy_buffering off;
|
||
}
|
||
|
||
# Static Files (Django)
|
||
location /static/ {
|
||
alias /staticfiles/;
|
||
expires 1y;
|
||
add_header Cache-Control "public, immutable";
|
||
add_header Access-Control-Allow-Origin *;
|
||
|
||
try_files $uri $uri/ =404;
|
||
access_log off;
|
||
|
||
# Compression for static files
|
||
location ~* \.(js|css)$ {
|
||
gzip_static on;
|
||
expires 1y;
|
||
add_header Cache-Control "public, immutable";
|
||
}
|
||
|
||
# Font files
|
||
location ~* \.(woff|woff2|ttf|eot)$ {
|
||
expires 1y;
|
||
add_header Cache-Control "public, immutable";
|
||
add_header Access-Control-Allow-Origin *;
|
||
}
|
||
|
||
# Images
|
||
location ~* \.(jpg|jpeg|png|gif|ico|svg)$ {
|
||
expires 1M;
|
||
add_header Cache-Control "public";
|
||
}
|
||
}
|
||
|
||
# Media Files (Django)
|
||
location /media/ {
|
||
alias /app/media/;
|
||
expires 1M;
|
||
add_header Cache-Control "public";
|
||
add_header Access-Control-Allow-Origin *;
|
||
|
||
try_files $uri $uri/ =404;
|
||
}
|
||
|
||
# API Routes
|
||
location /api/ {
|
||
limit_req zone=api burst=50 nodelay;
|
||
|
||
proxy_pass http://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 https;
|
||
proxy_set_header X-Forwarded-Host $server_name;
|
||
proxy_set_header X-Forwarded-Port 443;
|
||
|
||
# API specific timeouts
|
||
proxy_connect_timeout 60s;
|
||
proxy_send_timeout 60s;
|
||
proxy_read_timeout 60s;
|
||
|
||
# Buffering
|
||
proxy_buffering on;
|
||
proxy_buffer_size 128k;
|
||
proxy_buffers 4 256k;
|
||
proxy_busy_buffers_size 256k;
|
||
}
|
||
|
||
# Admin Routes - ВАЖНО для исправления редиректов
|
||
location /admin/ {
|
||
limit_req zone=auth burst=5 nodelay;
|
||
|
||
proxy_pass http://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 https;
|
||
proxy_set_header X-Forwarded-Host $server_name;
|
||
proxy_set_header X-Forwarded-Port 443;
|
||
|
||
# Отключаем редиректы от nginx
|
||
proxy_redirect off;
|
||
|
||
proxy_buffer_size 128k;
|
||
proxy_buffers 4 256k;
|
||
proxy_busy_buffers_size 256k;
|
||
}
|
||
|
||
# Frontend Application (Vue.js SPA)
|
||
location / {
|
||
proxy_pass http://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 https;
|
||
proxy_set_header X-Forwarded-Host $server_name;
|
||
proxy_set_header X-Forwarded-Port 443;
|
||
|
||
# Handle SPA routing
|
||
proxy_intercept_errors on;
|
||
error_page 404 = @fallback;
|
||
}
|
||
|
||
# SPA Fallback
|
||
location @fallback {
|
||
proxy_pass http://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 https;
|
||
}
|
||
|
||
# Health Check
|
||
location /health/ {
|
||
access_log off;
|
||
return 200 "healthy\n";
|
||
add_header Content-Type text/plain;
|
||
}
|
||
|
||
# Robots.txt
|
||
location /robots.txt {
|
||
alias /staticfiles/robots.txt;
|
||
try_files $uri =404;
|
||
}
|
||
|
||
# Favicon
|
||
location /favicon.ico {
|
||
alias /staticfiles/favicon.ico;
|
||
try_files $uri =404;
|
||
expires 1y;
|
||
add_header Cache-Control "public, immutable";
|
||
}
|
||
}
|
||
|
||
# HTTP to HTTPS redirect
|
||
server {
|
||
listen 80;
|
||
server_name test.byte-mate.xyz;
|
||
|
||
# Allow Let's Encrypt challenges
|
||
location /.well-known/acme-challenge/ {
|
||
root /var/www/certbot;
|
||
}
|
||
|
||
# Redirect all other traffic to HTTPS
|
||
location / {
|
||
return 301 https://$server_name$request_uri;
|
||
}
|
||
}
|
||
|
||
# Блокировка запросов по IP и техническим доменам
|
||
server {
|
||
listen 80 default_server;
|
||
listen 443 ssl default_server;
|
||
server_name _;
|
||
|
||
# Минимальная SSL конфигурация для блокировки HTTPS запросов
|
||
ssl_certificate /etc/letsencrypt/live/test.byte-mate.xyz/fullchain.pem;
|
||
ssl_certificate_key /etc/letsencrypt/live/test.byte-mate.xyz/privkey.pem;
|
||
ssl_reject_handshake on;
|
||
|
||
# Возвращаем 444 (connection closed without response) для всех запросов
|
||
return 444;
|
||
}
|
||
}
|