3

I have an Nginx with Docker for my development environment with HTTP and HTTPS, here's the configuration:

listen 80;
listen 443 ssl;

set_real_ip_from 10.0.0.0/8;
real_ip_header X-Real-IP;
real_ip_recursive on;

location / {
    try_files $uri @rewriteapp;
}

location @rewriteapp {
    rewrite ^(.*)$ /app.php/$1 last;
}

location ~ ^/(app|app_dev|app_test|config)\.php(/|$) {
    fastcgi_pass php-upstream;
    fastcgi_split_path_info ^(.+\.php)(/.*)$;
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_param HTTPS $https;
}

I want to test HTTP and HTTPS in my local environment but in production, I have an Nginx reverse proxy in front with:

upstream app_upstream {
  server app:80;
}

server {
server_name $APP_DOMAIN;

listen 443 ssl;
ssl_certificate /run/secrets/app_cert.pem;
ssl_certificate_key /run/secrets/app_key.pem;

proxy_set_header HOST $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

location / {
    proxy_pass http://app_upstream;
}
}

I want the reverse proxy to accept the only HTTPS and forward to the application nginx but my PHP application behind is receiving $_SERVER['HTTPS'] = ""

I also want to keep the SSL certificate only on the reverse proxy, how do I pass HTTPS from reverse proxy to Nginx to PHP?

2 Answers 2

3

The HTTPS variable is set to $https (which is set according to the connection to the backend server, which will always be HTTP), but you want it to be set according to the forwarded connection.

You can use the X-Forwarded-Proto header to set the HTTPS variable using a map. For example:

map $http_x_forwarded_proto $https_flag {
    default off;
    https on;
}
server {
    ...
    location ~ ^/(app|app_dev|app_test|config)\.php(/|$) {
        ...
        fastcgi_param  HTTPS  $https_flag;
        ...
    }
}

See this document for more.

Sign up to request clarification or add additional context in comments.

Comments

0

I just had to deal with the same troubles perhaps.

My main goal was to use one physical server for several websites. Each website would have wordpress hosted by it's own nginx server, living inside it's own Ubuntu container.

To keep those all silo'd, I wanted them all behind an Nginx reverse proxy, which also lives on a separate container.

The usual LEMP installations were easy enough on the Ubuntu containers, although I found that the current LXC ubuntu image includes Apache2 .. sudo apt remove apache2 was the fix for that one.

To enable HTTPS, the Certbot installation only needs to be done on your reverse proxy, which will then provide certificates valid for all of your domains.

There were 2 special steps to facilitate the Nginx reverse proxy:

1 - On your 'reverse proxy' container, headers like the following need to be included in your server {} block in each of your /etc/nginx/sites-enabled/yourDetailedSites files: (I've left the # comments on the individual fields that I'm not sure are required or not)

#######################################################################
server {
  server_name your.example.domain;

  location / {
    # proxy_pass_header Authorization;
    proxy_pass http://xx.xx.xx.xx:80;
    # proxy_redirect off;
    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-Host $server_name;
    # proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-Proto https;
  }

    listen 443 ssl; # managed by Certbot
    ... there will be more in here after the Certbot installation ...
}

server {
    if ($host = your.example.domain) {
        return 301 https://$host$request_uri;
    } # managed by Certbot

  server_name your.example.domain;
    listen 80;
    return 404; # managed by Certbot
}
#######################################################################

2 - Within your individual containers acting as each of the proxy_pass recipients, once wordpress is installed, you need to edit your wp-config.php file to include the following code. This needs to be customized for your.domain.name vs 'www.mydomain.com' and you'll need to add this just below the 'salts' area, but before the php really gets going.

////////////////////////////////////////////////////////////////
define('.COOKIE_DOMAIN.', 'my.example.org');
define('.SITECOOKIEPATH.', '.');

if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
        $list = explode(',',$_SERVER['HTTP_X_FORWARDED_FOR']);
        $_SERVER['REMOTE_ADDR'] = $list[0];
  }
define( 'WP_HOME', 'https://my.example.org' );
define( 'WP_SITEURL', 'https://my.example.org' );
$_SERVER['HTTP_HOST'] = 'my.example.org';
$_SERVER['REMOTE_ADDR'] = 'https://my.example.org';
$_SERVER[ 'SERVER_ADDR' ] = 'my.example.org';

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

Once I did the above, I was able to use the '5 minute sign-in' and edit my wordpress sites.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.