This is a short article on how to make Apache, Nginx, and SSL work together.
I was going to run a blog at www.example.com 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; server_name www.example.com; return 301 https://$server_name$request_uri; } server { listen 443 ssl; server_name www.example.com; ssl_certificate /etc/ssl/certs/www.example.com.crt; ssl_certificate_key /etc/ssl/private/www.example.com.key; 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/www.example.com.access.log; error_log /var/log/nginx/www.example.com.error.log; 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 https://www.example.com; } }
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:
ServerName www.example.com ServerAlias example.com 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/www.example.com/webroot 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/www.example.com/webroot SetEnv HTTPS 1...
After this change, the setup started working as I needed it to.
2 Comments
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
[…] Я нашел решение в этой статье singularaspect.com/nginx-apache-ssl-and-wordpress/. […]