Reputation: 2071
With below nginx configuration
server {
listen 2022;
location /STFlow/ {
rewrite ^/STFlow(.*)$ $1 last;
proxy_pass http://zuul-proxy:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $http_x_forwarded_for;
proxy_set_header X-Forwarded-For $http_x_forwarded_for;
}
location / {
set $realip $remote_addr;
if ($http_x_forwarded_for ~ "^(\d+\.\d+\.\d+\.\d+)") {
set $realip $1;
}
proxy_pass http://zuul-proxy:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $http_x_forwarded_for;
proxy_set_header X-Forwarded-For $http_x_forwarded_for;
client_max_body_size 50M;
}
with executing
curl http://okd-dev-route.internal.com/STFlow/dashboard
I get following logs:
2020/07/16 07:38:39 [notice] 31#31: *1 "^/STFlow(.*)$" matches "/STFlow/dashboard", client: 10.129.4.1, server: , request: "GET /STFlow/dashboard HTTP/1.1", host: "okd-dev-route.internal.com"
2020/07/16 07:38:39 [notice] 31#31: *1 rewritten data: "/dashboard", args: "", client: 10.129.4.1, server: , request: "GET /STFlow/dashboard HTTP/1.1", host: "okd-dev-route.internal.com"
2020/07/16 07:38:39 [notice] 31#31: *1 "^(\d+\.\d+\.\d+\.\d+)" matches "10.221.196.254", client: 10.129.4.1, server: , request: "GET /STFlow/dashboard HTTP/1.1", host: "okd-dev-route.internal.com"
2020/07/16 07:38:39 [info] 31#31: *1 client 10.129.4.1 closed keepalive connection (104: Connection reset by peer)
I'm a noob to nginx and okd. It looks for me as if rewrites from both locations /STFlow/ and / are executed!
As far as I understood nginx documentation only one location should be selected and executed.
But here we can see two matches:
"^/STFlow(.*)$" matches "/STFlow/dashboard"
which seems to come from location /STFlow/
and later
"^(\d+.\d+.\d+.\d+)" matches "10.221.196.254" which seems to come from if condition in
location /
How is it possible?
What's going on here?
Is it possible to put some custom debug logs in both locations to see which lines are executed and in what order?
Upvotes: 1
Views: 1122
Reputation: 2071
Here is the explanation of my problem:
The break, if, return, rewrite, and set directives are processed in the following order:
the directives of ngx_http_rewrite_module module specified on the server level are executed sequentially;
repeatedly:
Upvotes: 0
Reputation: 9895
As far as I understood nginx documentation only one location should be selected and executed
Only a single location is indeed selected for serving a request. It does not mean that there is no "jumping" done between the locations (contexts) while reaching the final location.
This is what the rewrite module is actually responsible for: jumping between contexts by rewriting current URI / repeating NGINX's location search based on the rewritten URI.
NGINX first finds the location
with longest prefix for serving request. Specific to your example, this is location /STFlow/ {
. Now it selected it for evaluation.
It sees rewrite ^/STFlow(.*)$ $1 last;
which modifies current URI to /dashboard
. The last
keyword to rewrite
directive triggers location search all over again based on the now current /dashboard
URI. Worth noting that while jumping location /STFlow/ {
to location / {
the directives from the former are not going to apply. After the "jump", now location / {
is the one currently selected for serving the request, etc.
The location / {
has no more directives (no try_files
, rewrite
, etc.) that can modify the current URI and trigger searching all over again. Thus it is the final location that will be used by NGINX for constructing the response.
The directives/configuration that will finally apply to serving response is the ones from the final location or its parent, if the final location is a nested location. Even then, it depends on specific directives. Some directives will be inherited from parent location and some would not. It is a major topic of its own. For example:
location / {
expires max;
location /foo/ {
index index.php;
}
}
The expires
will apply for request to /foo/bar
because it belongs to the nested location /foo/
.
But if you were to make it non-nested:
location / {
expires max;
}
location /foo/ {
index index.php;
}
The expires
will not apply to URI /foo/bar
.
Array-like directives, e.g. fastcgi_param
, add_header
, etc. are counter-intuitive in how they inherit from parent location. They are inherited only if they are not present in the nested location.
location / {
add_header X-Foo Bar;
location /foo/ {
add_header X-Something 1;
}
}
With this config, only X-Something: 1;
is set, but if you were to comment out its line, you will have parent header apply and see X-Foo: Bar
in the output headers.
Some may call it "bad design" because it leads to a lot of confusion at the beginning.
Upvotes: 2