forked from solomon2773/nora
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathnginx.conf
More file actions
177 lines (154 loc) · 6.48 KB
/
Copy pathnginx.conf
File metadata and controls
177 lines (154 loc) · 6.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
resolver 127.0.0.11 ipv6=off valid=1s;
# Don't advertise the nginx version in error pages or the Server header.
server_tokens off;
map $request_uri $surface_x_frame_options {
default "DENY";
~^/api(/|\?|$) "";
~^/(app|admin)(/|\?|$) "SAMEORIGIN";
~^/_next(/|\?|$) "";
}
map $request_uri $surface_x_content_type_options {
default "nosniff";
~^/api(/|\?|$) "";
}
map $request_uri $surface_referrer_policy {
default "strict-origin-when-cross-origin";
~^/api(/|\?|$) "";
}
map $request_uri $surface_cross_origin_opener_policy {
default "same-origin";
~^/api(/|\?|$) "";
}
# Baseline security headers applied to every response. nginx.public.conf
# adds HSTS on top of these (only safe behind always-on TLS). Use `always`
# so headers also appear on 4xx/5xx responses.
add_header X-Content-Type-Options $surface_x_content_type_options always;
add_header X-Frame-Options $surface_x_frame_options always;
add_header Referrer-Policy $surface_referrer_policy always;
add_header Cross-Origin-Opener-Policy $surface_cross_origin_opener_policy always;
# Fix: 400 Bad Request – Request Header Or Cookie Too Large
large_client_header_buffers 4 32k;
proxy_buffer_size 16k;
proxy_buffers 4 16k;
# WebSocket support mapping
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
# Rate limit zones. Per-IP buckets; the backend applies a second,
# stricter cap inside Express so the two form a belt-and-braces defense.
# 10m of shared memory per zone holds ~160k active states.
#
# auth_limit: login/signup/oauth — tight to slow credential stuffing.
# api_limit: all other /api/* traffic — generous to avoid throttling
# interactive dashboard use while still catching bots.
limit_req_zone $binary_remote_addr zone=auth_limit:10m rate=5r/s;
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=30r/s;
limit_req_status 429;
# Default local-only config. Public-domain installs use nginx.public.conf.
server {
listen 80;
server_name localhost 127.0.0.1 _;
# Shared proxy settings
proxy_http_version 1.1;
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 Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
set $backend_api http://backend-api:4000;
set $app_dashboard http://frontend-dashboard:3000;
set $admin_dashboard http://admin-dashboard:3000;
set $marketing_site http://frontend-marketing:3000;
# 1a. WebSocket streams: logs & terminal (must be above /api/)
location /api/ws/ {
proxy_pass $backend_api/ws/;
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_read_timeout 86400;
}
# 1b. Gateway SSE streams (chat) — disable buffering for real-time streaming
location ~ ^/api/(agents/[^/]+/gateway/chat)$ {
proxy_pass $backend_api/$1$is_args$args;
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 300;
chunked_transfer_encoding off;
proxy_set_header Accept-Encoding "";
}
# 1c. Gateway UI proxy — HTML, JS/CSS assets, favicons, internal paths, embed
location ~ ^/api/(agents/[^/]+/gateway/(ui|assets|favicon|__openclaw__|embed).*)$ {
proxy_pass $backend_api/$1$is_args$args;
proxy_buffering off;
proxy_read_timeout 30;
}
# 1d. Auth surface — credential stuffing / brute-force shield
location ~ ^/api/auth/(login|signup|oauth-login|session-upgrade|logout) {
limit_req zone=auth_limit burst=10 nodelay;
rewrite ^/api/(.*)$ /$1 break;
proxy_pass $backend_api;
}
# 1e. Backend API (general) — loose per-IP cap as a DDoS/scrape fence;
# Express applies tighter per-route limits on top.
location /api/ {
limit_req zone=api_limit burst=60 nodelay;
rewrite ^/api/(.*)$ /$1 break;
proxy_pass $backend_api;
}
# 2. Admin Dashboard
location /admin {
proxy_pass $admin_dashboard;
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 Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
location /admin/_next/ {
proxy_pass $admin_dashboard;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
# 3. App Dashboard (Unified base path)
location /app {
proxy_pass $app_dashboard;
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 Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
# 3. Next.js Static Assets & HMR WebSocket
# Marketing uses root _next (includes webpack-hmr WebSocket)
location /_next/ {
proxy_pass $marketing_site;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
# Dashboard uses /app/_next because of its basePath
location /app/_next/ {
proxy_pass $app_dashboard;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
# 4. Marketing Pages (Root)
location / {
proxy_pass $marketing_site;
}
}
}