I am trying to get NGINX to reverse proxy & provide SSL Termination for a WordPress site running on Apache at port 8086. I want NGINX to handle the static files, and proxy only PHP requests to Apache.
I have been successful in getting this to work using standard links. (i.e. https://example.com/?post=274 works correctly)
When I enable permalinks of any kind, the home page will load, as will wp-admin, but https://example.com/what-we-do/ fails.
Looking at the NGINX logs, I see
2018/05/23 09:36:40 [error] 7472#0: *1 "/var/www/example.com/live_site/what-we-do/index.php" is not found (2: No such file or directory), client: xxx.xxx.xxx.xxx, server: example.com, request: "GET /what-we-do/ HTTP/2.0", host: "example.com", referrer: "https://example.com/?post=274"
So NGINX is attempting to look for /permalink/index.php as a static path/file instead of passing to apache. Any thoughts on how to get this to work?
My NGINX Config looks like:
upstream example_apache {
ip_hash;
server 127.0.0.1:8086;
}
server {
# HTTP/HTTPS Server Block
# General Config
listen [::]:80;
listen 80;
listen [::]:443 http2 ssl;
listen 443 http2 ssl;
server_name example.com
www.example.com;
root /var/www/example.com/live_site;
access_log /var/log/nginx/access-example.com.log main;
error_log /var/log/nginx/error-example.com.log;
index index.php;
#SSL Cert Configuration
# Check SSL config at https://www.ssllabs.com/ssltest/
ssl_prefer_server_ciphers on;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers "ECDHE-ECDSA-CHACHA20-POLY1305 ECDHE-RSA-CHACHA20-POLY1305 EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH DHE-RSA-CHACHA20-POLY1305 EDH+aRSA !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS !RC4 !SEED !CAMELLIA";
ssl_session_cache shared:SSL:100m;
ssl_session_timeout 180m;
ssl_dhparam /var/www/certs/dh4096.pem;
ssl_certificate /var/www/certs/lets_encrypt/web01.example.com/web01.example.com.fullchain.secp384r1.cer;
ssl_certificate_key /var/www/certs/lets_encrypt/web01.example.com/web01.example.com.secp384r1.key;
ssl_certificate /var/www/certs/lets_encrypt/web01.example.com/web01.example.com.fullchain.rsa4096.cer;
ssl_certificate_key /var/www/certs/lets_encrypt/web01.example.com/web01.example.com.rsa4096.key;
# Enable HSTS #Deploy in stages to prevent extended loss to site.
add_header Strict-Transport-Security "max-age=300; includeSubdomains;"; #300s-5min TTL Testing
#add_header Strict-Transport-Security "max-age=604800; includeSubdomains;"; #1week TTL Testing
#add_header Strict-Transport-Security "max-age=2592000; includeSubdomains;"; #1month TTL Testing
#add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"; #10886400s-126days Min for Preload
#add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"; #63072000s-2years Production Value
# OCSP Configuration
ssl_trusted_certificate /var/www/certs/lets_encrypt/web01.example.com/web01.example.com.fullchain.secp384r1.cer;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.4.4 8.8.8.8 valid=300s;
resolver_timeout 10s;
# LetEncrypt webroot alias
location /.well-known/acme-challenge/ {
alias /var/www/le_root/.well-known/acme-challenge/;
}
# www to non-www rewrite
# Redirect to the correct place, if needed
set $https_redirect 0;
if ($server_port = 80) { set $https_redirect 1; }
if ($host ~ '^www\.') { set $https_redirect 1; }
if ($https_redirect = 1) {
return 301 https://example.com$request_uri;
}
# Wordpress entry point
location / {
#Try file dir index.php else 404
try_files $uri $uri/ /index.php?$args =404;
#All Files except for *.php
location ~ .+(?<!\.php)$ {
location ~ ^[^.]+\.[^.]+$ {
expires max;
add_header Cache-Control public;
break;
}
}
#Only *.php files
location ~ \.php$ {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass_header Set-Cookie;
proxy_set_header SSL_PROTOCOL $ssl_protocol;
proxy_set_header SSL_CLIENT_CERT $ssl_client_cert;
proxy_set_header SSL_CLIENT_VERIFY $ssl_client_verify;
proxy_set_header SSL_SERVER_S_DN $ssl_client_s_dn;
proxy_pass http://example_apache;
}
}
}
Since this issue isnt even getting to the proxy pass part, and appears to be strictly NGINX related (that I can tell), the following doesnt apply. But someone will be wondering, or it may help others stumbling on this question to know the apache config side as well.
My apache has an .htaccess file containing:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
And my wp-config.php has:
// If WordPress is behind reverse proxy
// which proxies https to http
if ( (!empty( $_SERVER['HTTP_X_FORWARDED_HOST'])) ||
(!empty( $_SERVER['HTTP_X_FORWARDED_FOR'])) ) {
$_SERVER['HTTP_HOST'] = $_SERVER['HTTP_X_FORWARDED_HOST'];
$_SERVER['HTTPS'] = 'on';
}
And my apache config has:
<VirtualHost *:8086>
ServerAdmin webmaster@localhost
DocumentRoot /var/www/example.com/live_site
ServerName example.com
ServerAlias www.example.com
ErrorLog ${APACHE_LOG_DIR}/example.com.error.log
CustomLog ${APACHE_LOG_DIR}/example.com.access.log combined
Alias "/.well-known/acme-challenge/" "/var/www/le_root/.well-known/acme-challenge/"
<Directory />
Options FollowSymLinks
AllowOverride None
</Directory>
<Directory /var/www/example.com/live_site>
Options Indexes FollowSymLinks MultiViews
AllowOverride All
Order allow,deny
allow from all
</Directory>
</VirtualHost>
I should also note, when I connect directly to Apache I can see all of the page permalinks correctly. (i.e. http://127.0.0.1:8086/what-we-do/ works correctly)
NGINX version 1.13.9
Apache 2.4.33 mpm_prefork
PHP version 7.1
Any thoughts or help getting NGINX to correctly proxy permalinks to apache would be greatly appreciated!