This came up from time here and there but no question properly covers this use case.
The relevant section of http
:
map $http_origin $origin_with_default {
default '*';
~. $http_origin;
}
map $request_method $es_target {
default '';
POST 'search';
GET 'search';
HEAD 'search';
OPTIONS 'options';
}
root /app;
The relevant section of server
:
server {
location ~* /(.*)/_search {
limit_except OPTIONS {
auth_basic "Read Users";
auth_basic_user_file /etc/nginx/htpasswd_read;
}
rewrite ^ /internal/$es_target;
}
location /internal {
return 405;
}
location /internal/search/ {
internal;
proxy_pass http://elasticsearch/;
proxy_http_version 1.1;
proxy_set_header Connection "Keep-Alive";
proxy_set_header Proxy-Connection "Keep-Alive";
proxy_hide_header Access-Control-Allow-Origin;
proxy_hide_header Access-Control-Allow-Credentials;
proxy_hide_header Access-Control-Allow-Headers;
proxy_hide_header Access-Control-Allow-Credentials;
include "cors.headers";
}
location /internal/options {
internal;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
add_header 'Access-Control-Max-Age' 1728000;
include "cors.headers";
return 204;
}
}
Finally, the cors.headers
file:
add_header Access-Control-Allow-Credentials "true" always;
add_header Access-Control-Allow-Origin $origin_with_default always;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS' always;
add_header Access-Control-Allow-Headers 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always;
POST https://example.com/index_name/_search
gives 401. This is as expected.OPTIONS https://example.com/index_name/_search
returns the options headers. This is also as expected.- However,
POST https://u:[email protected]/index_name/_search
gives a 404 and the server log containsopen() "/app/index_name/_search" failed (2: No such file or directory),
. Before I added therewrite ^ /internal/$es_target;
and thelocation /internal/search/
section, when theproxy_pass
was just afterlimit_except
insidelocation ~* /(.*)/_search {
it did work. Because of 1) and 2) I believe the rewrite and the location matching works. But why does it try to serve a file instead of doing a proxy pass?
CodePudding user response:
Here's a working config. It needed limit_except
removed, every location switched to regex matching consuming everything -- and the last location being last is important to be so otherwise it gets into a rewrite loop. The "If the proxy_pass directive is specified with a URI, then when a request is passed to the server, the part of a normalized request URI matching the location is replaced by a URI specified in the directive" part of the rewrite module is not something I was able to get working.
We still need the http
section:
map $http_origin $origin_with_default {
default '*';
~. $http_origin;
}
map $request_method $es_target {
default 'invalid';
POST 'search';
GET 'search';
HEAD 'search';
OPTIONS 'options';
}
And then comes server
server {
location ~ /internal/search/(?<search>.*) {
internal;
auth_basic "Read Users";
auth_basic_user_file /etc/nginx/htpasswd_read;
proxy_pass http://elasticsearch/$search;
proxy_http_version 1.1;
proxy_set_header Connection "Keep-Alive";
proxy_set_header Proxy-Connection "Keep-Alive";
proxy_hide_header Access-Control-Allow-Origin;
proxy_hide_header Access-Control-Allow-Credentials;
proxy_hide_header Access-Control-Allow-Headers;
proxy_hide_header Access-Control-Allow-Credentials;
include "cors.headers";
}
location ~ /internal/options {
internal;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
add_header 'Access-Control-Max-Age' 1728000;
include "cors.headers";
return 204;
}
location ~ /internal/invalid {
return 405;
}
location ~* /_search$ {
rewrite (.*) /internal/$es_target$1;
}
}