0

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

Steve
  • 143
  • 1
  • 8

2 Answers2

0

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;
}
Tero Kilkanen
  • 36,796
  • 3
  • 41
  • 63
  • 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` – Steve Nov 17 '22 at 07:17
  • 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. – Tero Kilkanen Nov 17 '22 at 07:39
  • 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? – Steve Nov 17 '22 at 09:29
  • That was my mistake, the `try_files` needs to have correct path to the index file. – Tero Kilkanen Nov 17 '22 at 15:25
  • 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`). – Steve Nov 17 '22 at 15:54
0

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.

Steve
  • 143
  • 1
  • 8