I have spent muy tiempo on this and I can't get a solution.
I need a way to point the same url but with different root directory to the same application. I don't want to use rewrites because the root directoy name has to be processed by the application and rewrite discards it.
http://www.host.com/a/ --> /var/www/html/project/
http://www.host.com/b/ --> /var/www/html/project/
http://www.host.com/c/ --> /var/www/html/project/
I've managed to configure in nginx an alias directory with a fixed name vdirectory and make nginx forward the request to fastcgi.
location /vdirectory {
alias /var/www/html/project/;
try_files $uri $uri/ /vdirectory/index.php;
location ~ \.php$ {
fastcgi_pass unix:/var/run/php5-fpm.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $request_filename;
}
}
The above works OK.
Since I don't want to use fixed root directory names but arbitrary ones, this is what I've managed so far:
location ~ ^/(.?)$ {
alias /var/www/html/project/;
try_files $uri $uri/ /$1/index.php;
location ~ \.php$ {
fastcgi_pass unix:/var/run/php5-fpm.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $request_filename;
}
}
Needless to say, it returns 404. It is a good sign because it means regex has recognized the path, but the request isn't forwarded correctly.
The only difference between the working config and the wrong one is /vdirectory vs ~ ^/(.?)$
alias works differently when inside a regular expression location block. See this document for details. You will need to capture the remainder of the URI and append that to the alias value. For example:
location ~ ^/(?<prefix>[^/]+)/(?<name>.*)$ {
alias /var/www/html/project/$name;
if (!-e $request_filename) { rewrite ^ /$prefix/index.php last; }
location ~ \.php$ {
if (!-f $request_filename) { return 404; }
fastcgi_pass unix:/var/run/php5-fpm.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $request_filename;
}
}
I avoid using try_files and alias within the same block due to long term issues. See this caution on the use of if.
Related
lets say I've a path like:
/var/www/myside/
that path contains two folders... let's say
/static and /manage
I'd like to configure nginx to have an access to:
/static folder on / (eg. http://example.org/)
this folder has some .html files.
/manage folder on /manage (eg. http://example.org/manage) in this case this folder contains Slim's PHP framework code - that means the index.php file is in public subfolder (eg. /var/www/mysite/manage/public/index.php)
I've tried a lot of combinations such as
server {
listen 80;
server_name example.org;
error_log /usr/local/etc/nginx/logs/mysite/error.log;
access_log /usr/local/etc/nginx/logs/mysite/access.log;
root /var/www/mysite;
location /manage {
root $uri/manage/public;
try_files $uri /index.php$is_args$args;
}
location / {
root $uri/static/;
index index.html;
}
location ~ \.php {
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;
fastcgi_pass 127.0.0.1:9000;
}
}
The / works correctly anyway manage doesn't. Am I doing something wrong? Does anybody know what should I change?
Matthew.
To access a path like /var/www/mysite/manage/public with a URI like /manage, you will need to use alias rather than root. See this document for details.
I am assuming that you need to run PHP from both roots, in which case you will need two location ~ \.php blocks, see example below. If you have no PHP within /var/www/mysite/static, you can delete the unused location block.
For example:
server {
listen 80;
server_name example.org;
error_log /usr/local/etc/nginx/logs/mysite/error.log;
access_log /usr/local/etc/nginx/logs/mysite/access.log;
root /var/www/mysite/static;
index index.html;
location / {
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_pass 127.0.0.1:9000;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $request_filename;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
}
location ^~ /manage {
alias /var/www/mysite/manage/public;
index index.php;
if (!-e $request_filename) { rewrite ^ /manage/index.php last; }
location ~ \.php$ {
if (!-f $request_filename) { return 404; }
fastcgi_pass 127.0.0.1:9000;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $request_filename;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
}
}
}
The ^~ modifier causes the prefix location to take precedence over regular expression locations at the same level. See this document for details.
The alias and try_files directives are not together due to this long standing bug.
Be aware of this caution in the use of the if directive.
server {
listen 80;
server_name ~^(?<cc>.+?).local.solar.bc.digital$;
client_max_body_size 1m;
root /home/vagrant/sites/$cc/_www/;
index index.html index.htm index.php;
error_page 404 /index.php;
access_log /var/log/nginx/$cc-access.log;
error_log /var/log/nginx/$cc-error.log;
charset utf-8;
sendfile off;
location / {
root /home/vagrant/sites/$cc/_www/php/;
try_files $uri $uri/ /index.php?$query_string;
}
location /shop/ {
# root /home/vagrant/sites/$cc/_www/bcshop/;
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_index index.php;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include /etc/nginx/fastcgi_params;
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME $request_filename;
fastcgi_param APP_ENV dev;
fastcgi_param PLATFORM_ENVIRONMENT local;
fastcgi_read_timeout 300;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
}
location ~ /\.ht {
deny all;
}
}
Right, given the config above. If you see what I am trying to do, know that it's not working!
Some details:
I have the general 'root', because without I get errors.
This is on a local VM used for development. We have a deployment tool locally that for each project (refer to $cc variable in the config above), it can deploy up to two apps. Not necessarily both are deployed for each project. The first app is deployed in /home/vagrant/sites/$cc/_www/php, the second one in /home/vagrant/sites/$cc/_www/bcshop (but I can make it shop - you'll see why from the config)
Both apps run on Drupal, so the way the load is the same. I simply can't make them work. I get file not found for both with most of the small variants I've tried.
When I place the second app in /home/vagrant/sites/$cc/_www/shop (rather than /home/vagrant/sites/$cc/_www/bcshop) I can get its homepage to load, but nothing else.
When I disregard the second app, and concentrate on the first, I can simply have a general root set to /home/vagrant/sites/$cc/_www/php and remove the local root from location /. That works. But it doesn't when it's specified as local root. In this case, in fact, I get this error in the logs: "FastCGI sent in stderr: "Primary script unknown" while reading response header from upstream". This only for the first app.
If you wonder why the general root is set to that value, it's because I get an error in the logs if the general root is not verifiable for the location being matched. Makes sense?
I think I've covered pretty much all of what I've done in summary.
Thoughts?
I am not an expert at all with nginx, so I am going by trial and errors, with the help of the docs and other questions answered on here. But so far, no joy.
Thanks all.
You have PHP files in both the _www/bcshop/ path and the _www/php/ path. If you would like to use one common location ~ \.php$ for both applications, then the URI for each application will need to be prefixed by /bcshop and /php respectively. That is, both applications appear to run in a subdirectory.
I suspect that you would like to use /shop prefix for one application, and the / prefix for the other. in which case two location ~ \.php$ blocks will be required.
One application runs from the server root:
root /home/vagrant/sites/$cc/_www/php;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
try_files $uri /index.php;
include /etc/nginx/fastcgi_params;
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME $request_filename;
...
}
And one application runs with a URI prefix of /shop but located in the subdirectory _www/bcshop:
location ^~ /shop {
rewrite ^/shop(?:/(.*))?$ /bcshop/$1 last;
}
location ^~ /bcshop/ {
internal;
root /home/vagrant/sites/$cc/_www;
try_files $uri /shop/index.php?$query_string;
location ~ \.php$ {
try_files $uri /shop/index.php;
include /etc/nginx/fastcgi_params;
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME $request_filename;
...
}
}
The ^~ modifier ensures that the location block takes precedence over the regular expression location block above. See this document for details.
Although the external URI prefix is /shop, it is silently rewritten to /bcshop so that we can continue to use the root directive. There is an alias directive, but it has issues with try_files and is tricky to use with PHP.
Based on the answer by #RichardSmith, I come up with my own variant (which is working fine). Simply because repeating the block for location ~ \.php$ was doing my head in.
...
...
root /home/vagrant/sites/$cc/_www/;
...
...
location / {
set $actual_root /home/vagrant/sites/$cc/_www/php/;
set $fastcgi_index /index.php;
root $actual_root;
try_files $uri $uri/ $fastcgi_index?$query_string;
}
location /shop/ {
set $actual_root /home/vagrant/sites/$cc/_www/;
set $fastcgi_index /shop/index.php;
root $actual_root;
try_files $uri $uri/ $fastcgi_index?$query_string;
}
location ~ \.php$ {
root $actual_root;
fastcgi_index $fastcgi_index;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include /etc/nginx/fastcgi_params;
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME $actual_root/$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param APP_ENV dev;
fastcgi_param PLATFORM_ENVIRONMENT local;
fastcgi_read_timeout 300;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
}
...
...
I have a Symfony2 application running alongside WordPress - mysite.com/blog routes to my /var/www/mysite/wordpress/ directory and everything else routes to /var/www/mysite/symfony:
server {
listen 80;
server_name mysite.com
location / {
try_files $uri /app.php$is_args$args;
}
location ~ ^/app\.php(/|$) {
fastcgi_pass 127.0.0.1:9000;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $request_filename;
internal;
}
location /blog {
root /var/www/mysite/wordpress;
rewrite ^/blog/(.+)$ /$1 break;
try_files $uri $uri/ /blog/index.php?q=$uri&$args;
index index.php;
location ~ \.php {
fastcgi_pass 127.0.0.1:9000;
include fastcgi_params;
fastcgi_split_path_info ^(?:\/blog)(.+\.php)(.*);
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
}
Everything works fine, except the WordPress admin (mysite.com/blog/wp-admin/) gives me a 404 error. Visiting mysite.com/blog/wp-admin/index.php works as expected, so it looks like the index index.php line is not working. What could be the issue here?
You should use alias instead of root directive:
location ^~ /blog {
alias /var/www/mysite/wordpress;
index index.php;
try_files $uri $uri/ /blog/index.php?q=$uri&$args;
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
include fastcgi_params;
fastcgi_split_path_info ^(?:\/blog)(.+\.php)(.*);
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
You need to edit the nginx server Configuration.
# WordPress single blog rules.
# Designed to be included in any server {} block.
# This order might seem weird - this is attempted to match last if rules below fail.
# http://wiki.nginx.org/HttpCoreModule
location / {
try_files $uri $uri/ /index.php?$args;
}
# Add trailing slash to */wp-admin requests.
rewrite /wp-admin$ $scheme://$host$uri/ permanent;
# Directives to send expires headers and turn off 404 error logging.
location ~* ^.+\.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
access_log off; log_not_found off; expires max;
}
# Uncomment one of the lines below for the appropriate caching plugin (if used).
#include global/wordpress-wp-super-cache.conf;
#include global/wordpress-w3-total-cache.conf;
# Pass all .php files onto a php-fpm/php-fcgi server.
location ~ [^/]\.php(/|$) {
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
if (!-f $document_root$fastcgi_script_name) {
return 404;
}
# This is a robust solution for path info security issue and works with "cgi.fix_pathinfo = 1" in /etc/php.ini (default)
include fastcgi.conf;
fastcgi_index index.php;
# fastcgi_intercept_errors on;
fastcgi_pass php;
}
More about this here:
http://codex.wordpress.org/Nginx#General_WordPress_rules
So, if you allege that /blog/wp-admin/index.php works, but /blog/wp-admin/ doesn't, perhaps just conditionally append index.php, if need be?
+ rewrite ^/blog/wp-admin(/)?$ /wp-admin/index.php break;
rewrite ^/blog/(.+)$ /$1 break;
So, what do the logs say in regards to your 404? I think this might be related to the fact that the index directive causes "an internal redirect", thus I would not be surprised if your 404 ends up being generated through the / instead of the /blog location.
Let's say I have a nginx configuration set up for a domain like this:
server {
root /path/to/one;
server_name one.example.org;
location ~ \.php$ {
try_files $uri =404;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
Now, if I want to add another domain with different content, is there a way I can re-use equivalent statements from the previous domain, or do I have to duplicate everything for every new domain I want to support?
server {
root /path/to/two; # different
server_name two.example.org; # different
location ~ \.php$ {
try_files $uri =404;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
I tried moving the location directive outside the server closure, but obviously things don't work like that because I got an error "location directive is not allowed here" when restarting nginx.
This is a good example to use nginx Map module. http://wiki.nginx.org/HttpMapModule
Following is what I tried. It works in my devbox. Note
map directive can only be put in the http block.
performance penalty of declaring a map directive is negligible (see above link)
you can have freedom to have different root folder, or port number, etc.
map $subdomain $root_folder {
one /path/to/one;
two /path/to/two;
}
map $subdomain $port_number {
one 9000;
two 9100;
}
server {
listen 80;
server_name ~^(?P<subdomain>.+?)\.mydomain\.com$;
root $root_folder;
location ~ \.php$ {
try_files $uri =404;
fastcgi_pass 127.0.0.1:$port_number;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
you can do:
server_name one.example.org two.example.org;
if both are exactly identical except for the domainname
if you have just similar locationblocks you can move those locations to a separate file and then do an
include /etc/nginx/your-filename;
to easily use it in each serverblock
I need to install multiple symfony2 applications on the same host but on different subdirectories (or location blocks).
With this config nginx throws a "file not found" or redirect loop message when trying to access any url.
Example:
/login -> /base/login
/app1 -> /base/app1
/app2 -> /base/app2
Current Config:
root /base/default; #Points to an empty directory
# Login Application
location ^~ /login {
alias /base/login/web;
try_files $uri app_dev.php;
}
# Anything else
location ~ ^/([\w\-]+) {
alias /base/$1/web;
try_files $uri app_dev.php;
}
location / {
# Redirect to the login
rewrite ^ /login redirect;
}
# Handle PHP
location ~ \.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 HTTPS off;
fastcgi_pass unix:/var/run/php5-fpm.sock;
}
After hours spended to find this (sf2 doc doesn't explain how cgi parameters are needed and interpreted, you need to go through Request.php to understand), so I share this.
This is a config which seems ok with sf2 in a directory {subdir} (and web access to others files than {subdir}/web/* prohibited).
It works for me with php-fpm (socket).
Of course, replace "{subdir}" by your /path/from/docroot/to/symfony_root/
dev environnement can be choosen by adding "dev" to "{subdir}" (since app_dev.php in the url no longer works with this conf)
server {
# general directives
location ~ ^/{subdir}(/.*)$ {
try_files /{subdir}/web$1 #sf2;
}
location ~ ^/{subdir}dev(/.*)$ {
expires off;
try_files /{subdir}/web$1 #sf2dev;
}
location #sf2 {
expires off;
fastcgi_pass {your backend};
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root/{subdir}/web/app.php;
fastcgi_param SCRIPT_NAME /{subdir}/app.php;
fastcgi_param REQUEST_URI /{subdir}$1;
}
location #sf2dev {
expires off;
fastcgi_pass {your backend};
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root/{subdir}/web/app_dev.php;
fastcgi_param SCRIPT_NAME /{subdir}dev/app_dev.php;
fastcgi_param REQUEST_URI /{subdir}dev$1;
}
# other location directives
# if some others apps needs php, put your usual location to cactch php here
}
I Hope it helps (and there isn't any misconfiguration), given without any guarantee...
Of course you can pick out prod/dev conf if you don't need. And you can use var and only one #sf2 location instead :
set $sf2_root /{subdir};
location ~ ^/{subdir}(/.*)$ {
set $sf2_prefix /{subdir};
set $sf2_ctrl app.php;
try_files $sf2_root/web$1 #sf2;
}
location ~ ^/{subdir}dev(/.*)$ {
set $sf2_prefix /{subdir}dev;
set $sf2_ctrl app_dev.php;
expires off;
try_files $sf2_root/web$1 #sf2;
}
location #sf2 {
expires off;
fastcgi_pass {your backend};
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$sf2_root/web/$sf2_ctrl;
fastcgi_param SCRIPT_NAME $sf2_prefix/$sf2_ctrl;
fastcgi_param REQUEST_URI $sf2_prefix$1;
}
Here is a simpler configuration for symfony2 on the "/front/" subdirectory.
Route generation and assets work fine.
The configuration
set $frontRoot /your/project/path/web;
set $sfApp app_dev.php; # Change to app.php for prod
location /front/ { # Static files
root $frontRoot;
rewrite ^/front/(.*)$ /$1 break;
try_files $uri #sfFront;
}
location #sfFront { # Symfony
fastcgi_pass phpfcgi;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $frontRoot/$sfApp;
fastcgi_param SCRIPT_NAME /front/$sfApp;
fastcgi_param REQUEST_URI /front$uri?$args;
fastcgi_param HTTPS off;
}
Some explanation
The trick is to make symfony believe app.php script is in /front/, so it generates routes and assets with this path.
I looked at what apache was giving to MOD-PHP to use the same values.
SCRIPT_FILENAME: The absolute path to the PHP file. Here, it is always /your/project/path/app_dev.php
REQUEST_URI: The URI the user entered. Here, we have to manually re-add /front at the begining of the path as it was removed by the file serving location (via rewrite ^/front/(.*)$ /$1 break;)
SCRIPT_NAME: The value is /front/app_dev.php. This is the most important part. Symfony will cut app_dev.php and prepend /front to all its routes.
Based on dcaillibaud's answer, here's a more generic configuration,
allowing to support multiple Symfony (version 2 or 3) projects under the root web path, using some regular expression magic:
server {
# other specific directives...
root /var/www;
location ~ ^/([^/]+)/dev(/.*)$ {
location ~ \.php { deny all; }
set $sf2_root /$1;
set $sf2_prefix /$1/dev;
set $sf2_ctrl app_dev.php;
expires off;
try_files $sf2_root/web$2 #sf2;
}
location ~ ^/([^/]+)(/.*)$ {
location ~ \.php { deny all; }
set $sf2_root /$1;
set $sf2_prefix /$1;
set $sf2_ctrl app.php;
try_files $sf2_root/web$2 #sf2;
}
location #sf2 {
expires off;
fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$sf2_root/web/$sf2_ctrl;
fastcgi_param SCRIPT_NAME $sf2_prefix/$sf2_ctrl;
fastcgi_param REQUEST_URI $sf2_prefix$2;
}
}
So basically, you'll have:
www.domain.com/project pointing to your PROD environment
and
www.domain.com/project/dev pointing to your DEV environment
Please replace the line:
fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
with your appropriate backend
This can also be easily adapted for newer Symfony projects using index.php script instead of app(_dev).php, changing the web/public path, and setting some ENV variables.
I think this approach, answers better the original question.