1- # =============================================================================
21# X-Accel-Redirect reverse proxy for minikv
32#
4- # DNS RESOLUTION NOTE:
5- # nginx resolves upstream hostnames at *startup* by default. If the upstream
6- # (coordinator, volume servers) is not yet in DNS, nginx refuses to start.
3+ # DNS resolution
74#
8- # To overcome this, we use `resolver` + a variable for every upstream.
9- # When the upstream is stored in a variable , nginx defers DNS resolution
10- # to *request time*, so startup succeeds even if backends aren't running yet .
5+ # By default, nginx resolves upstream hostnames at startup. If an upstream
6+ # service (coordinator or volume server) is not yet resolvable , nginx fails
7+ # to start .
118#
12- # Docker's internal DNS resolver is always at 127.0.0.11.
13- # =============================================================================
9+ # To avoid this, upstreams are stored in variables and a `resolver` is
10+ # configured. When `proxy_pass` references a variable, DNS resolution
11+ # happens at request time instead of startup time.
12+ #
13+ # In Docker environments, the internal DNS resolver is available at
14+ # 127.0.0.11.
1415
1516worker_processes auto;
1617error_log /dev/stderr warn;
@@ -28,34 +29,30 @@ http {
2829 server_tokens off;
2930 default_type application/octet-stream;
3031
31- # Docker's internal DNS — required for runtime upstream resolution.
32- # `valid=5s` re-resolves every 5 seconds so container restarts are
33- # picked up quickly without reloading nginx.
32+ # Docker internal DNS for runtime upstream resolution.
33+ # `valid=5s` forces periodic re-resolution so container restarts
34+ # are detected without reloading nginx.
3435 resolver 127.0.0.11 valid=5s ipv6=off;
3536
3637 server {
3738 listen 8080 default_server;
3839 server_name _;
3940
40- # ------------------------------------------------------------------
41- # Coordinator upstream as a variable — defers DNS to request time.
42- # Service name matches docker-compose: "minikv"
43- # ------------------------------------------------------------------
41+ # Coordinator upstream stored in a variable to defer DNS resolution
42+ # to request time. Service name matches docker-compose ("minikv").
4443 set $coordinator_upstream "minikv:3000";
4544
46- # ------------------------------------------------------------------
47- # Main proxy: all client requests go to the coordinator.
45+ # Main proxy. All client requests are forwarded to the coordinator.
4846 #
49- # On GET/ HEAD the coordinator returns :
50- # X-Accel-Redirect: /accel/volume1:8080/sv09/a2/38/...
51- # Content-Type: image/jpeg
52- # Content-Blake3: <hash>
53- # Key-Balance: balanced
47+ # For GET and HEAD, the coordinator responds with :
48+ # X-Accel-Redirect: /accel/<volume>/<object-path>
49+ # Content-Type
50+ # Content-Blake3
51+ # Key-Balance
5452 #
55- # nginx intercepts X-Accel-Redirect and performs an internal
56- # subrequest, streaming the object body to the client with the
57- # coordinator's headers intact.
58- # ------------------------------------------------------------------
53+ # nginx intercepts X-Accel-Redirect and performs an internal subrequest.
54+ # The object body is streamed from the volume server while preserving
55+ # coordinator-provided metadata headers.
5956 location / {
6057 proxy_pass http://$coordinator_upstream;
6158
@@ -64,10 +61,10 @@ http {
6461 proxy_set_header X-Real-IP $remote_addr;
6562 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
6663
67- # Disable request buffering — required for streaming PUT uploads.
64+ # Disable request buffering to allow streaming PUT uploads.
6865 proxy_request_buffering off;
6966
70- # Disable response buffering — stream GET bodies directly.
67+ # Disable response buffering to stream GET responses directly.
7168 proxy_buffering off;
7269
7370 # Pass all coordinator metadata headers through to client.
@@ -77,23 +74,21 @@ http {
7774 proxy_pass_header Key-Volumes;
7875 }
7976
80- # ------------------------------------------------------------------
8177 # Internal X-Accel-Redirect handler.
8278 #
8379 # URI format: /accel/<volume-host:port>/<object-path>
84- # Example: /accel/volume1:8080/sv09/a2/38/bXlib ...
80+ # Example: /accel/volume1:8080/sv09/a2/38/...
8581 #
86- # `internal` makes this location unreachable by direct client
87- # requests — only X-Accel-Redirect from the coordinator can
88- # trigger it . Direct requests return 404.
82+ # The `internal` directive prevents direct client access. Only
83+ # X-Accel-Redirect responses from the coordinator can trigger this
84+ # location . Direct requests return 404.
8985 #
90- # The upstream is captured into a variable ($vol_upstream) so
91- # DNS resolution is deferred to request time (same pattern as above).
92- # ------------------------------------------------------------------
86+ # The captured upstream is stored in a variable to defer DNS
87+ # resolution to request time.
9388 location ~ ^/accel/([^/]+)/(.*)$ {
9489 internal;
9590
96- # Capture volume host:port and path into variables for runtime DNS .
91+ # Capture volume host:port and object path into variables.
9792 set $vol_upstream $1;
9893 set $vol_path $2;
9994
@@ -102,26 +97,22 @@ http {
10297 # Do not forward client request headers to volume servers.
10398 proxy_pass_request_headers off;
10499
105- # ---------------------------------------------------------------
106- # Content-Type injection via variable persistence.
100+ # Content-Type handling.
107101 #
108- # The coordinator sets X-Content-Type on its response.
109- # nginx stores this as $upstream_http_x_content_type — a variable
110- # that persists across the X-Accel-Redirect internal redirect
111- # (same ngx_http_request_t context).
102+ # The coordinator provides X-Content-Type in its response. nginx
103+ # exposes this as $upstream_http_x_content_type. This variable
104+ # persists across the internal X-Accel-Redirect.
112105 #
113- # If the coordinator has no stored Content-Type for this object
114- # (object was PUT without a Content-Type header, or rebuilt from
115- # volume data), $upstream_http_x_content_type will be empty.
116- # In that case we fall back to application/octet-stream rather
117- # than emitting an empty Content-Type header.
106+ # If no Content-Type metadata exists (for example, the object was
107+ # uploaded without one or reconstructed from volume data), the
108+ # variable is empty. In that case, application/octet-stream is used.
118109 #
119- # Objects can be re-PUT with Content-Type to populate the field.
120- # ---------------------------------------------------------------
110+ # Objects may be re-uploaded with a Content-Type header to set
111+ # the stored metadata.
121112 proxy_hide_header Content-Type;
122113
123- # Resolve effective Content-Type: coordinator metadata wins,
124- # fall back to octet-stream when metadata is absent.
114+ # Coordinator metadata takes precedence. Fall back to
115+ # application/ octet-stream when absent.
125116 set $effective_ct $upstream_http_x_content_type;
126117 if ($effective_ct = "") {
127118 set $effective_ct "application/octet-stream";
0 commit comments