I'm currently trying to break apart 3 applications from one repository into 3, but keeping the url structure, so basically different locations under the same domain have to be delivered by different applications.
What I'm struggling with is that one of the apps needs to be the fallback for non-existent urls, so if the first one doesn't match, and the second one doesn't, then the third should handle the request
The structure I've got is:
/etc/nginx/sites-enabled/main_site, in here, apart from server_name and logs I've got include /etc/nginx/subsites-enabled/*
, where I've got 3 configuration files, one for each of the apps.
Each of the 3 config files contains a location block.
I've tried negative lookahead in regex (basically trying to hardcode the urls the other apps handle) but failed.
So, to summarise:
/ and /community should be delivered by /etc/nginx/subsites-enabled/example.org/home (a few perl scripts)
/news should be delivered by /etc/nginx/subsites-enabled/example.org/news (wordpress)
everything else should be delivered by /etc/nginx/subsites-enabled/example.org/app (cake app)
The perl bit works fine. The problem I'm having is that the app is taking over news (probably because it matches .*), I've tried various options (I've been at this for 2 days) but none of them solved all the problems (sometimes static assets wouldn't work, etc).
My configuration is:
/etc/nginx/sites-enabled/example.org:
server {
listen 80;
server_name example.org;
error_log /var/log/nginx/example.org.log;
include /etc/nginx/subsites-enabled/example.org/*;
}
/etc/nginx/subsites-enabled/example.org/home:
location = / {
rewrite ^.*$ /index.pl last;
}
location ~* /community(.*) {
rewrite ^.*$ /index.pl last;
}
location ~ \.pl {
root /var/www/vhosts/home;
access_log /var/log/nginx/home/access.log;
error_log /var/log/nginx/home/error.log;
include /etc/nginx/fastcgi_params;
fastcgi_index index.pl;
fastcgi_param SCRIPT_FILENAME /var/www/vhosts/home$fastcgi_script_name;
fastcgi_pass unix:/var/run/fcgiwrap.socket;
}
/etc/ngins/subsites-enabled/news
location /news {
access_log /var/log/nginx/news/access.log;
error_log /var/log/nginx/news/error.log debug;
error_page 404 = /news/index.php;
root /var/www/vhosts/news;
index index.php;
if (!-e $request_filename) {
rewrite ^.*$ /index.php last;
}
location ~ \.php {
include /etc/nginx/fastcgi_params;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /var/www/vhosts/news$fastcgi_script_name;
}
}
/etc/nginx/subsites-enabled/app:
location ~ .* {
access_log /var/log/nginx/app/access.log;
error_log /var/log/nginx/app/error.log;
rewrite_log on;
index index.php;
root /var/www/vhosts/app/app/webroot;
if (-f $request_filename) {
expires 30d;
break;
}
if (!-e $request_filename) {
rewrite ^.*$ /index.php last;
}
location ~ \.php {
include /etc/nginx/fastcgi_params;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /var/www/vhosts/app/app/webroot$fastcgi_script_name;
}
}
There are a few things wrong with your config, the two relevant ones being:
For instance, take the URL example.org/news/test.htm
location /news
block will match it/news/test.htm
- this does not change, just because it is in the location block/var/www/vhosts/news/news/test.htm
if (!-e $request_filename)
statement should capture this non-existent file/index.php
last
the processes starts over (breaking out of the location block)/index.php
is now captured by thelocation /app block
.The problem mentioned above, with the root directive, is compounded when you go to your app location block. Unlike with the 'news' block, where you could conceivably just remove 'news' from the path (since it will be added back in), you cannot do this for the app path, which ends in 'webroot'.
The solution lies in the
alias
directive. This does not change the document_root, but it does change the file path that is used to serve the request. Unfortunately,rewrite
andtry_files
tend to behave a bit unexpectedly withalias
.Let's start with a simple example - no PHP - just HTML and your Perl block - but with a folder structure matching yours (tested on Nginx 1.0.12, CentOS 6):
location = /
- will only match the root pathlocation ^~ /community
- will match every path starting with /communitylocation ~ \.pl
- will match all files that contain .pllocation ^~ /news
- will match every path starting with /newslocation ^~ /app
- will match every path starting with /applocation /
- will match all paths not matched aboveYou should be able to remove the
^~
- but it may offer a slight performance improvement, since it stops searching once a match is found.While it should be a simple matter to add the PHP blocks back in, there is, unfortunately, a slight difficulty -
try_files
(and your rewrite) do not end up passing the desired path to the nested location block - and usingalias
when only the extension is specified in the location block doesn't work.One solution is to use separate location blocks that perform a capture together with the alias directive - it isn't quite elegant, but as far as I can tell, it does work (again, tested on Nginx 1.0.12, CentOS 6 - of course, I didn't setup CakePHP, Wordpress, and Perl - I just used a couple of PHP and HTML files in each folder)
The above config, takes the simple one above, and makes two changes:
location ~* ^/news/(.*\.php)$
- will match all files ending in .php, with paths starting with /news/location ~* ^/app/(.*\.php)$
- will match all files ending in .php, with paths starting with /app/^~
matching - this is required so that the two added location blocks can match against paths (otherwise matching would stop on the /news or /app blocks).It should be noted that the order for location matching is very important here:
=
)^~
secondA matching regex will supersede a straight string!
An important point of mention is that when captures are used with alias, the entire URL is replaced - not just the leading folder. Unfortunately, this means that
$fastcgi_script_name
is left empty - so, I have used$1
above instead.I am sure you will need to make a few changes, but the basic premise should be functional. You should be able to separate the blocks into multiple files as needed - ordering shouldn't affect the config.