I have a setup that roughly looks like this (I have tried to simplify this as much as possible):

Port 443 - nginx listens and forwards to port 80, config looks something like this

server {
  listen 443 ssl;
  location / {
  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 https;
  proxy_set_header X-Forwarded-Port 443;
  proxy_set_header Host $host;

Port 80 - Varnish (reverse proxy) which forwards traffic to port 8080 unless there is a cache hit.

port 8080 nginx setup for PHP with fastcgi. I have some common config:

location ~ \.php$ {
  include fastcgi_params;

and fastcgi_params file which looks like this

fastcgi_param   HTTPS           $https if_not_empty;

What I've been trying to do is to create a setup, where nginx when listening on port 8080 is able to detect if it's serving content to http or https. It needs to tell this to PHP so it can create URLs with the correct scheme.

I was thinking that somewhere I should listen for the X-Forwarded-Proto and then tell nginx that https is turned on. I don't know how/where to make some kind of if statement or if something like this is even possible or how to tell nginx that https should be on.

  • You should use the protocol relative version of URLs in your application, like //serverfault.com/path/to/resource or path relative URL /path/to/resource. This makes browser request the resource with the protocol current page has loaded with. – Tero Kilkanen Sep 24 '17 at 16:36

You may solve this in two ways... at the application level or at the Nginx level.

At the application level

Since, it is a PHP application, you may use the following at the top of the code / application...

if ($_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') $_SERVER['HTTPS']='on';

At the Nginx level

Step 1: Map X-Forwarded-Proto to a variable whose value depends on X-Forwarded-Proto.

map $http_x_forwarded_proto $fastcgi_param_https_variable {
    default '';
    https 'on';

Step 2: Replace the existing line fastcgi_param HTTPS $https $if_not_empty with the following line that sets fastcgi_param HTTPS based on the above variable

fastcgi_param HTTPS $fastcgi_param_https_variable;

Personally, I prefer the first method since it requires just a single line to set things correctly. The second method should work too, but is not tested.

  • Note that not all PHP applications test $_SERVER['HTTPS'] the same. The PHP documentation says that a non-empty value means that the HTTPS protocol was used, but when I set this up for Phabricator, I found that it required the value to be true. So check your PHP application - setting it to 'on' may not work. – Peter Nov 24 '17 at 6:36
  • 1
    Important note! The map directive must be in the root of the http directive (it's usually in /etc/nginx/nginx.conf). Otherwise Nginx will fail to load the configuration. – Finesse Jan 16 '20 at 3:04
  • As mentioned by @Peter, I run with fastcgi_param HTTPS $fastcgi_param_https_variable if_not_empty; to make sure HTTPS is not passed unless it has a value. So far works well with WordPress – Christopher Janzon Sep 11 '20 at 22:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.