Reputation: 924
i want to use nginx set directive to use a variable as argument of proxy_pass
but doing so ends up in a endless 301 Moved Permanently
error in chrome when accessing https://foo.de/myleaps
with the code below:
user "reverse-proxy" "reverse-proxy";
error_log stderr;
daemon off;
events {}
http {
server {
listen 80;
listen [::]:80;
server_name foo.de;
location /myleaps {
rewrite ^ https://$server_name$request_uri? permanent;
}
} server {
ssl on;
listen 443 ssl;
listen [::]:443 ssl;
server_name foo.de;
ssl_certificate /var/lib/nixcloud/TLS/foo.de/selfsigned/fullchain.pem;
ssl_certificate_key /var/lib/nixcloud/TLS/foo.de/selfsigned/key.pem;
location /myleaps {
set $tttt http://127.0.0.1:3031/myleaps;
# https default flags
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_pass $tttt;
}
location /myleaps/leaps/ws {
# https websocket default flags
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Forwarded-For $remote_addr;
proxy_read_timeout 36000s;
# required because of CORS
proxy_set_header Host $host;
proxy_pass http://127.0.0.1:3031/myleaps/leaps/ws;
}
}
}
when using this:
proxy_pass http://127.0.0.1:3031/myleaps;
instead of:
proxy_pass $tttt;
it works for my example.
so the question is: why does proxy_pass
work with an hard coded string but not with using a variable?
in the reverse-proxy here https://github.com/nixcloud/nixcloud-webservices/blob/be57d526547c66db05595002682525ca62c8f068/modules/services/reverse-proxy/default.nix#L144 the code which generates the proxy_pass
is basically hardcoded and if a user wishes to override this it is going to be really complicated. so the idea is to generate 3 variables: ip, port and path and put it into the location scope and let the user later use these. this way i could get rid of the hardcoded proxy_pass
directive and the user would be much more flexible in modifying/generating the location record.
so the code could be like this:
set $targetIP = ${location.ip};
set $targetPort = ${toString location.port}
set $targetPath = ${removeSuffix "/" (toString (builtins.toPath (location.path)))};
and the 3 lines above would always be generated into that location record, no matter what. but the code below is dynamically generated and a default implementation could be this:
proxy_pass http://$targetIP:$targetPort$targetPath;
but the user could simply override it by:
nixcloud.reverse-proxy = {
enable = true;
extendEtcHosts = true;
extraMappings = [
{
domain = "example.com";
path = "/";
https = {
mode = "on";
basicAuth."joachim" = "foo";
record = ''
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_pass http://$targetIP:$targetPort$targetPath
'';
};
}
];
};
Upvotes: 0
Views: 4823
Reputation: 924
it is working using $request_uri
instead of hardcoding the proxy_pass path using $targetPath:
set $targetIP 127.0.0.1;
set $targetPort 3031;
proxy_pass http://$targetIP:$targetPort$request_uri;
this code will soon be in nixcloud-webservices!
thanks to irc.freenode.net#nginx@benbrown (Ben Brown) for this solution!
Upvotes: 1