Score:0

Multiple php-fpm pools and nginx

be flag

I have a website which is built on Codeigniter 3. It is a typical nginx + php-fpm setup. Now I need to direct some of the requests to be handled by another php-fpm pool. Here is a simplified example of the configuration:

nginx configuration

test.conf:

server {
    server_name example.com;
    root /var/www/ci;
    index index.html index.php;

    location ~* \.(ico|css|js|gif|jpe?g|png)(\?[0-9]+)?$ {
        expires max;
        log_not_found off;
    }

    # Somehow send all requests starting with /test/ to /index.php 
    # but use 127.0.0.1:9001 instead of the default 127.0.0.1:9000

    #location /test/ {
    #   ...
    #}

    location / {
        try_files $uri $uri/ /index.php;
    }

    location ~* \.php$ {
        fastcgi_pass 127.0.0.1:9000;
        include fastcgi.conf;
    }
}

php-fpm configuration

www1.conf:

[www]
user = www-data
group = www-data
listen = 127.0.0.1:9000
listen.owner = www-data
listen.group = www-data
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3

www2.conf:

[www2]
user = www-data
group = www-data
listen = 127.0.0.1:9001
listen.owner = www-data
listen.group = www-data
pm = ondemand
pm.max_children = 5

How can I tell nginx to send every request starting with /test/ to the other pool (www2)?

Examples

Score:0
be flag

Looks like you can use nginx's map directive to achieve this.

First we add a map to the http block in nginx.conf:

http {
    # ...

    map $request_uri $upstream_port {
        default        9000;
        "~^/test($|/)" 9001;
    }

    # ...
}

We use a regular expression to check if the path starts with /test and select the php-fpm port number based on that.

Next we change test.conf to utilize this new variable:

server {
    server_name example.com;
    root /var/www/ci;
    index index.html index.php;

    location ~* \.(ico|css|js|gif|jpe?g|png)(\?[0-9]+)?$ {
        expires max;
        log_not_found off;
    }

    location / {
        try_files $uri $uri/ /index.php;
    }

    location ~* \.php$ {
        fastcgi_pass 127.0.0.1:$upstream_port; # <-- This changed
        include fastcgi.conf;
    }
}

I don't know if this will cause a significant performance penalty in the real world but in my synthetic tests the difference was fairly small. There might be a better way of doing this.

Score:0
us flag

This redirects all requests to PHP files under /test to another pool:

location ~*^/test/.+\.php$ {
    fastcgi_pass 127.0.0.1:9001;
    include fastcgi.conf;
}

To cover frameworks using front-controller pattern, this is needed:

location /test {
    root /path/to/webroot;
    try_files $uri $uri/ /test/index.php;
}
Steve avatar
be flag
Unfortunately this won't work. Codeigniter like many other PHP frameworks utilizes "clean URLs" which means that all the requests are routed through a single `index.php` which sits in the document root directory. If I try to direct a request from path /test/ to the index.php in root, nginx will fail configtest: `nginx: [emerg] location "/index.php" is outside location "/test/" in /etc/nginx/sites-enabled/test.conf:17`
us flag
I added the directives to cover front-controller pattern. The original question didn't mention front controllers, so I didn't know it was needed.
Steve avatar
be flag
If I add the new location block which should handle the front controller pattern, all the requests go to pool www1. Am I missing something?
us flag
That was my mistake, the `try_files` needs to have correct path to the index file.
Steve avatar
be flag
The problem is that there is no `/test/index.php`. In both cases (www1 & www2) the request should be directed to the same index.php file which is located in the document root (`/var/www/ci`).
I sit in a Tesla and translated this thread with Ai:

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.