Is it possible to have nginx load balance to multiple container based on location?

Currently trying to set up a micro service load balancer based on location rather than domain and having some issues setting it up in nginx, mainly because nginx seems to require the source code as well as my php-fpm container even though there are no static files.

Current example which works without issue:

server {
    charset utf-8;
    client_max_body_size 128M;

    listen 80 default;
    server_name localhost;

    root /var/www/public;
    index index.php;

    location / {
        try_files $uri $uri/ /index.php?_url=$uri&$args;
    }

    location ~ \.php {
        try_files   $uri =404;

        fastcgi_pass  php:9000;
        fastcgi_index index.php;

        include fastcgi_params;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_param PATH_INFO $fastcgi_path_info;
        fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }

    location ~ /\.ht {
        deny all;
    }
}

However, I’d ideally like to have my nginx container load balance across different containers based on the location.

server {
    listen 80 default;
    server_name localhost;

    location /test {
        # php container 1
    }
    
    location /test2 {
        # php container 2
    }
    
    location /test3 {
        # php tonainer 2
    }
    
    # some form of catch all
}

Is this something that’s possible or am I trying to do something ridiculous?

Thanks,
Gary

The only way I can think of doing this at the moment (but haven’t had time to test) is have each PHP FPM process have their own nginx container and then using proxy_pass to them.

Never mind, figured it out.

upstream test {
    server nginx-test;
}

server {
    location / {
        return 404;
    }

    location /test {
        rewrite ^/test/(.*)$ /$1 break;
        proxy_pass http://test;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
    }
}

This is using swarm mode?

No, I started down that route but couldn’t seem to quite get it right.
Based on the docs, as I’m using OSX it’s still a little bit complicated and have to use Virtual Box.

I will probably try again at some point to use Swarm.

I just tried getting a similar setup to work but found the solution with

rewrite ^/test/(.*)$ /$1 break;

rather hacky, so I investigated a bit further. It turns out that if you append the proxy_pass URI with a ‘/’, Nginx will treat the proxy_pass address as a URI rather than a host:port mapping, and redirect all requests made to location to that URI. This worked for me:

upstream test1 {
    server test-container1;
}

upstream test2 {
    server test-container2;
}

server {
    listen 80;
    server_name myhost;
    
    location / {
        return 404;
    }

    location /test1/ {
        proxy_pass http://test1/;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
    }

    location /test2/ {
        proxy_pass http://test2/;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
    }
}

This way, a request to myhost:80/test1/ gets forwarded to http://test1/ and a request to myhost:80/test2/ gets forwarded to http://test2/.