serve react frontend and php backend on same domain with nginx - symfony

I have a React frontend and a Symfony backend I'm trying to serve on the same domain. The React frontend needs to serve assets if they exist otherwise fallback to serve index.html.
I'd like to serve the php Symfony app when /api is in the request uri. Similar to the React app, I need all requests to go to the index.php file.
The frontend is being served correctly but not the api. I get a 404 from nginx when i hit /api in the browser.
I feel like i'm close but for some reason nginx doesn't have the correct $document_root. I'm adding a header(X-script) to test what the variables are and I'm getting the following:
X-script: /usr/share/nginx/html/index.php
Here's my nginx config.
server {
listen 80 default_server;
index index.html index.htm;
access_log /var/log/nginx/my-site.com.log;
error_log /var/log/nginx/my-site.com-error.log error;
charset utf-8;
location /api {
root /var/www/my-site.com/backend;
try_files $uri $uri/ /index.php$is_args$args;
}
location / {
root /var/www/my-site.com/frontend;
try_files $uri /index.html;
}
location ~* \.php$ {
add_header X-script "$document_root$fastcgi_script_name" always;
try_files $fastcgi_script_name =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTPS off;
}
}
Any help would be much appreciated.

The web root of a Symfony 4 project must include the public subfolder. I am not using NGINX but I think this is the correct configuration:
location /api {
root /var/www/my-site.com/backend/public;

In the following vhost, the most important changes I made are :
commented out index directive in server block : it is handled directly in locations blocks
added a slash after location /api/ and remove unnecessary $uri/ in the same api location block
moved the php_fpm logic to index.php location block : you want all requests to be passed to front controller in Symfony app
For the same reason, moved the 404 logic to a general php block, which will handle any other php file request
server {
listen 80 default_server;
access_log /var/log/nginx/my-site.com.log;
error_log /var/log/nginx/my-site.com-error.log error;
charset utf-8;
location /api/ {
root /var/www/my-site.com/backend;
try_files $uri /index.php$is_args$args;
}
location / {
root /var/www/my-site.com/frontend;
try_files $uri /index.html;
}
location ~ ^/index\.php(/|$) {
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
fastcgi_param HTTPS off;
internal;
}
# return 404 for all other php files not matching the front controller
# this prevents access to other php files you don't want to be accessible.
location ~ \.php$ {
return 404;
}
}
Last, I bet you'll have to add symfony public folder into api location block root directive.
This vhost was tested fine on my localhost with following tree.
api_test
- backend
- index.php
- frontend
- index.html
I can successfully access to
backend/index.php from api_test.dv/api
frontend/index.html from api_test.dv/

Kojos answer is excellent, but to make it completely functional a root directive needs to be added under server or an error message “primary script unknown” will be observed. This is almost always related to a wrongly set SCRIPT_FILENAME in the nginx fastcgi_param directive.
# Nginx configuration
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name ${NGINX_HOST};
root /var/www/html/backend/public;
access_log /var/log/nginx/access_log.log;
error_log /var/log/nginx/error.log error;
charset utf-8;
location / {
root /var/www/html/frontend/build;
try_files $uri /index.html;
}
location /api {
alias /var/www/html/backend/public;
try_files $uri /index.php$is_args$args;
}
location ~ ^/index\.php(/|$) {
fastcgi_pass php-fpm:9000;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
internal;
}
# return 404 for all other php files not matching the front controller
# this prevents access to other php files you don't want to be accessible.
location ~ \.php$ {
return 404;
}
}

Related

nginx vhost, problem service .css as static file or dynamic file

I have problems matching my requirements:
I want 2 things;
https://www.test-boutique.vm/store.css to be routed to the PHP application because the file content is streamed by the app;
https://www.test-boutique.vm/static/css/basic.css to be served from the filesystem because it exists on it;
My vhost is :
server {
listen 443;
server_name www.test-boutique.vm;
root /srv/app/public/front;
index index.php;
location / {
# try to serve file directly, fallback to index.php
try_files $uri $uri/ /index.php$is_args$args;
}
# css are for the files generated by the application (store.css)
location ~ \.(php|htm|css)$ {
try_files $uri $uri/ /index.php$is_args$args;
fastcgi_pass unix:/var/run/php-fpm.app.sock;
fastcgi_index index.php;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
fastcgi_param HTTPS on;
fastcgi_param APP_ENV dev;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
location ~* \.(js|css|bmp|png|jpg|jpeg|gif|swf|ico)$ {
try_files $uri =404;
log_not_found off;
access_log off;
expires 7d;
add_header Cache-Control public;
add_header Cache-Control must-revalidate;
}
rewrite ^/media/(.*)$ https://test.cloud/$http_host/media/$1 permanent;
rewrite ^/img/(.*)$ https://test.cloud/$http_host/img/$1 permanent;
access_log /var/log/nginx/fov4_access_log;
error_log /var/log/nginx/fov4_error_log;
}
With this version:
✅ /store.css file works well (generated by the PHP application)
❌ /static/css/basic.css is trying to be served by the PHP application instead of serving the file directly from the filesystem (the file exists for sure under this path)
When removing the css part from the vhost
(location ~ \.(php|htm|css)$ { TO NEW location ~ \.(php|htm)$ {
❌ /store.css file is trying to be served as a static asset and ends up 404 (the request is not passed to the application)
✅ /static/css/basic.css is served correctly
What am I missing please ?
Instead of matching all css files like you do here: location ~ \.(php|htm|css)$ {, try matching that one css file that you need to have generated by PHP:
location ~ \.(php|htm)$ {
# you php-fpm config here
}
location ~* \.(js|css|bmp|png|jpg|jpeg|gif|swf|ico)$ {
# your static files config here
}
location = /store.css {
# you php-fpm config here
}

Nginx Laravel and phpmyadmin configuration [duplicate]

So here's my server block
server {
listen 80;
server_name domain.tld;
root /var/www/domain.tld/html;
index index.php index.html index.htm;
location / {
}
location /phpmyadmin {
alias /var/www/phpmyadmin;
}
location /nginx_status {
stub_status on;
access_log off;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
browsing http://domain.tld/index.php works fine the only problem im encountering is browsing http://domain.tld/phpmyadmin/. It returns 404 yet the folder /var/www/phpmyadmin exist on the server. Viewing /var/log/nginx/error.log, no error is being logged there yet the access to it is logged in /var/log/nginx/access.log. What could be the problem here?
The problem is that phpmyadmin is a PHP application and your location ~ \.php$ block does not point to the correct document root.
You need to construct two PHP locations with different document roots.
If phpmyadmin is located at /var/www/phpmyadmin, you do not need an alias directive, as a root directive will be more efficient. See this document.
server {
listen 80;
server_name domain.tld;
root /var/www/domain.tld/html;
index index.php index.html index.htm;
location / {
}
location /nginx_status {
stub_status on;
access_log off;
}
location ~ \.php$ {
try_files $uri =404;
include fastcgi_params;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
location ^~ /phpmyadmin {
root /var/www;
location ~ \.php$ {
try_files $uri =404;
include fastcgi_params;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
}
The location ^~ /phpmyadmin is a prefix location that takes precedence over the regex location normally used to process .php files. It contains a location ~ \.php$ block which inherits a value of /var/www for the document root.
It is advisable to include fastcgi_params before defining other fastcgi_param parameters otherwise your custom values may be silently overwritten.
See this document for more.

Nginx - Use different directory for serving files while stripping out path from URL

I am trying to use different directory from where to serve the files, but have been unsuccessful. /var/www/site.app/public is where the root, but I want to serve news from /var/www/news/api instead, while having URL http://site.app/news/123, from which I want to remove the news part, because otherwise it would map to /var/www/news/api/news/123.
Judging by the debug logs, it seems that it gets rewritten correctly when first testing all location blocks, but after it is done rewritting, it goes through all of them again, and ends up serving content with location block /.
Here is my configuration file I have.
server {
listen 80;
server_name site.app;
root /var/www/site.app/public;
rewrite_log on;
error_log /var/log/nginx/error.log debug;
index index.php index.html;
location / {
try_files $uri $uri/ index.php?$query_string;
}
location /news/ {
root /var/www/news/api;
rewrite ^/news/(.*) /api.php?_=$1;
index index.php index.html;
}
location ~ \.(hh|php)$ {
try_files $uri /index.php =404;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
The root directive in your /news/ location currently does nothing. You are rewriting the URI to /api.php which then hits your \.(hh|php)$ location, which inherits the root from the parent server container.
You need a distinct location for /api.php, possibly /news/api.php. In which case you can construct a separate location block (possibly nested within /news/) where you can place fastcgi_pass code using the different root.
So this is not ideal solution, but it works. By default it would still allow access to api.php, but I am denying access to it by checking if the URL contains /news/
server {
listen 80;
server_name site.app;
root /var/www/site.app/public;
index index.php index.html;
location / {
try_files $uri $uri/ index.php?$query_string;
}
location = /api.php {
if ($request_uri !~ ^/news/) {
return 444;
}
root /var/www/site.app/news/;
try_files $uri $uri/ /api.php?$query_string =408;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
location /news/ {
rewrite ^/news/(.*) /api.php?$1;
}
location ~ \.(hh|php)$ {
try_files $uri /index.php =407;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}

Multiple applications Symfony2 in a single nginx vhost

I’d like to separate my main app and XHR requests on a Symfony2 project.
Here are my regular Sf2 controllers :
https://www.example.com/* => /web/app.php/*
https://www.example.com/app_dev.php/* => /web/app_dev.php/*
But I’d like to add XHR requests like that (on the same domain, to avoid CORS issues) :
https://www.example.com/xhr/* => /web/xhr.php/* (no dev environment required)
I’m trying to create a nginx vhost, but I don’t find the correct way :
server {
listen 443 default_server ssl;
server_name www.example.com;
root /var/www/example.com/current/web;
include ssl_config.conf;
location /xhr {
try_files $uri /xhr.php$is_args$args;
}
location / {
try_files $uri /app.php$is_args$args;
}
location ~ ^/(app|app_dev|xhr)\.php(/|$) {
fastcgi_pass 127.0.0.1:9000;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTPS on;
}
}
Your configuration will strip pathinfo during the redirect. Perhaps you should use:
try_files $uri /xhr.php$uri$is_args$args;
or simply:
try_files $uri /xhr.php$request_uri;

Location route not matching

I have a location which simply for some reason isn't triggering. I've tried the routes in all sorts of different orders, and still it doesn't work. When a user comes along and requests /_hostmanager/ it should trigger, but instead it gets the index.php page from the route.
The server config file is:
server {
index index.php index.html;
root /var/www/html;
server_name _;
listen 80;
# Logging
error_log /var/log/httpd/elasticbeanstalk-error_log;
# Route standard requests
location / {
try_files $uri $uri/ /index.php;
}
# Proxy Hostmanager
location /_hostmanager/ {
proxy_pass http://127.0.0.1:8999/;
}
# Include PHP
location ~ \.php {
# CGI Configuration
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include /etc/nginx/fastcgi_params;
fastcgi_index index.php;
# Zero-day exploit defense
try_files $uri $uri/ /index.php =404;
# Use socket for connection
fastcgi_pass unix:/tmp/php5-fpm.sock;
}
# Cache control
location ~* \.(jpg|jpeg|gif|png|css|js|ico|xml)$ {
log_not_found off;
expires 360d;
}
# Disable hidden files
location ~ /\. {
deny all;
}
}
Can anyone spot what my (probably stupid!) error is?
Thanks in advance! :)
Nevermind, I worked it out! For some reason using the reload command on nginx wasn't working. stopped and started and voila!

Resources