Opened 13 months ago

Last modified 13 months ago

#2477 new enhancement

proxy_redirect is missing feature for HTTP header "Link"

Reported by: jochenwezel@… Owned by:
Priority: critical Milestone:
Component: nginx-core Version: 1.18.x
Keywords: Cc: jochenwezel@…
uname -a: Linux revproxy02 5.15.0-69-generic #76-Ubuntu SMP Fri Mar 17 17:19:29 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
nginx -V: nginx version: nginx/1.18.0 (Ubuntu)
built with OpenSSL 3.0.2 15 Mar 2022
TLS SNI support enabled
configure arguments: --with-cc-opt='-g -O2 -ffile-prefix-map=/build/nginx-d8gVax/nginx-1.18.0=. -flto=auto -ffat-lto-objects -flto=auto -ffat-lto-objects -fstack-protector-strong -Wformat -Werror=format-security -fPIC -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-Bsymbolic-functions -flto=auto -ffat-lto-objects -flto=auto -Wl,-z,relro -Wl,-z,now -fPIC' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-compat --with-debug --with-pcre-jit --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --add-dynamic-module=/build/nginx-d8gVax/nginx-1.18.0/debian/modules/http-geoip2 --with-http_addition_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_sub_module

Description (last modified by jochenwezel@…)

PLEASE NOTE: please ignore space chars in urls in following ticket (I had to "remove" all external links to be able to post this ticket, here: "Maximum number of external links per post exceeded")

Used configuration

Given is a reverse proxy configuration like

location / {
    proxy_pass     https :// upstream/;
    proxy_redirect https :// upstream/ /;
}

As the documentation at https :// nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_redirect explains, proxy_redirect will change Location headers redirect. This is required and good and works.

HTTP Response of upstream server

My wordpress 6 system now starts to send HTTP responses like:

HTTP/1.1 200 OK
Server: nginx/1.18.0 (Ubuntu)
Date: Wed, 29 Mar 2023 15:31:02 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Link: <https :// upstream/index.php/wp-json/>; rel="https://api.w.org/"
Link: <https :// upstream/index.php/wp-json/wp/v2/pages/69>; rel="alternate"; type="application/json"
Link: <https :// upstream/>; rel=shortlink
Vary: Accept-Encoding
Content-Encoding: gzip

HTTP protocol standard

Since I've never seen this type of 'link' header before, this was a real surprise to me. But it seems that it's a feature which exists for many years, now: https :// www.w3.org/wiki/LinkHeader

Problem description

The problem is, that the many Link headers remain unchanged and are delivered (as they are) to the client. Of course, the client machine doesn't know anything about my upstream server and can't access it to load these linked urls.

The result is, that my nginx reverse proxy response to the client contains unchanged Link headers

Link: <https :// upstream/index.php/wp-json/>; rel="https://api.w.org/"
Link: <https :// upstream/index.php/wp-json/wp/v2/pages/69>; rel="alternate"; type="application/json"
Link: <https :// upstream/>; rel=shortlink

Feature request

So, proxy_redirect should (by default) substitute in headers

  • Location
  • Link [array]

Optionally, the substitution of Link headers could be configured with another switch (e.g. proxy_redirect_links) to on|off|default

Change History (5)

comment:1 by jochenwezel@…, 13 months ago

Description: modified (diff)

comment:2 by jochenwezel@…, 13 months ago

Description: modified (diff)

comment:3 by jochenwezel@…, 13 months ago

Description: modified (diff)

comment:4 by jochenwezel@…, 13 months ago

Description: modified (diff)

comment:5 by Maxim Dounin, 13 months ago

Note that there are a lot of ways how backend servers can sent various links to the client, including response headers and the response body. In general it is not possible to change all the links, and nginx only tries to support the most common use cases - such as the Location header (proxy_redirect) and Set-Cookie headers (proxy_cookie_domain, proxy_cookie_path, proxy_cookie_flags). Instead of using nginx to rewrite links, a better approach is to configure your backend server to send the correct links.

If configuring your backend server to return correct links is not an option, an immediately available solution for the Link header might be to use the proxy_hide_header directive to hide such incorrect links.

Alternatively, headers can be removed with proxy_hide_header and re-added with modifications by something like this (assuming up to 3 Link headers):

map $upstream_http_link $rewritten1_link {
    ~^(.*)https://upstream/(.*)$ $1https://example.org/$2;
    default $upstream_http_link;
}

map $rewritten1_link $rewritten2_link {
    ~^(.*)https://upstream/(.*)$ $1https://example.org/$2;
    default $rewritten1_link;
}

map $rewritten2_link $rewritten_link {
    ~^(.*)https://upstream/(.*)$ $1https://example.org/$2;
    default $rewritten2_link;
}

proxy_hide_header Link;
add_header Link $rewritten_link;

Note that this requires at least nginx 1.23.0 to properly handle multiple Link headers.

Having said that, it might still make sense to support easy rewriting of the Link headers, so keeping this feature request open for now.

Note: See TracTickets for help on using tickets.