266 lines
12 KiB
Nginx Configuration File
266 lines
12 KiB
Nginx Configuration File
worker_rlimit_nofile 131072;
|
||
events { worker_connections 16384;
|
||
}
|
||
|
||
http {
|
||
keepalive_requests 10000;
|
||
include /etc/nginx/mime.types;
|
||
default_type application/octet-stream;
|
||
resolver 127.0.0.11 ipv6=off;
|
||
limit_conn_zone $binary_remote_addr zone=perip:10m;
|
||
limit_req_zone $binary_remote_addr zone=reqperip:10m rate=100r/s;
|
||
set_real_ip_from 130.211.0.0/22;
|
||
set_real_ip_from 35.191.0.0/16;
|
||
real_ip_header X-Forwarded-For;
|
||
real_ip_recursive on;
|
||
|
||
# ───────────── upstreams to Docker services ─────────────
|
||
upstream backend5000 { server server1:5000; } # auth & free
|
||
upstream backend5001 { server server2:5001;
|
||
keepalive 1024;} # onet, distance, etc.
|
||
upstream backend5002 { server server3:5002; } # premium
|
||
upstream gitea_backend { server gitea:3000; } # gitea service (shared network)
|
||
upstream woodpecker_backend { server woodpecker-server:8000; }
|
||
|
||
########################################################################
|
||
# 1. HTTP → HTTPS redirect for the main site
|
||
########################################################################
|
||
server {
|
||
listen 80;
|
||
listen [::]:80;
|
||
server_name dev1.aptivaai.com;
|
||
return 301 https://$host$request_uri;
|
||
}
|
||
|
||
########################################################################
|
||
# 2. Main virtual host (dev1.aptivaai.com) on :443
|
||
########################################################################
|
||
server {
|
||
listen 443 ssl;
|
||
http2 on;
|
||
http2_max_concurrent_streams 2048;
|
||
server_name dev1.aptivaai.com;
|
||
|
||
ssl_certificate /etc/letsencrypt/live/dev1.aptivaai.com/fullchain.pem;
|
||
ssl_certificate_key /etc/letsencrypt/live/dev1.aptivaai.com/privkey.pem;
|
||
ssl_protocols TLSv1.2 TLSv1.3;
|
||
|
||
# ==== RUNTIME PROTECTIONS ====
|
||
server_tokens off;
|
||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||
add_header X-Content-Type-Options nosniff always;
|
||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||
add_header X-Frame-Options SAMEORIGIN always;
|
||
|
||
client_max_body_size 10m;
|
||
large_client_header_buffers 4 8k;
|
||
|
||
client_header_timeout 30s;
|
||
client_body_timeout 30s;
|
||
send_timeout 35s;
|
||
keepalive_timeout 65s;
|
||
|
||
proxy_set_header X-Request-ID $request_id;
|
||
add_header X-Request-ID $request_id always;
|
||
proxy_request_buffering off;
|
||
proxy_max_temp_file_size 0;
|
||
proxy_buffer_size 16k;
|
||
proxy_buffers 8 16k;
|
||
proxy_busy_buffers_size 32k;
|
||
|
||
if ($request_method !~ ^(GET|POST|PUT|PATCH|DELETE|OPTIONS)$) { return 405; }
|
||
|
||
if ($host !~* ^(dev1\.aptivaai\.com)$) { return 444; }
|
||
|
||
location ~ /\.(?!well-known/) { deny all; }
|
||
|
||
location ~* \.(?:env|ini|log|sql|sqlite|db|db3|bak|old|orig|swp)$ { deny all; }
|
||
|
||
# ───── React static assets ─────
|
||
root /usr/share/nginx/html;
|
||
index index.html;
|
||
# ======= REVIEW-ONLY SURFACE =======
|
||
# 1) Send root to the public A2P page
|
||
location = / { return 302 /a2p/; }
|
||
|
||
# 2) Allowlist public docs
|
||
location ^~ /a2p/ { try_files $uri $uri/ =404; } # /public/a2p/index.html
|
||
location = /sms { return 302 /sms/; }
|
||
location ^~ /sms/ { try_files $uri $uri/ =404; } # /public/sms/index.html
|
||
location ^~ /legal/ { try_files $uri $uri/ =404; } # /public/legal/.../index.html
|
||
|
||
# 3) Keep health + SMS webhooks working
|
||
location = /healthz { return 200 'ok'; add_header Content-Type text/plain; }
|
||
# (Your existing /api/auth/ proxy already covers /api/auth/sms/*)
|
||
|
||
# 4) TEMP: block SPA fallback so deep links don’t expose the app
|
||
location / {
|
||
try_files $uri $uri/ =404;
|
||
}
|
||
|
||
location ~* \.(?:ico|css|js|gif|jpe?g|png|woff2?|eot|ttf|svg)$ {
|
||
expires 6M;
|
||
access_log off;
|
||
}
|
||
|
||
# ───── API reverse‑proxy rules ─────
|
||
location ^~ /api/onet/ {
|
||
proxy_http_version 1.1;
|
||
proxy_set_header Connection "";
|
||
proxy_read_timeout 90s;
|
||
proxy_connect_timeout 15s;
|
||
proxy_pass http://backend5001;
|
||
}
|
||
location ^~ /api/chat/ {
|
||
limit_conn perip 10;
|
||
limit_req zone=reqperip burst=20 nodelay;
|
||
proxy_pass http://backend5001;
|
||
proxy_http_version 1.1;
|
||
proxy_buffering off;
|
||
proxy_set_header Connection "";
|
||
}
|
||
location ^~ /api/job-zones {
|
||
proxy_http_version 1.1;
|
||
proxy_set_header Connection "";
|
||
proxy_read_timeout 90s;
|
||
proxy_connect_timeout 15s;
|
||
proxy_pass http://backend5001;
|
||
}
|
||
location ^~ /api/salary {
|
||
proxy_http_version 1.1;
|
||
proxy_set_header Connection "";
|
||
proxy_read_timeout 90s;
|
||
proxy_connect_timeout 15s;
|
||
proxy_pass http://backend5001;
|
||
}
|
||
location ^~ /api/cip/ {
|
||
proxy_http_version 1.1;
|
||
proxy_set_header Connection "";
|
||
proxy_read_timeout 90s;
|
||
proxy_connect_timeout 15s;
|
||
proxy_pass http://backend5001;
|
||
}
|
||
location ^~ /api/projections/ {
|
||
proxy_http_version 1.1;
|
||
proxy_set_header Connection "";
|
||
proxy_read_timeout 90s;
|
||
proxy_connect_timeout 15s;
|
||
proxy_pass http://backend5001;
|
||
}
|
||
|
||
location ^~ /api/tuition/ { proxy_pass http://backend5001; }
|
||
location ^~ /api/skills/ { proxy_pass http://backend5001; }
|
||
location ^~ /api/maps/distance { proxy_pass http://backend5001; }
|
||
location ^~ /api/schools { proxy_pass http://backend5001; }
|
||
location ^~ /api/support {
|
||
limit_conn perip 5;
|
||
limit_req zone=reqperip burst=10 nodelay;
|
||
proxy_pass http://backend5001;
|
||
}
|
||
location ^~ /api/data/ { proxy_pass http://backend5001; }
|
||
location ^~ /api/careers/ { proxy_pass http://backend5001; }
|
||
location ^~ /api/programs/ { proxy_pass http://backend5001; }
|
||
|
||
location ^~ /api/premium/ {
|
||
limit_conn perip 10;
|
||
limit_req zone=reqperip burst=20 nodelay;
|
||
proxy_pass http://backend5002;
|
||
proxy_http_version 1.1;
|
||
proxy_set_header Connection "";
|
||
}
|
||
location ^~ /api/premium/stripe/webhook {
|
||
proxy_pass http://backend5002;
|
||
proxy_http_version 1.1;
|
||
proxy_set_header Connection "";
|
||
}
|
||
location ^~ /api/public/ { proxy_pass http://backend5002; }
|
||
location ^~ /api/ai-risk { proxy_pass http://backend5002; }
|
||
|
||
location = /api/signin { limit_conn perip 5;
|
||
limit_req zone=reqperip burst=10 nodelay;
|
||
proxy_pass http://backend5000; }
|
||
location = /api/register { limit_conn perip 3;
|
||
limit_req zone=reqperip burst=5 nodelay;
|
||
proxy_pass http://backend5000; }
|
||
location ^~ /api/auth/ { limit_conn perip 5;
|
||
limit_req zone=reqperip burst=10 nodelay;
|
||
proxy_pass http://backend5000; }
|
||
location = /api/user-profile { limit_conn perip 5;
|
||
limit_req zone=reqperip burst=10 nodelay;
|
||
proxy_pass http://backend5000; }
|
||
|
||
# General API (anything not matched above) – rate-limited
|
||
location ^~ /api/ { proxy_pass http://backend5000; }
|
||
|
||
# shared proxy headers
|
||
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;
|
||
|
||
error_page 502 503 504 /50x.html;
|
||
location = /50x.html { root /usr/share/nginx/html; }
|
||
}
|
||
|
||
########################################################################
|
||
# 3. Gitea virtual host (HTTPS) gitea.dev1.aptivaai.com
|
||
########################################################################
|
||
server {
|
||
listen 443 ssl;
|
||
http2 on;
|
||
server_name gitea.dev1.aptivaai.com;
|
||
client_max_body_size 1024m;
|
||
|
||
ssl_certificate /etc/letsencrypt/live/gitea.dev1.aptivaai.com/fullchain.pem;
|
||
ssl_certificate_key /etc/letsencrypt/live/gitea.dev1.aptivaai.com/privkey.pem;
|
||
ssl_protocols TLSv1.2 TLSv1.3;
|
||
|
||
location / {
|
||
proxy_pass http://gitea_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;
|
||
}
|
||
}
|
||
|
||
########################################################################
|
||
# 4. Gitea HTTP → HTTPS redirect
|
||
########################################################################
|
||
server {
|
||
listen 80;
|
||
server_name gitea.dev1.aptivaai.com;
|
||
return 301 https://$host$request_uri;
|
||
}
|
||
########################################################################
|
||
# 5. Woodpecker CI – HTTPS ci.dev1.aptivaai.com
|
||
########################################################################
|
||
|
||
server {
|
||
listen 443 ssl;
|
||
http2 on;
|
||
server_name ci.dev1.aptivaai.com;
|
||
|
||
ssl_certificate /etc/letsencrypt/live/ci.dev1.aptivaai.com/fullchain.pem;
|
||
ssl_certificate_key /etc/letsencrypt/live/ci.dev1.aptivaai.com/privkey.pem;
|
||
ssl_protocols TLSv1.2 TLSv1.3;
|
||
|
||
location / {
|
||
proxy_http_version 1.1;
|
||
proxy_set_header Connection "";
|
||
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_pass http://woodpecker_backend;
|
||
}
|
||
}
|
||
|
||
########################################################################
|
||
# 6. Woodpecker – HTTP → HTTPS redirect
|
||
########################################################################
|
||
server {
|
||
listen 80;
|
||
server_name ci.dev1.aptivaai.com;
|
||
return 301 https://$host$request_uri;
|
||
}} |