Serve php-fpm via nginx for a specific path in URL defaulting to static content

5,621

After spending a considerable amount of time trying to get a working config I seem to have finally managed to do it.

I can now perform requests to http://monkey.com/some/angular/path or http://monkey.com/api/users and serve both, static content or a PHP site respectively, from the same domain.

In case someone stumbles upon this question, here's the config that I've ended up with:

server {
    listen      80;
    server_name monkey.com;

    location / {
        alias     /var/www/website/;
        try_files $uri $uri/ /index.html =404;
    }

    location /api/ {
        alias     /var/www/api/public;
        try_files /index.php =404;

        set $path $request_uri;
        if ($request_uri ~ ^/api/(.*)$ ) {
            set $path /$1;
        }

        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass            unix:/var/run/php5-fpm.sock;
        fastcgi_index           index.php;

        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root/index.php;
        fastcgi_param REQUEST_URI     $path;                                                                                                                                                                                                                                        
    }
}

The configuration above strips the /api/ prefix and sets REQUEST_URI to whatever followed it. E.g. if you requested monkey.com/api/users/1 you would end up passing /users/1 to php-fpm.

If you don't need to modify the original request URI in any way and just want to pass the whole request URI to PHP you can simplify (and possibly speed up) the configuration as follows:

server {
    listen      80;
    server_name monkey.com;

    location / {
        alias     /var/www/website/;
        try_files $uri $uri/ /index.html =404;
    }

    location /api/ {
        alias     /var/www/api/public;
        try_files /index.php =404;

        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass            unix:/var/run/php5-fpm.sock;
        fastcgi_index           index.php;

        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root/index.php;
    }
}

Now on to setting up a Guzzle project for the proxy website!

Share:
5,621

Related videos on Youtube

Andris
Author by

Andris

Full stack React, PHP and .NET Core developer.

Updated on September 18, 2022

Comments

  • Andris
    Andris over 1 year

    I'm trying to run two websites on the same hostname where one serves static content (an AngularJS application) and the other one routes all requests to PHP (API written using Apigility) but only for a specific path in the URL (more on that later).

    At the moment I have two nginx vhosts listening on two different domains, which works just fine, however the client application will eventually be authenticating against the API using OAuth and I don't want to store tokens or any other sensitive data in client's cookies, local storage or anywhere else. This article explains the reasoning behind it better than I could explain myself.

    With that problem in mind I've decided to have a "proxy" server, which will by default (important) serve any static content that the client browser requests, however if a request comes in that starts with /api/ then it should be rerouted to php-fpm.

    To give you an example, let's assume the API has an endpoint /users. What I want to be able to do is run my AngularJS application as I normally would, e.g. on http://monkey.com/index.html but at the same time if I perform an AJAX request to http://monkey.com/api/users it should forward the /users bit to PHP, which will be installed in a different directory (for the sake of this question assume that AngularJS app is installed in /var/www/website and the API is in /var/www/api.

    These are the two configs that I have at the moment and which work as separate websites:

    AngularJS application config:

    server {
        listen      80;
        server_name monkey.com;
    
        root        /var/www/website;
        index       index.html
    
        location / {
            try_files $uri $uri/ /index.html =404;
        }
    }
    

    API config:

    server {
        listen      80;
        server_name api.monkey.com;
    
        root        /var/www/api/public;
        index       index.php
    
        include     /etc/nginx/fcgiwrap.conf;
    
        location / {
            try_files $uri $uri/ /index.php$is_args$args;
        }
    
        location ~ \.php$ {
            try_files $uri =404;
            fastcgi_split_path_info ^(.+\.php)(/.+)$;
            fastcgi_pass unix:/var/run/php5-fpm.sock;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            fastcgi_index index.php;
            include fastcgi_params;
        }
    }
    

    To avoid confusion I won't post my failed attempts but I can only say that I've tried using root and alias to no avail. I guess my biggest issue is I'm not sure how to extract only the part that comes after /api and forward it to PHP, which, to complicate matters, is in a different directory to $document_root.

    I've seen quite a few articles and answers on SO mentioning that having root inside a location entry is not a good idea but I don't think this can be solved without doing it.

    I've been fighting with this seemingly simple problem for a while now so I hope that someone can give an example of a config that actually works.