# Upstream configuration upstream skyartshop_backend { server localhost:5000; keepalive 64; } # Rate limiting zones - Enhanced for security limit_req_zone $binary_remote_addr zone=general:10m rate=100r/s; limit_req_zone $binary_remote_addr zone=admin:10m rate=10r/s; # Reduced from 20 to 10 limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m; # Only 5 login attempts per minute limit_conn_zone $binary_remote_addr zone=addr:10m; # Block common attack patterns map $request_uri $is_blocked { default 0; "~*\.(asp|aspx|php|jsp|cgi)$" 1; # Block common SQL injection keywords except allow legitimate admin endpoints "~*(eval|base64|decode|union|select|insert|update|drop)" 1; "~*(/\.|\.\./)" 1; } server { server_name skyarts.ddns.net localhost; # Block malicious requests if ($is_blocked = 1) { return 444; } # Enhanced 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; add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always; # Content Security Policy - Allow only trusted CDNs add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.jsdelivr.net https://cdn.ckeditor.com https://cdnjs.cloudflare.com; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://cdnjs.cloudflare.com https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com https://cdn.jsdelivr.net https://cdnjs.cloudflare.com; img-src 'self' data: https:; connect-src 'self' https://cdn.jsdelivr.net https://cdn.ckeditor.com; frame-src 'none';" always; # Prevent clickjacking add_header X-Permitted-Cross-Domain-Policies "none" always; # HSTS - Force HTTPS add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; # Connection limits limit_conn addr 10; # General rate limiting limit_req zone=general burst=200 nodelay; # Logging access_log /var/log/nginx/skyartshop_access.log combined buffer=32k; error_log /var/log/nginx/skyartshop_error.log warn; # Block access to sensitive files location ~ /\. { deny all; access_log off; log_not_found off; } # Block access to config files location ~* \.(conf|config|json|lock|git|env)$ { deny all; } # Admin root redirect - exact matches for /admin and /admin/ location = /admin { limit_req zone=admin burst=10 nodelay; proxy_pass http://skyartshop_backend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection keep-alive; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Real-IP $remote_addr; proxy_connect_timeout 60s; proxy_send_timeout 60s; proxy_read_timeout 60s; client_max_body_size 1M; } location = /admin/ { limit_req zone=admin burst=10 nodelay; proxy_pass http://skyartshop_backend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection keep-alive; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Real-IP $remote_addr; proxy_connect_timeout 60s; proxy_send_timeout 60s; proxy_read_timeout 60s; client_max_body_size 1M; } # API routes - proxy to backend location /api/ { limit_req zone=general burst=100 nodelay; proxy_pass http://skyartshop_backend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection keep-alive; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Real-IP $remote_addr; proxy_connect_timeout 60s; proxy_send_timeout 60s; proxy_read_timeout 60s; client_max_body_size 50M; } # Admin static files (HTML, CSS, JS) location /admin/ { limit_req zone=admin burst=20 nodelay; alias /var/www/skyartshop/admin/; try_files $uri $uri/ =404; # Cache static assets location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2|ttf|eot)$ { expires 7d; add_header Cache-Control "public, immutable"; } # No cache for HTML files location ~* \.html$ { add_header Cache-Control "no-cache, no-store, must-revalidate"; add_header Pragma "no-cache"; add_header Expires "0"; } } # Main application - catch all location / { proxy_pass http://skyartshop_backend; proxy_http_version 1.1; # Connection headers proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection keep-alive; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; # Forwarding headers proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Real-IP $remote_addr; # Timeouts proxy_connect_timeout 60s; proxy_send_timeout 60s; proxy_read_timeout 60s; # Buffer settings for performance proxy_buffering on; proxy_buffer_size 4k; proxy_buffers 24 4k; proxy_busy_buffers_size 8k; proxy_max_temp_file_size 2048m; client_max_body_size 50M; } listen [::]:443 ssl ipv6only=on; # managed by Certbot listen 443 ssl; # managed by Certbot ssl_certificate /etc/letsencrypt/live/skyarts.ddns.net/fullchain.pem; # managed by Certbot ssl_certificate_key /etc/letsencrypt/live/skyarts.ddns.net/privkey.pem; # managed by Certbot include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot } server { if ($host = skyarts.ddns.net) { return 301 https://$host$request_uri; } # managed by Certbot listen 80; listen [::]:80; server_name skyarts.ddns.net localhost; return 404; # managed by Certbot }