Possible bug with "proxy_intercept_errors on;

F
  • 29 Jun '23
Hi...

I have one peculiar issue with NGINX 1.22.0 + "proxy_intercept_errors
on;" + custom 302 "error_page".

Here is my simplified NGINX config:

http {
  error_page 301 302 /30x.html;
  server {
    location /30x.html {
      root /etc/nginx/custom_error_pages;
      sub_filter_once off;
      sub_filter '*HTTP_STATUS_CODE*' '$status';
      internal;
    }
    location /mysystem {
      rewrite ^(.*)$ / break; # remove "/mysystem" and only send "/" to backend
      proxy_intercept_errors on;
      proxy_pass http://php_server;
    }
  }
}

Using both "proxy_intercept_errors on;" and "error_page" directive, I
have HTTP 302 response from my php backend server (OK!), but without
HTTP new "location" header:

$ curl -v https://foo/mysystem
...
< HTTP/2 302
< date: Thu, 29 Jun 2023 17:48:31 GMT
< content-type: text/html
< strict-transport-security: max-age=63072000
...

Why? If I turn off the "proxy_intercept_errors" directive or remove
the line "error_page 301 302 /30x.html;", it works:

$ curl -v https://foo/mysystem
...
< HTTP/2 302
< date: Thu, 29 Jun 2023 18:05:42 GMT
< content-type: text/html; charset=UTF-8
< location: https://bar
< strict-transport-security: max-age=63072000
...

Is this normal? Why can't I have a 302 custom error page using
"proxy_intercept_errors on;"?

Thanks in advance.
M
  • 29 Jun '23
Hello!

On Thu, Jun 29, 2023 at 04:29:39PM -0300, Fabiano Furtado Pessoa Coelho wrote:

> Hi...
> 
> I have one peculiar issue with NGINX 1.22.0 + "proxy_intercept_errors
> on;" + custom 302 "error_page".
> 
> Here is my simplified NGINX config:
> 
> http {
>   error_page 301 302 /30x.html;
>   server {
>     location /30x.html {
>       root /etc/nginx/custom_error_pages;
>       sub_filter_once off;
>       sub_filter '*HTTP_STATUS_CODE*' '$status';
>       internal;
>     }
>     location /mysystem {
>       rewrite ^(.*)$ / break; # remove "/mysystem" and only send "/" to backend
>       proxy_intercept_errors on;
>       proxy_pass http://php_server;
>     }
>   }
> }
> 
> Using both "proxy_intercept_errors on;" and "error_page" directive, I
> have HTTP 302 response from my php backend server (OK!), but without
> HTTP new "location" header:
> 
> $ curl -v https://foo/mysystem
> ...
> < HTTP/2 302
> < date: Thu, 29 Jun 2023 17:48:31 GMT
> < content-type: text/html
> < strict-transport-security: max-age=63072000
> ...
> 
> Why? If I turn off the "proxy_intercept_errors" directive or remove
> the line "error_page 301 302 /30x.html;", it works:
> 
> $ curl -v https://foo/mysystem
> ...
> < HTTP/2 302
> < date: Thu, 29 Jun 2023 18:05:42 GMT
> < content-type: text/html; charset=UTF-8
> < location: https://bar
> < strict-transport-security: max-age=63072000
> ...
> 
> Is this normal? Why can't I have a 302 custom error page using
> "proxy_intercept_errors on;"?

The "proxy_intercept_errors" handling does not copy any response 
headers from the original response (the only exception is 
WWW-Authenticate for 403 responses).

If you want nginx to copy some headers, consider doing it yourself 
with the $upstream_http_* variables and the add_header directive.  
Something like this should work:

    location /30x.html {
        add_header Location $upstream_http_location;
        ...
    }

Note though that you'll have to manually rewrite location if 
needed (as proxy_redirect handling won't be used).

-- 
Maxim Dounin
http://mdounin.ru/
F
  • 29 Jun '23
Thanks! I'm gonna try this approach.

On Thu, Jun 29, 2023 at 7:00 PM Maxim Dounin <mdounin at mdounin.ru> wrote:
>
> Hello!
>
> On Thu, Jun 29, 2023 at 04:29:39PM -0300, Fabiano Furtado Pessoa Coelho wrote:
...
>
> The "proxy_intercept_errors" handling does not copy any response
> headers from the original response (the only exception is
> WWW-Authenticate for 403 responses).
>
> If you want nginx to copy some headers, consider doing it yourself
> with the $upstream_http_* variables and the add_header directive.
> Something like this should work:
>
>     location /30x.html {
>         add_header Location $upstream_http_location;
>         ...
>     }
>
> Note though that you'll have to manually rewrite location if
> needed (as proxy_redirect handling won't be used).
F
  • 30 Jun '23
Hello Maxim...

On Thu, Jun 29, 2023 at 7:00 PM Maxim Dounin <mdounin at mdounin.ru> wrote:
>
> Hello!
>
> On Thu, Jun 29, 2023 at 04:29:39PM -0300, Fabiano Furtado Pessoa Coelho wrote:
>
> > Hi...
...
> > "proxy_intercept_errors on;"?
>
> The "proxy_intercept_errors" handling does not copy any response
> headers from the original response (the only exception is
> WWW-Authenticate for 403 responses).
>
> If you want nginx to copy some headers, consider doing it yourself
> with the $upstream_http_* variables and the add_header directive.
> Something like this should work:
>
>     location /30x.html {
>         add_header Location $upstream_http_location;
>         ...
>     }
>
> Note though that you'll have to manually rewrite location if
> needed (as proxy_redirect handling won't be used).

Your approach worked fine for me! Thanks for the help.

Horever, without this "add_header" modification and with
"proxy_intercept_errors on;", I've two situations:
* without "error_page 301 302 /30x.html;" directive configured: I
receive the HTTP "location" header from my NGINX;
* with "error_page 301 302 /30x.html;" directive configured: I don't
receive the HTTP "location" header from my NGINX;

If "proxy_intercept_errors" handling does not copy any response
headers from the original response, why is this HTTP "location" header
present with "error_page 301 302 /30x.html;" directive configured in
my system?

I really don't understand why it happens.

Well, thanks again.
Fabiano