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.
Related
I have a Symfony 3.4 application running on nginx and a maintenance mode is implemented the following way in nginx:
location / {
# try to serve file directly, fallback to app.php
try_files $uri /app.php$is_args$args;
}
location ~ ^/(app)\.php(/|$) {
if (-f "/var/www/mysite.com/web/maintenance.html") {
return 503;
}
fastcgi_pass unix:/run/php/php7.0-fpm.sock;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
}
error_page 503 #maintenance;
location #maintenance {
rewrite ^(.*)$ /maintenance.html break;
}
I would like to exempt a certain location from maintenance mode, so that this location keeps being served by the Symfony application. So that requests to mysite.com/still/available/route are not redirected to the maintenance page.
How can that be done?
I found the answer, actually, it was quite obvious. One just needs to put the "if" into the root location block (/) and add another location block with the path that is supposed to remain accessible during maintenance mode. There, of course, must not appear that if-clause:
location / {
# try to serve file directly, fallback to app.php
if (-f "/var/www/mysite.com/web/maintenance.html") {
return 503;
}
try_files $uri /app.php$is_args$args;
}
location /still/available/route {
try_files $uri /app.php$is_args$args;
}
location ~ ^/(app)\.php(/|$) {
fastcgi_pass unix:/run/php/php7.0-fpm.sock;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
}
error_page 503 #maintenance;
location #maintenance {
rewrite ^(.*)$ /maintenance.html break;
}
I'm a newbie with nginx and it's rewrite commands and I really need some help with this one. I've been trying to solve this the whole day but nothing..
If user gives this url:
someurl.com/sub/1.0/healthcheck
I would like to rewrite it to point into the Symfonys project file here:
/var/www/sub/1.0/web/app_dev.php
And the "healthcheck" in the url goes for the Symfony.
But nope. Something is wrong here. It seems that it finds the Symfony but there is something wrong with the url since it always returns:
Route not found
Even if I omit the "healthcheck" from the url, it still returns the same error. (there is an index -action with "/" as the route.)
Here is the current Nginx config:
server {
server_name localhost;
root /var/www/sub/1.0/web;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
location / {
root /var/www/html/;
index index.html;
}
location /sub/1.0/ {
index app_dev.php;
rewrite ^/sub/1.0/ /app_dev.php last;
}
location ~ (app|app_dev).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_pass unix:/var/run/php/php7.0-fpm.sock;
}
}
I figured this one out. The problem was that Symfony takes the request uri, which was not affected by the rewrite as far as fastcgi was concerned. I added the "fastcgi_param REQUEST_URI $uri?$args;" and tadaa! It works!
Here's the fixed config(without the excess lines, like the root location '/'):
server {
root /var/www/sub/1.0/web;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
# If user writes the app_xxx.php into the url, remove it:
rewrite ^/app_dev\.php/?(.*)$ /$1 permanent;
location /sub/1.0/ {
index app_dev.php;
rewrite ^/sub/1.0/(.*)$ /app_dev.php/$1 last;
return 403; # If the rewrite was not succesfull, return error.
}
location ~ (app|app_dev).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 REQUEST_URI $uri?$args;
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
}
}
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.
I have fully worked example of virtual host for a project on Symfony from ()[].
There is a code:
server {
listen 80;
server_name localhost www.localhost;
root /vagrant/web;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
location / {
# try to serve file directly, fallback to app.php
try_files $uri /app_dev.php$is_args$args;
}
# DEV
# This rule should only be placed on your development environment
# In production, don't include this and don't deploy app_dev.php or config.php
location ~ ^/(app_dev|config)\.php(/|$) {
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTPS off;
}
# PROD
location ~ ^/app\.php(/|$) {
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTPS off;
# Prevents URIs that include the front controller. This will 404:
# http://domain.tld/app.php/some-path
# Remove the internal directive to allow URIs like this
#internal;
}
}
But I want to improve it a bit for me. How can I load maintenance.html by default instead of app_dev.php?
P.S. I need a behaviour like with try_files $uri /maintenance.html$is_args$args; instead of try_files $uri /app_dev.php$is_args$args;, but ONLY if maintenance.html exists
Solution from here with bit of comments
location / { #can be any location or even in server
if (-f $document_root/maintenance.html) {
return 503; #503 for search engines
}
... # the rest of your config goes here
}
error_page 503 #maintenance;
location #maintenance {
rewrite ^(.*)$ /maintenance.html break;
}
I solved it with:
try_files $uri /maintenance.html$is_args$args /app_dev.php$is_args$args;
I saw that many people had problem configuring one nginx server to have multiple symfony2 applications. However, none wanted the same things and had the same problem as me.
What I want to do is to have multiple applications on the same domain. One main application will answer directly to the domain, and the others will be on alias subdirectory.
With a schema :
http://mydomain/ -> main app
http://mydomain/subdir1 -> another app
http://mydomain/subdir2 -> yet another app
I tried by myself to do that and the main app works perfectly. But the subdirectories are most of the time intercepted by the main app, which throws 404. When I try to add app.php in the URL of a subdirectory (like http://mydomain/subdir1/app.php/my/route), the server return 404.
This is what I did until now :
server {
listen 80;
server_name mydomain;
root /server/www/main-app/web;
location / {
# try to serve file directly, fallback to app.php
try_files $uri /app.php$is_args$args;
# PROD
location ~ ^/app\.php(/|$) {
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTPS off;
}
}
location /subdir1/ {
alias /server/www/other-app1/web;
# try to serve file directly, fallback to app.php
try_files $uri /server/www/other-app1/web/app.php$is_args$args;
# PROD
location ~ ^/other-app1/app\.php(/|$) {
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTPS off;
}
}
}
Thanks you for your help !
EDIT 26/12/2014 :
For those who did not understand exactly what I want : I want to host multiple symfony2 apps on the same domain name without subdomain. Without subdomain, I must use subdirectory. Before that I tried nginx, I used Apache2 and it was easy to do the trick with Alias.
I did more search and found out that "alias" and "try_files" aren't good friends (see this bug report : http://trac.nginx.org/nginx/ticket/97). So I activated debug mode and did many tests.
Now I almost did it. The main apps no longer intercepts subdirectories and the others apps answer.
But those others apps answer by 404 so I looked in their logs. And I found out that they looked for URL pattern with the subdirectory in it. For instance they searched /subdir1/login instead of /login.
So this is my new configuration :
server {
listen 80;
server_name mydomain;
root /server/www/main-app/web;
location #rewriteapp {
rewrite ^(.*)$ /app.php/$1 last;
}
location /subdir1/ {
set $root "/server/www/other-app1/web";
# try to serve file directly, fallback to app.php
try_files $uri #rewriteapp;
}
location / {
index app.php;
set $root "/server/www/main-app/web";
# try to serve file directly, fallback to app.php
try_files $uri #rewriteapp;
}
# PROD
location ~ ^/app\.php(/|$) {
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}
As you can see, the trick was to not use $document_root for the SCRIPT_FILENAME and I created my own instead. I don't know how the symfony2 router search the pattern in the URL, but with my previous configuration (Apache2) I never had this problem. So maybe their is another trick to send the correct path to script app.php.
Thanks you again for your help !
This solved it finally for me (thanks to Claros answer), after million things i tried. Like this, urls like the following work:
/abc/path/to/endpoint
but not /abc/app.php/path/to/endpoint. Config.php and App_dev.php, if in web folder are given back as plain text.
I still try to figure out to get /abc to work (/abc/ works but /abc not). There i get a Symfony exception that route /abc can not be found.
Also some font urls (for bootstrap) are still incorrect but styles, routing etc works.
location /abc {
set $subpath /abc;
set $sfPath /var/www/abc/current/web;
alias $sfPath;
try_files $uri #rewrite;
}
location / {
set $subpath "";
set $sfPath /var/www/def/current/web;
alias $sfPath;
try_files $uri #rewrite;
}
location #rewrite {
rewrite ^(.*)$ $subpath/app.php$1 last;
}
location ~ /app\.php(/|$) {
internal;
include /etc/nginx/fastcgi_params;
fastcgi_index app.php;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_param DOCUMENT_ROOT $sfPath;
fastcgi_param SCRIPT_FILENAME $sfPath/app.php;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
}
If you want also the app_dev.php to work in demo environment the best way i found is the following (to have the php block everytime inside the location block):
location /xyz {
set $subpath /xyz;
set $sfPath /var/www/xyz/current/web;
alias $sfPath;
try_files $uri #rewrite;
#Change the match for app_dev.php to work
location ~ /(app|app_dev|config)\.php(/|$) {
#Drop the internal for App_dev.php to work
#internal;
include /etc/nginx/fastcgi_params;
fastcgi_index app.php;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_param DOCUMENT_ROOT $sfPath;
fastcgi_param SCRIPT_FILENAME $sfPath/app.php;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
}
}
After many hours of debugging, I finally solved the problem. This is my final configuration :
server {
listen 80;
server_name mydomain;
root /server/www;
location #rewriteMainApp {
rewrite ^(.*)$ /app.php/$1 last;
}
location #rewriteOtherApp1 {
rewrite ^(.*)$ /subdir1/app.php/$1 last;
}
location /subdir1 {
alias /server/www/other-app1/web;
index app.php;
set $subfolder "other-app1/web";
try_files $uri #rewriteOtherApp1;
}
location / {
root /server/www/main-app/web;
index app.php;
set $subfolder "main-app/web";
try_files $uri #rewriteMainApp;
}
# PROD
location ~ /app\.php(/|$) {
fastcgi_pass unix:/var/run/php5-fpm.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root/$subfolder/app.php;
}
}
Thanks you all for your help !
Seperate your applications with-in another server tag in your sites-enabled file.
For example:
#Site 1
server {
#Configuration
}
server {
#Configuration 2
}
server {
#Configuration 3
}
Sample configuration:
server {
listen 80;
root /var/www/yourdomain.com/web;
server_name yourdomain.com www.yourdomain.com;
add_header X-UA-Compatible "IE=Edge,chrome=1";
location ~* \.(css|js|gif|jpe?g|png)$ {
expires 1y;
add_header Pragma public;
add_header Cache-Control "public, must-revalidate, proxy-revalidate";
}
location / {
try_files $uri #rewriteapp;
}
location #rewriteapp {
rewrite ^(.*)$ /app_dev.php/$1 last;
}
location ~ ^/(app|app_dev|config)\.php(/|$) {
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTPS off;
}
error_log /var/log/nginx/yourdomain.com.error.log;
access_log /var/log/nginx/yourdomain.com.access.log;
}
server {
listen 80;
root /var/www/yourdomain.com/anotherproject/web;
server_name sub1.yourdomain.com www.sub1.yourdomain.com;
add_header X-UA-Compatible "IE=Edge,chrome=1";
location ~* \.(css|js|gif|jpe?g|png)$ {
expires 1y;
add_header Pragma public;
add_header Cache-Control "public, must-revalidate, proxy-revalidate";
}
location / {
try_files $uri #rewriteapp;
}
location #rewriteapp {
rewrite ^(.*)$ /app_dev.php/$1 last;
}
location ~ ^/(app|app_dev|config)\.php(/|$) {
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTPS off;
}
error_log /var/log/nginx/sub1.yourdomain.com.error.log;
access_log /var/log/nginx/sub1.yourdomain.com.access.log;
}