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.