Search code examples
nginxhttp-redirectjettyreverse-proxynginx-reverse-proxy

nginx reverse proxy redirects to http instead of https


Having the following setup: NGINX (Port 443) > Jetty (Port 9090) > Spring Controller

For simplifying the problem I use the following files:

  • /main.html containing an iframe calling the spring controller /test
  • spring controller /test doing return "redirect:/iframe.html";
  • /iframe.html with simple text saying "This is IFrame"

With HTTP there is no problem but after switching the NGINX configuration to HTTPS I get the following error in the browser and the iframe is not displayed:

main.html:7 Mixed Content: The page at 'https://dev/main.html' was loaded over HTTPS, but requested an insecure frame 'http://dev/iframe.html'. This request has been blocked; the content must be served over HTTPS.

So the controller redirects to http instead of https, this is my NGINX configuration which from my understanding should let the jetty/controller know that it is running on https:

 server {
    listen 443      ssl http2;
    listen [::]:443 ssl http2;
    server_name dev;

    ssl on;
    ssl_certificate ...;
    ssl_certificate_key ...;

    location / {
        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_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Port $server_port;
        
        proxy_ssl_name $host;
        proxy_ssl_server_name on;

        proxy_pass http://127.0.0.1:9090;
    }
}

Solution

  • You need to do a few things ...

    1. On the nginx side, Use the Standard Forwarded header from RFC7239, not the X-Forwarded-* headers. This is because the X-Forwarded-* headers are not a standard and conflict in meaning across their usage. (in your example, you made the port separate, which now conflicts with the "host", "proto", and "for" usages for the port as well)

    2. On the Jetty side, enable the ForwardedRequestCustomizer. This will look for the various Forwarding headers and update the request's authority, protos, and "is secure" flags appropriately.

    3. On the Jetty side, configure the HttpConfiguration.securePort to be the port for your SSL/TLS on your nginx, not the port that Jetty itself uses.