Use a different PHP Upstream based on arguments in the URL - NGinx
I run Nginx and PHP-FPM. Nginx runs under www-data and PHP-FPM runs as a separate user for each website. I use Nginx FASTCGI Caching and use the Nginx Helper plugin for WordPress. Unfortunately due to the difference in user we can't use the "Purge All" function in the plugin as the php user doesn't have access to the cache.
Changing permissions isn't an option due to security.
What I want to do is use a different PHP-FPM Pool if the below argument exists in the URL.
nginx_helper_urls=all
My current NGinx Config is below:
upstream examplebackend {
server unix:/var/run/php-fcgi-example.sock;
}
upstream cachedeletebackend {
server unix:/var/run/php-fcgi-cachedelete.sock;
}
server {
listen 80 default;
server_name www.example.com;
return 301 https://www.example.com$request_uri;
}
server {
listen 80;
server_name example.com;
return 301 https://www.example.com$request_uri;
}
server {
listen 443 ssl;
server_name example.com;
return 301 https://www.example.com$request_uri;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
}
server {
listen 443 ssl;
ssl_protocols TLSv1.2 TLSv1.3;
server_name www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
access_log /home/examplecom/logs/example.com.access.log;
error_log /home/examplecom/logs/example.com.error.log;
root /home/examplecom/public_html;
index index.php;
set $skip_cache 0;
# POST requests and urls with a query string should always go to PHP
if ($request_method = POST) {
set $skip_cache 1;
}
if ($query_string != "") {
set $skip_cache 1;
}
# Don't cache uris containing the following segments
if ($request_uri ~* "/wp-admin/|/xmlrpc.php|wp-.*.php|/feed/|index.php|sitemap(_index)?.xml") {
set $skip_cache 1;
}
# Don't use the cache for logged in users or recent commenters
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") {
set $skip_cache 1;
}
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
try_files $uri =404;
include fastcgi_params;
if ( $args ~ nginx_helper_urls=all ) { fastcgi_pass cachedeletebackend; }
fastcgi_pass examplebackend;
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
fastcgi_cache WORDPRESS;
fastcgi_cache_valid 60m;
}
location ~ /purge(/.*) {
fastcgi_cache_purge WORDPRESS "$scheme$request_method$host$1";
}
location ~* ^.+\.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
access_log off; log_not_found off; expires max;
}
location = /robots.txt { access_log off; log_not_found off; }
location ~ /\. { deny all; access_log off; log_not_found off; }
}
Not sure where I am going wrong or if it is even possible. Thanks
This likely happens because If is evil.
In nginx, most of the if
statements should be implemented with map
feature instead.
In your case, first define the map
in http
level:
map $arg_nginx_helper_urls $backend {
all cachedeletebackend;
default examplebackend;
}
Then, in PHP location
block use:
location ~ \.php$ {
try_files $uri =404;
include fastcgi_params;
fastcgi_pass $backend;
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
fastcgi_cache WORDPRESS;
fastcgi_cache_valid 60m;
}
The map will assign a value to $backend
variable depending on query argument nginx_helper_urls
value. By default, examplebackend
is used. If the argument value is all
, then cachedeletebackend
is assigned to the variable.