My nginx config file goes following:
server {
location /mysite {
auth_request /authVerify;
proxy_pass http://localhost:4200;
error_page 401 = /login;
}
location /authVerify {
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
proxy_pass http://localhost:3000;
}
location /login {
proxy_cookie_path / "/; HttpOnly";
proxy_pass http://localhost:3000;
}
location / {
root html;
index index.html index.htm;
}
}
log related configs use the default settings.
the auth_request configration works. But when I send request to /mysite, there is only logging of it in access log, there is no logging of /authVerify although it actually proxy through this locatoin. If I send request to /authVerify directly, there will be loggings as well.
So in the redirect cases how to produce logs for all the locations the request running through?
Update
Based on the comment, I set log_subrequest as on in http block level. After this change, the logs of internal rediect was produced, but the log of original mysite location disappear.
Currently after I send one request to /mysite, the log is as following:
I found the following explanation on nginx doc:
Requests are logged in the context of a location where processing ends. It may be different from the original location, if an internal redirect happens during request processing.
http://nginx.org/en/docs/http/ngx_http_log_module.html
Is that because of that? Any more methods to log the request's entire flow?
Have you tried enabling log_subrequest?
log_subrequest
Context: http, server, and location
Enables or disables logging of sub-requests triggered by internal redirects or SSI requests.
Syntax: on or off
Default value: off
Related
I am trying to write an nginx configuration for authentication, but I am unsure of how to retain headers when using a 302 redirect.
Below is an example of how the server is setup.
location / {
#send to /auth/ for authentication
request_auth /auth/;
#upon failure, redirect to login
error_page 401 404 = #noaccess;
...
}
location #noaccess {
return 302 /login/;
}
location /auth/ {
internal;
proxy_pass http://127.0.0.1:8888/;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
#The header set here is what I would like to retain
proxy_set_header X-Original-URI $request_uri;
}
location /login/ {
proxy_pass http://127.0.0.1:9000/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
#by the time 302 redirect, $request_uri is no longer the original...
proxy_set_header X-Target $request_uri;
}
Essentially all requests to the server must first be authenticated in the /auth/ location. This location will generally possess the $request_uri that I care about in its sub request. However, whenever the requeset_auth directive fails, and we are redirected with the #noaccess location, nginx makes a new request to /login/.
Is there a way for me to retain the original $request_uri such that it is sent as a header to the /login/ location? (this is needed in order to do a redirect later upon successful authentication).
I've seen some users talk about the auth_request_set directive, but I honestly do not understand how to use it effectively and how the headers of the sub request are renamed or made available.
Yes. With cookies.
Browser state is managed with cookies, so you need to be sending a Set-Cookie header with the 302 that has $request_uri and then convert the cookie to a header in the /login/ location.
I've an nginx web server that proxy pass traffic to different services on my LAN. After a recent update of one of those services the redirect stop working as expected. The service behind the redirect is Pi-Hole so I can't/wan't modify how the web service works. I just want to fix the redirect.
My actual nginx configuration looks like this:
server {
listen 80;
listen [::]:80;
server_name servername.xyz localhost default;
access_log /var/log/nginx/servername-xyz.access.log;
error_log /var/log/nginx/servername-xyz.error.log;
location = /pihole {
return 301 http://servername.xyz/pihole/admin;
}
location = /pihole/ {
return 301 http://servername.xyz/pihole/admin;
}
location /pihole/ {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://127.0.0.1:31480/;
}
location = / {
return 418;
}
}
This configuration was working perfectly. Every time I write in my browser http://servername.xyz/pihole, I automatically get the redirect to http://servername.xyz/pihole/admin and start using the Pi-Hole web console flawless.
With the last Pi-Hole update, they make a small change that broke the redirect. Now every time you ask for http://pi-hole.domain/admin the web console is automatically redirected to http://pi-hole.domain/admin/. Note the slash at the end of the second URL.
In my configuration, that means the following behaviour:
I ask the browser for http://servername.xyz/pihole
I get the 301 and go to http://servername.xyz/pihole/admin
Here I get a redirect that I don't expect from the Pi-Hole web console that makes me go to: http://servername.xyz/admin/. Note the ending slash.
When I get to the third step, the redirect doesn't allow me to get into the Pi-Hole web console. I've tried some changes to the rules, but I didn't succeed in my objective to get a 301 towards http://servername.xyz/admin/ to avoid the Pi-Hole web console redirect.
Big thanks to Richard's Smith comment. It let me fix the configuration file. Now the proxy_pass action in the file looks like:
location /pihole/ {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://127.0.0.1:31480/;
proxy_redirect http://servername.xyz/admin/ http://servername.xyz/pihole/admin/;
}
After including the proxy_redirect directive, things start working again.
im trying to mock sites from my own FS. i want to intercept any http request and redirect it to my server that will return the needed file.
i have wrote a simple default sever:
server {
listen <<SERVICE_PORT>> default_server;
server_name _;
location / {
proxy_set_header X-ORIGINAL-URI $request_uri;
proxy_set_header X-ORIGINAL-REFERRER $http_referer;
proxy_set_header X-ORIGINAL-HOST $http_host;
proxy_pass <<BROWSE_RESOURCE_URL>>/browsing/resource/;
proxy_redirect off;
}
}
when a url as "http://exapmle.com" enters it works fine. but when any path is added as "http://exapmle.com/bar" it dose not pass the to <<BROWSE_RESOURCE_URL>>/browsing/resource/. currently i recive 404 but not from my server.
offcurce i dont need the orignal uri to be concated to my proxy_pass at all.
why dosent it work for me?
From Nginx's documentation:
A request URI is passed to the server as follows:
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
So, for your given configuration, when you request http://example.com/bar:
The normalized request URI will be /bar
The URI specified in the proxy_pass directive will be /browsing/resource/
The final URI that will be passed to the backend server is /browsing/resource/bar.
You have not configured the backend server to understand /browsing/resource/bar. So it only understands /browsing/resource/. That's why your backend server returned a 404 not found.
Because you don't want Nginx to combine the request URI with the URI specified in the proxy_pass directive, you can use another feature of the proxy_pass directive as mentioned in the Nginx's documentation:
When the URI is changed inside a proxied location using the rewrite directive, and this same configuration will be used to process a request (break):
...
In this case, the URI specified in the directive is ignored and the full changed request URI is passed to the server.
So you will instruct Nginx to rewrite all request URIs to the same URI /browsing/resource/ as follows:
location / {
proxy_set_header X-ORIGINAL-URI $request_uri;
proxy_set_header X-ORIGINAL-REFERRER $http_referer;
proxy_set_header X-ORIGINAL-HOST $http_host;
rewrite ^ /browsing/resource/ break;
proxy_pass <<BROWSE_RESOURCE_URL>>;
proxy_redirect off;
}
Foreword
In the main body of the question, the problem is described incorrectly. The correct explanation is described in the UPDATE block. Old text saved for history.
My project consists of two parts: backend and frontend. The following locations are responsible for redirecting requests:
location / {
root /opt/site/;
try_files $uri $uri/ /index.html;
}
location /adminpanel {
proxy_pass http://192.168.1.4:4567;
}
location /api {
proxy_pass http://192.168.1.4:4567;
}
The challenge is to redirect users to url /auth if there is no user login in the $remote_user header.
I tried to make the following construction:
in http I added:
map $remote_user $var {
default 0;
"" 1;
}
And in location / added:
if ($var) {
return 301 http://$server_name/auth;
}
When I try to enter the site, I get an error in my browser:
ERR_TOO_MANY_REDIRECTS
How do I fix my configuration file?
Thanks in advance!!!
UPDATE
My task is to configure Kerberos authentication on nginx. The backend is django. The idea is that when a request is made to api, nginx should perform kerberos authentication. But in case the user is not in the domain, then a redirect to the /auth authorization page must occur, so that the user can authenticate under an account that is registered in django CMS.
Authentication of domain users is successful. But there is a problem with non-domain users. When you open a site page that makes an api call, a basic authentication window appears. I use the auth_gss_allow_basic_fallback off directive, but this does not help.
How can I disable this and configure redirection to /auth?
My configuration file (I do not specify settings such as gzip, headers, etc.):
server {
listen 80;
server_name srv-01.example.com;
proxy_set_header remote-user $remote_user;
location / {
root /opt/site/;
try_files $uri $uri/ /index.html;
}
location /adminpanel {
proxy_pass http://192.168.1.4:4567;
}
location /api {
proxy_pass http://192.168.1.4:4567;
auth_gss on;
auth_gss_realm EXAMPLE.COM;
auth_gss_keytab /etc/krb5.keytab;
auth_gss_service_name HTTP/srv-01.example.com;
auth_gss_allow_basic_fallback off;
}}
I currently have the following proxy pass definition in my nginx config file :
location /pass/ {
proxy_pass http://localhost:9999/pass/;
proxy_redirect off;
proxy_set_header Host $host;
}
This is working as expected - /pass requests are forwarded to the app running on port 9999.
Now, what I want to do is make the port forwarding part dynamic as follows :
location /pass/<input> {
{a $port variable here that is evaluated via a script (php?)}
proxy_pass http://localhost:$port/pass/;
proxy_redirect off;
proxy_set_header Host $host;
}
Requests to /pass/ABCD1234 should be forwarded to port 9898 and Requests to /pass/ABCD5678 should be forwarded to port 9797.
Note that the flow is dynamic - so, the mapping from ABCD1234 to 9898 should happen through some sort of scripting (PHP maybe?) and based on the output of the script (a port) the proxy_pass should forward the request to that port.
Please Help in this regard.
UPDATE :
Instead of getting the proxy_pass port from URI input, I would like to get this going with a cookie. So, here is the updated code block :
location /pass/ {
add_header X-debug-message $host always;
add_header X-debug-message $cookie_sdmport;
set $proxyurl http://127.0.0.1:$cookie_theport/pass/;
add_header X-debug-message $proxyurl;
proxy_pass $proxyurl;
proxy_redirect off;
proxy_set_header Host $host;
}
With this code, there is looping 301 redirect back to the browser. The moment I switch back to static port, it works again! strange! The $proxyurl in the X-debug-message looks correct on the browser. So, wondering why proxy_pass is doing a 301!
UPDATE 2:
Finally got the forwarding working with following setup:
set $targetIP 127.0.0.1;
set $targetPort $cookie_passport;
proxy_pass http://$targetIP:$targetPort$request_uri;
Not sure why the solution as posted in above keeps spinning with a 301 - I guess nginx does not like mixing dynamic and static parts in the proxy_pass param
Thank You.
You can do this using the auth_request module. It's not built by default though, you can find out if you have it by running the following:
nginx -V 2>&1 | grep -qF -- --with-http_auth_request_module && echo ":)" || echo ":("
If you see a smiley face then you are good to go.
location ~* /pass/(.*) { <- regex capture for your variable
auth_request /auth; <- location to process request
auth_request_set $proxyurl http://localhost:$upstream_http_x_port/pass/; <- set $proxyurl using value returned in x-port header of your php script
add_header x-my-variable $1; <- Pass variable from regex capture to auth location
proxy_pass $proxyurl;
}
Then a location to handle the auth subrequests:
location /auth {
internal; <- make location only accessible to internal requests from Nginx
proxy_set_header x-my-variable $http_x_my_variable; <- pass variable to php
proxy_pass_request_body off; <- No point sending body to php
proxy_set_header Content-Length "";
proxy_pass http://your-php-script/file.php;
}
This module is actually meant for access control, so if your php script returns response code 200 then client will be allowed access, if it returns 401 or 403 then access will be denied. Is you dont care about that then just set it to always return 200.
Do whatever evaluation you need and have your php return the port in the header defined earlier:
header('X-Port: 9999');
This now sets the variable for your proxy_pass directive port number and Nginx does the rest.