This is a short article on how to make Apache, Nginx, and SSL work together.

I was going to run a blog at using WordPress and under SSL. The hosting of the blog is configured so that Nginx is a reverse proxy for an Apache-managed WordPress.

The Nginx configuration is as follows:

server {
   listen 80;
   listen [::]:80;
   return 301 https://$server_name$request_uri;

server {
    listen 443 ssl;

    ssl_certificate /etc/ssl/certs/;
    ssl_certificate_key /etc/ssl/private/;

    ssl on;
    ssl_session_cache  builtin:1000  shared:SSL:10m;
    ssl_protocols  TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;
    ssl_prefer_server_ciphers on;

    access_log            /var/log/nginx/;
    error_log             /var/log/nginx/;

    location / {
        proxy_pass http://my_ip_address:8080;
        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-Port 443;
        proxy_read_timeout  90;
        proxy_redirect      http://localhost:8080;

The upper part of the Nginx config listens to HTTP requests and redirects them squarely to the secure site. The secure site listens to incoming requests over the port 443 and passes them on to the Apache.

Apache listens to the non-secure port 8080. The Apache VirtualHost config is this:

        ErrorLog /var/log/apache2/www.example.com_error.log
        LogLevel warn
        CustomLog /var/log/apache2/www.example.com_access.log vhost_combined
        DocumentRoot /var/www/

        SetEnv HTTPS 1
                Options FollowSymLinks
                AllowOverride All
                Order allow,deny
                Allow from all

The problem I had after getting this setup to run was that WordPress refused to see that it was working in SSL content. Since Apache is listening to the unsecure port, the server variables $_SERVER['HTTPS'] and $_SERVER['SERVER_PORT'] do not have values on and 443 respectively.

Because of this, half the links are rendered with the http schema and the mixed content doesn’t work. The function is_ssl() that makes this check, is located in wp-includes/load.php:

function is_ssl() {
	if ( isset( $_SERVER['HTTPS'] ) ) {
		if ( 'on' == strtolower( $_SERVER['HTTPS'] ) ) {
			return true;

		if ( '1' == $_SERVER['HTTPS'] ) {
			return true;
	} elseif ( isset( $_SERVER['SERVER_PORT'] ) && ( '443' == $_SERVER['SERVER_PORT'] ) ) {
		return true;
	return false;

I tried first manipulating the server variables directly in wp-config.php , setting them like this:

$_SERVER['HTTPS'] = 'on';

This did not work as I expected. The link rendering worked fine, but the admin area refused to let me in under the admin account showing the error message:

Sorry, you are not allowed to access this page.

This was because the user variable was losing its “capabilites” parameters. I could not figure out exactly where and how, but that was it. In some part of the request timeline the user instance was OK, then suddenly it was not having any capabilites.

Fortunately, I can set server variables in the VirtualHost config using the SetEnv function. So I tweaked the Apache VirtualHost config like this:

 CustomLog /var/log/apache2/www.example.com_access.log vhost_combined
        DocumentRoot /var/www/

        SetEnv HTTPS 1


After this change, the setup started working as I needed it to.


Gilles · January 17, 2023 at 5:09 pm

Thanks !!!!
It works, only this line : SetEnv HTTPS 1

WP with Nginx SSL proxypass — MySprav · March 24, 2022 at 6:47 pm

[…] Я нашел решение в этой статье […]

Leave a Reply

Avatar placeholder

Your email address will not be published. Required fields are marked *