Repository navigation
Expand file tree
/
Copy pathnginx.conf.template
More file actions
160 lines (134 loc) · 6.12 KB
/
Copy pathnginx.conf.template
File metadata and controls
160 lines (134 loc) · 6.12 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
worker_processes auto;
daemon off;
pid $NGINX_PID_PATH;
error_log $NGINX_ERROR_LOG_PATH;
# Run worker processes as root so that they can access root-owned Unix domain sockets.
user root;
events {
worker_connections 1024;
}
http {
access_log $NGINX_ACCESS_LOG_PATH;
# Serve static assets with correct MIME type based on file extension.
include /etc/nginx/mime.types;
default_type application/octet-stream;
sendfile on;
# See https://nginx.org/en/docs/http/websocket.html.
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
# $request_sub2_uri is $request_uri without the first two slashes and path components.
map $request_uri $request_sub2_uri {
"~^/[^/]+/[^/]+(/.*)$" $1;
default "/";
}
# Cache for /api/auth-route
proxy_cache_path /var/cache/nginx_auth_route keys_zone=auth_route_cache:8m;
# The app.
server {
listen 3000;
server_name localhost;
# /_vs/<session_id>/* forwards to the VS Code server identified by <session_id>,
# as long as the auth_request accepts the user's session cookie.
location ~ ^/_vs/(?<session_id>[^/]+)/.*$ {
# AUTHENTICATION
# Capture the current URI for the auth subrequest.
# ($request_uri doesn't work since it's the original URI, pre-rewrite,
# whereas $uri evaluates to the subrequest URI in the auth subrequest's context.)
set $auth_route_uri $uri;
# Authentication is cached on the session ID and all cookies,
# notably the better-auth session cookie:
# this data grants access to all subpaths of this VSC session.
# (We could extract just the session cookie,
# but this is simpler and cookies don't change often.)
set $auth_route_cache_key "$session_id:$http_cookie";
# `auth_request` does not expand variables, so the URI is fixed;
# our handler reads the data to verify from X-Auth-URI.
auth_request /api/auth-route/vs;
# PROXY SETTINGS
auth_request_set $socket_path $upstream_http_x_socket_path;
proxy_pass http://unix:$socket_path:$request_sub2_uri;
proxy_http_version 1.1;
proxy_set_header Host $http_host;
# Support WebSocket upgrades
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
# Recommended by https://coder.com/docs/code-server/guide#using-lets-encrypt-with-nginx
proxy_set_header Accept-Encoding gzip;
# Leave connections open for 24h even if no bytes are sent.
proxy_read_timeout 86400;
}
# Block unmatched /_vs/*
location /_vs/ {
return 404;
}
# /_file/<token>/<relPath> serves the static asset at <rootDir>/<relPath>
# where <rootDir> is <token>'s root directory, as long as <token> is valid.
# See `lib/server/authToken.ts`.
location ~ ^/_file/[^/]+/.*$ {
# NORMALIZATION
# Serve index.html on directory requests.
# `last` starts a search for a location matching the changed URI after rewriting.
rewrite ^(.+)/$ $1/index.html last;
# AUTHENTICATION
set $auth_route_uri $uri;
# We must cache file request authentication on the whole URI
# since the auth handler returns the validated path.
set $auth_route_cache_key $uri;
auth_request /api/auth-route/file;
# FORWARDING
# After auth succeeds, alias to the path that has been approved.
auth_request_set $validated_path $upstream_http_x_validated_file_path;
alias $validated_path;
# SANDBOXING
# Same restrictions as on /_vs/, since static assets are also user-authored.
add_header Content-Security-Policy "sandbox allow-scripts" always;
add_header Access-Control-Allow-Origin "*" always;
add_header Referrer-Policy "strict-origin" always;
# Auth-file ensures that $validated_path lives under <rootDir>,
# but the underlying file could be replaced by a symlink right after auth responds.
# We block the TOCTOU attack by preventing any symlinks here.
disable_symlinks on;
}
# Block unmatched /_file/*
location /_file/ {
return 404;
}
# Validates that a request has the necessary permissions.
# Target of `auth_request` in /_file/* and /_vs/* requests.
# See https://docs.nginx.com/nginx/admin-guide/security-controls/configuring-subrequest-authentication/.
location ^~ /api/auth-route/ {
# Can only be reached by internal requests
internal;
proxy_pass http://127.0.0.1:3002;
proxy_http_version 1.1;
proxy_set_header Host $http_host;
# Skip the original body (but keep the headers).
proxy_pass_request_body off;
proxy_set_header Content-Length "";
# Send the URI to be authenticated as a header.
proxy_set_header X-Auth-URI $auth_route_uri;
# Cache successes to avoid hitting Next.js repeatedly.
proxy_cache auth_route_cache;
proxy_cache_key $auth_route_cache_key;
proxy_cache_valid 200 10m;
}
# Resolvers for the publish origin are defined in this app, but the publish
# server block is their only caller. Deny them here.
location ^~ /api/pub-route/ {
return 404;
}
# All other requests are forwarded to Next.js server.
location / {
proxy_pass http://127.0.0.1:3002;
proxy_http_version 1.1;
proxy_set_header Host $http_host;
# Allow WebSocket connections for Next.js HMR
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}
# The publish origin, when one is configured. See `nginx-pub.conf.template`.
include $NGINX_CONF_DIR/pub.conf;
}