nginxslimslim-4

Dynamic nginx root based on the first URL segment


First of all, I've searched across the SO and elsewhere, but looks like I just can't make this thing to work. I was "scraping" what other people tackled and trying to combine their solutions, but all I got was bunch of 404's and redirect loops. I have no idea if any of the attempts were close enough to be posted as an almost-working one.

This is a Slim 4 app if it matters, but actually it's supposed to serve multiple "sub-applications", based on specific configs that each of those apps will contain in their respective directories.

The project root is something like /var/www/project/instances and in that directory there will be multiple (generated) subdirectories, each of them having their own index.php (and some other files). Those subdirectories are supposed to act as "root" directories for each of those sub-apps:

/var/www/project/instances
|- /1/index.php
|- /2/index.php
|- /...
|- /N/index.php

The apps would sit at app.project.test/1, app.project.test/2, and so on. I have no problems running a specific "app" if I just hardcode the root, but this is supposed to be a dynamic solution.

The basic layout of the server config would be something like this:

server {
    listen 80;
    listen [::]:80;
    
    server_name app.project.test;
    
    root /var/www/project/instances;

    absolute_redirect off;

    index index.php;

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

    location ~ \.php$ {
        fastcgi_pass 127.0.0.1:9000;
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param SCRIPT_NAME $fastcgi_script_name;
        fastcgi_index index.php;
    }
}

Now, the problematic part is "routing" http requests to these subdirectories properly. Should the root be set dynamically based on the first segment in the URL? Should the try_files should handle that? Do fastcgi params need to be adjusted as well?


Solution

  • Figured it out along the way, using map to get the first URI segment and then just craft the root with it.

    map $request_uri $instance_id {
        ~^/(?<first_uri_segment>[^/?]+) $first_uri_segment;
    }
    
    server {
        listen 80;
        listen [::]:80;
        
        server_name app.project.test;
    
        absolute_redirect off;
    
        set $root_path /var/www/project/instances/$instance_id;
    
        if (!-d $root_path) {
            rewrite . http://projects.test redirect;
        }
        
        root $root_path;
    
        index index.php;
    
        location / {
            try_files $uri /index.php$is_args$args;
        }
    
        location ~ \.php$ {
            fastcgi_pass 127.0.0.1:9000;
            try_files $uri =404;
            fastcgi_split_path_info ^(.+\.php)(/.+)$;
            include fastcgi_params;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            fastcgi_param SCRIPT_NAME $fastcgi_script_name;
            fastcgi_index index.php;
        }
    }