NGINX location fallback to Symfony - php

I'm working on a legacy API project written in pure PHP and now trying to move it to Symfony 4 and need to make some changes to the NGINX configuration.
I am required to keep both the old and the new endpoints working at the same time, so my plan is to setup NGINX in a way that it tries to serve first the old endpoint and if it doesn't exist (since I plan to remove them as I migrate to Symfony) it redirects to Symfony's front controller.
The current directory structure is this:
So far my NGINX conf is like so:
server {
root /project/www;
index index.php;
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass php-fpm:9000;
include fastcgi_params;
fastcgi_param HTTPS on;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
location ~ / {
try_files $uri $uri/ /index.php$is_args$args;
}
}
It works fine, if I request /api/client_status it uses the index.php under the client_status directory and if I remove that folder it uses Symfony's front controller.
The thing is that other applications are using these enpoints sometimes with index.php appended, e.g /api/client_status/index.php, and in these cases I get a 404 instead of being redirected to Symfony's front controller.
I tried rewriting at the top of the server block with rewrite ^/api/(.*)/index.php /api/$1; but it didn't help. Any input or even a suggestion of another approach is very welcome.

The URIs with index.php appended, will be processed by the location ~ \.php$. You need to add a try_files statement to this block to avoid the 404 responses, and instead send the requests to Symfony's front controller.
For example:
location ~ \.php$ {
try_files $uri /index.php$is_args$args;
...
}

Related

How to configure nginx to map only the first path in URL to a specific directory for php app?

I'm working on a php web app and want the URLs to be mapped to a folder on the server like this:
https://app.com/clientOne/... --> /client/...
https://app.com/clientTwo/... --> /client/...
etc
And all folders following clientOne and clientTwo in the URL exist on my server under client E.g. clientOne/admin/ gets mapped to client/admin/, and clientTwo/app/ gets mapped to client/app/. I want all clients to share the same application, and the application will determine the client from the URL. (I don't want to deal with subdomains right now.)
My nginx config works only when directories are in the URL. When I reference specific php files, I get a 404:
https://app.com/clientOne/admin/ (works)
https://app.com/clientOne/admin/index.php (returns 404)
I've searched and haven't found anyone with this particular issue. I think I know what needs to be done, but everything I have tried has not worked. Here is my standard nginx config:
location ~ \.php$ {
try_files $uri =404;
include fastcgi_params;
fastcgi_pass unix:/var/run/php-fpm/www.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
and this:
location ~ ^/(clientOne|clientTwo)/(.*)$ {
try_files $uri $uri/ /client/$2?$query_string;
}
I'm thinking I need to update the php location block to address my issue and then I won't need the second location block, but everything I have tried has not worked. I tried changing the try_files in the php location block to this, but it didn't work:
try_files $uri /client/ =404;
Does anyone know how to do this? Thanks

Clean URLs and php extension on nginx

I've looked at dozens of other questions and references on the web - and by all my calculations, my setup should work, but it doesn't.
I have nginx installation with php-fpm. If I try to access a .php file, it runs correctly and I get the correct results. I got this in my config file:
location ~ \.php$ {
try_files $uri =404;
fastcgi_pass unix:/var/run/php5-fpm.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
Now, I want to setup my web app so that /somedir/file automatically executes /somdir/file.php while still displaying /somdir/file in the browser's address bar. So I modified my config to contain the following:
location / {
try_files $uri $uri/ $uri.php?query_string
}
This kind of works, that is, the server does access the .php file. Yet, instead of executing it using the existing location ~ \.php$ block above, it simply spits the php source code as the download into the browser. If I append the .php manually to the requested URL, then the php is executed.
It feels as if once the server matches try_files to $uri.php, it then does not do another pass at locations to see that what it needs to do with the php files. I tried putting the php block above and below the location /, but it makes no difference.
How can I get the php to be executed?
You want file.php to be treated as an index file, so that domain.com/dir/file.php works on domain.com/dir/ ?
Why not just rename it to index.php?
You can do this by adding this param on your location block:
index index.html file.php index.php;
If not, you might want to look into writing a rewrite rule for nginx to map domain.com/dir/ to domain.com/dir/file.php (but you have to do it for each dir that you need it to work)

How to remove a path segment from NGiNX fastcgi_script_name?

This question could also be: "How to modify an NGiNX variable with a RegEx?",
or: "Can RegEx backreference have gaps?"
Either of those would resolve the problem I'm having. Perhaps a really simple solution exists, and after digging the web for few hours, it's time to ask for help.
Here's the scenario:
There's a part of the request URI that is going to be present always (for a sort of a gimmicky domain name + URI combination :-). I enforce the presence of that always-present URI path component, which follows immediately after the domain name, like so:
http://somedomain.com/basepart/rest/of/the/path?q=123
In the above example the "/basepart" represents the always-present URI component.
So far so good. The problem arises when I want the base file path to be /var/www/somedomain.com/htdocs/ without the basepart, and php5_fpm proxy is used. I obviously set:
location /basepart {
alias /var/www/somedomain.com/htdocs;
try_files $uri $uri/ /index.php?$args;
}
But since the dynamic files are in PHP, I need to either use fastcgi_split_path_info or $request_uri to build/pass the SCRIPT_FILENAME to php5_fpm. How do I do that? How do I remove the /basepart from $fastcgi_script_name, or from $request_uri, as otherwise PHP will look for the file in /var/www/somedomain.com/htdocs/basepart?
I've considered named backreferences, or "collecting" or "fragmented" backreferences (which I don't think exist in regex) so that I could capture the segment in $fastcgi_script_name before and after the basepart when fastcgi_split_path_info assignment happens, but haven't got them to work. Dayo writes earlier at SO: »Nginx is a webserver and not a scripting application.», and suggests use of Lua for more complex scripting. But I have a feeling I may be overlooking some really simple, facepalm-worthy solution :-].
Any thoughts, anyone?
If someone else stumbles on this question, after some brainstorming i came up with stupidly obvious solution:
root /app/frontend/web/;
location /api/ {
alias /app/backend/web/;
index index.php index.html;
# Double /api/ because "that's how nginx alias and try_files works together"
try_files $uri /api//api/index.php$is_args$args;
location ~ ^/api(/.*\.php(?:\?.*)?)$ {
try_files $uri /api//api/index.php$is_args$args;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$1;
...
}
}
I.e. using regex capturing group.
With this rules requests will be routed following way:
/index.html -> /app/frontend/web/index.html
/test/test.php -> /app/frontend/web/test/test.php as plaintext
/api/<somepath> -> /app/backend/web/<somepath> (proxied to FPM if .php) if it exists, otherwise /app/backend/web/index.php
The alias directive is fine for static websites but not so useful when PHP is involved. My preferred solution is to internally rewrite the URI without the /basepart and then use root rather than alias.
The problem is that many PHP scripts use $request_uri in order to process the request, which is frozen with the /basepart intact. However, we can specify any value we choose for REQUEST_URI and construct a more appropriate value from $uri or captures. In the example below, I preserve the value of $uri after the first rewrite so that it can be used to pass our modified request URI to the PHP script.
root /var/www/somedomain.com/htdocs;
location ^~ /basepart {
rewrite ^/basepart/(.*)$ /$1 last;
rewrite ^ / last;
}
location / {
internal;
try_files $uri #index;
}
location #index {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root/index.php;
fastcgi_param REQUEST_URI $uri;
...
}
location ~ \.php$ {
internal;
try_files $uri #index;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param REQUEST_URI $uri;
...
}
The fastcgi code block is duplicated across two locations. If it becomes unwieldy, the common code can be placed into a separate include file.
Locations are made private by using the internal directive keeping the /basepart mandatory for external access.

Nameserver always at the top in url bar in nginx (with no redirect)

My app has only two pages presented to the user, both in mobile or desktop. Firstly a login page and after the app page itself. When accessing www.myapp.com the user is firstly indexed towards the login page and if he is logged in he is then php redirected to the app page. Here is my server schema:
root
index.php (login page)
mobile/mobile.php
profile/profile.php
What I'd like is to avoid the user having www.myapp.com/mobile/mobile.php,www.myapp.com/profile/profile.php but instead www.myapp.com and www.myapp.com/desktop or www.myapp.com/mobile
so he can also switch between layouts. Unfortunately this is throwing a 404 error in my servers:
nginx default file:
location ~ /mobile/mobile.php$ {
rewrite $host/mobile break;
}
location ~ /index.php$ {
rewrite $host break;
}
location ~ profile/profile.php$ {
rewrite $host/desktop break;
}
Should it be something like this or should it be another complete way? I'd like to do this in my server, not in the user device... Thank you very much for your help...
The following was tested on my development server:
server {
listen 80;
root /usr/local/www/test;
index index.php;
location = /mobile { rewrite ^ /mobile/; }
location = /desktop { rewrite ^ /profile/; }
location / {
try_files $uri $uri/ =404;
}
location /mobile {
index mobile.php;
try_files $uri $uri/ =404;
}
location /profile {
index profile.php;
try_files $uri $uri/ =404;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass php;
}
}
It uses index and try_files to find your scripts and then internally redirect to the fastcgi handler. I have upstream php { ... } defined elsewhere. You might employ rewrite rules and the internal directive to enforce the scheme of no php script on the URL bar.
The mobile rewrite is simply to maintain consistency with the desktop rewrite, so that the client doesn't see a trailing /.
This is just one example of a multitude of solutions. Typically, there are ancillary files (css, js, images) with their URLs that also need to be accommodated.

What is the correct mapping for php in subfolders in nginx? (picocms, including mod-rewrite)

I'm trying to create a server mapping in nginx so that I can reach http://example.com/blog. I am using the following configuration
server {
listen 80;
server_name example.com;
root /home/www/blog;
index index.php index.html index.htm;
try_files $uri $uri/ /index.php$args;
location /blog/ {
location ~ \.php$ {
try_files $uri =404;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
}
}
}
If I go to http://example.com/blog it does not work, but http://example.com/blog/index.php does at least for the welcome page. Unfortunately, browsing to another sub-category doesn't work. This will lead to a URL like http://example.com/blog/food/. Weird thing is: if I remove the location /blog/ everything works fine. With it, it keeps downloading (Chrome) the index.php file.
I think the URL rewriting makes it not work (although the URL in the browser looks correct).
Can you suggest me ways to debug nginx behaviour like this? What am I missing that it works for http://example.com/food, but not for the subfolder one?
Btw: I modified pico's base_url property in the config.php to match either http://example.com or http://example.com/blog (depending on the scenarios I tried).

Categories