Nginx config for Yii 2 Advanced App Template - nginx

I would like to configure the Nginx web-server in such a way that:
Requests to the /index.php URI should be handled by public_html/frontend/web/index.php
Requests to the /admin/index.php URI should be handled by public_html/backend/web/index.php
Advice please where I'm wrong. Here is my config:
server {
listen 80;
server_name yii2.lo;
server_tokens off;
client_max_body_size 128M;
charset utf-8;
access_log /var/log/nginx/yii2-access.log main buffer=50k;
error_log /var/log/nginx/yii2-error.log notice;
set $host_path "/srv/http/yii2/public";
set $yii_bootstrap "index.php";
index $yii_bootstrap;
location / {
root $host_path/frontend/web;
try_files $uri $uri/ /$yii_bootstrap?$args;
}
location /admin {
root $host_path/backend/web;
try_files $uri $uri/ /$yii_bootstrap?$args;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_index $yii_bootstrap;
# Connect to php-fpm via socket
fastcgi_pass unix:/run/php-fpm/php-fpm.sock;
fastcgi_connect_timeout 30s;
fastcgi_read_timeout 30s;
fastcgi_send_timeout 60s;
fastcgi_ignore_client_abort on;
fastcgi_pass_header "X-Accel-Expires";
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param HTTP_REFERER $http_referer;
include fastcgi_params;
}
location ~* \.(js|css|less|png|jpg|jpeg|gif|ico|woff|ttf|svg|tpl)$ {
expires 24h;
access_log off;
}
location = /favicon.ico {
log_not_found off;
access_log off;
}
location = /robots.txt {
log_not_found off;
access_log off;
}
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
}

Long story short: use the first method provided below.
The rest of the answer is a list of recommendations.
I'm going to separate my answer in two sections.
In the first part, I will tell you the easiest and the fastest way to achieve your goal according to your desired URL requests, but it partly breaks the app structure, nothing serious, though.
In the second part, I will describe you where you made mistakes in your configuration file and I will show you a poorly written configuration for your needs which works.
I. Shared Hosting deployment
I highly encourage you to use this. This is an official way from Yii 2 documentation to make backend work at the same domain, although it helps to deploy a project to a shared hosting. And it doesn't require any additional nginx configuration, just a basic one for frontend root.
Let me write a simple list according to this guide:
Move contents from /backend/web to /frontend/web/admin.
Correct scripts' paths in /frontend/web/admin/index.php (and index-test.php, if you use it)
That's all, you have your backend at the same domain at /admin URL. Additionally, read the last section of the guide regarding cookies. The advanced template was designed to use different domains for each environment, therefore the guide describes backend config for shared hosting to keep cookies from frontend and backend separate.
Of course, don't forget to modify your /environments files for proper initialization of your project with /init script.
II. Nginx configuration
Mistakes
I'm not a profressional nginx administrator, but I can describe what's wrong in your configuration based on my personal experience and the documentation. Unfortunately, I won't be able to provide links to the documentation, because my current rating won't allow me to post more than 2 links.
Server context root
You do not have root directive in your server context. Thus, when ~ \.php$ location is matched, it doesn't have root at all and uses default nginx root. Try setting common root directive in the server context, then all locations will have it by default. For example:
server {
# Beginning of your configuration
# ...
root /srv/http/yii2/public/frontend/web;
# The rest of your configuration
# ...
}
Not having a higher context root is a common pitfall.
root instead of alias
Secondly, when a location is matched, the uri is appended to the location's root and that's the path the server attempts to look for. Thus, your /admin location suggests that the server search for $host_path/backend/web/admin. In your situation, you should use alias directive which tells the server that the matched location uri refers to alias path, not appended to root:
location /admin {
alias $host_path/backend/web;
# The rest of location
# ...
}
I recommend that you read related nginx documentation about location, root and alias directives.
Working but poorly written configuration
I post this sample configuration with comments for your understanding only, not for production use, I dicourage you to apply it for your production (until you're positive it's safe and sound).
It works, but it has an annoying defect: backend cannot find Yii2 entry script if you request it directly (like /admin/index.php), so it must be used with enablePrettyUrl set to true and showScriptName set to false, however it finds any other PHP script in the backend web root.
server {
# The beginning of your configuration
# ...
# By default we will provide frontend
root /srv/http/yii2/public/frontend/web;
index index.php;
location / {
try_files $uri $uri/ /index.php?$args;
}
location /admin {
# We use /web/index here to make backend call to php scripts
# distinct from frontend call
index /web/index.php;
alias $root_base/backend/web;
try_files $uri $uri/ /web/index.php?$args;
# Rewrite PHP requests from /admin to /web
# However, Yii2 entry script returns 404
location ~ ^/admin/.*\.php$ {
rewrite ^/admin/(.*)$ /web/$1;
}
}
location ~ ^/web/.*\.php$ {
# Make sure this location cannot be called externally
internal;
# Remember, that the uri of this location
# will be appended to this root!
root $root_base/backend;
# PHP settings for backend
}
location ~ \.php$ {
# PHP settings for frontend
}
# The rest of your configuration
# ...
}
Additionally, add baseUrl property to the request component in your Yii2 backend config and set it to /admin.
I hope my answer will help you deploying your Yii2 advanced project and understanding nginx more, nevertheless your question is 6 months old.

Here's my working config, based on accepted answer. My project backend directory is renamed to admin
# Example config for nginx
# frontend is available on yii-application.local/
# backend (admin) is available on yii-application.local/admin
# make sure that #app/frontend/config/main.php and #app/admin/config/main.php components sections are configured properly
# e.g. #app/frontend/config/main.php
# 'homeUrl' => '',
# ...
# 'components' => [
# 'request' => [
# 'baseUrl' => '',
# ],
# 'urlManager' => [
# 'enablePrettyUrl' => true,
# 'showScriptName' => false,
# ],
# ]
#
# e.g. #app/admin/config/main.php
# 'homeUrl' => '/admin',
# ...
# 'components => [
# 'request' => [
# 'baseUrl' => '/admin',
# ],
# 'urlManager' => [
# 'enablePrettyUrl' => true,
# 'showScriptName' => false,
# ],
# ]
server {
set $project_root /home/yii/apps/yii-advanced;
set $fcgi_server unix:/opt/php/var/run/php5-fpm.sock;
charset utf-8;
client_max_body_size 128M;
listen 80;
server_name yii-application.local;
root $project_root/frontend/web;
index index.php;
access_log /home/yii/apps/yii-advanced/logs/access-backend.log;
error_log /home/yii/apps/yii-advanced/logs/error-backend.log;
location / {
try_files $uri $uri/ /index.php?$args;
}
location /admin {
index /web/index.php;
alias $project_root/admin/web;
try_files $uri $uri/ /web/index.php?$args;
location ~ ^/admin/.*\.php$ {
rewrite ^/admin/(.*)$ /web/$1;
fastcgi_pass $fcgi_server;
include fastcgi.conf;
}
}
location ~ ^/web/.*\.php$ {
internal;
root $project_root/admin;
fastcgi_pass $fcgi_server;
include fastcgi.conf;
}
location ~* \.php$ {
try_files $uri =404;
fastcgi_pass $fcgi_server;
include fastcgi.conf;
}
location ~* \.(htaccess|htpasswd|svn|git) {
deny all;
}
}

Try to specify the config Nginx :
I use the configuration for "Advanced" template
in the domain configuration file, specify the frontend for so:
listen frontend.site.loc:80; # for frontend
specify the backend domain:
listen backend.site.loc:80; # for backend

This guy has done a very good job of creating advanced app nginx config (with subdomain which IMHO is the best setup): https://gist.github.com/Kison/45ec9ce3c1ebf422cbd42bd5ce04d8e4

Related

Nginx screen pops up on website homepage but rest of site works fine

I am working with a localhost site and been checking my nginx configuration files over and over again because the default homepage screen shows the 'WELCOME TO NGINX!" title. After awhile I figured out by typing /user I was able to by-pass the homescreen and actually able to login to the site. Everything works EXCEPT the homepage screen, which gets directed to the NGINX home screen page. I'm a bit a a loss as to why this is. Here is my nginx conf file:
server {
server_name zeragames.localhost;
root /var/www/html/zeragames/web; ## <-- Your only path reference.
location = /favicon.ico {
log_not_found off;
access_log off;
}
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
# Very rarely should these ever be accessed outside of your lan
location ~* \.(txt|log)$ {
allow 192.168.0.0/16;
deny all;
}
location ~ \..*/.*\.php$ {
return 403;
}
location ~ ^/sites/.*/private/ {
return 403;
}
# Block access to scripts in site files directory
location ~ ^/sites/[^/]+/files/.*\.php$ {
deny all;
}
# Allow "Well-Known URIs" as per RFC 5785
location ~* ^/.well-known/ {
allow all;
}
# Block access to "hidden" files and directories whose names begin with a
# period. This includes directories used by version control systems such
# as Subversion or Git to store control files.
location ~ (^|/)\. {
return 403;
}
location / {
# try_files $uri #rewrite; # For Drupal <= 6
try_files $uri /index.php?$query_string; # For Drupal >= 7
}
location #rewrite {
#rewrite ^/(.*)$ /index.php?q=$1; # For Drupal <= 6
rewrite ^ /index.php; # For Drupal >= 7
}
# Don't allow direct access to PHP files in the vendor directory.
location ~ /vendor/.*\.php$ {
deny all;
return 404;
}
# Protect files and directories from prying eyes.
location ~* \.(engine|inc|install|make|module|profile|po|sh|.*sql|theme|twig|tpl(\.php)?|xtmpl|yml)(~|\.sw[op]|\.bak|\.orig|\.save)?$|/(\.(?!well-known).*)|Entries.*|Repository|Root|Tag|Template|composer\.(json|lock)|web\.config$|/#.*#$|\.php(~|\.sw[op]|\.bak|\.orig|\.save)$ {
deny all;
return 404;
}
# In Drupal 8, we must also match new paths where the '.php' appears in
# the middle, such as update.php/selection. The rule we use is strict,
# and only allows this pattern with the update.php front controller.
# This allows legacy path aliases in the form of
# blog/index.php/legacy-path to continue to route to Drupal nodes. If
# you do not have any paths like that, then you might prefer to use a
# laxer rule, such as:
# location ~ \.php(/|$) {
# The laxer rule will continue to work if Drupal uses this new URL
# pattern with front controllers other than update.php in a future
# release.
location ~ '\.php$|^/update.php' {
fastcgi_split_path_info ^(.+?\.php)(|/.*)$;
# Ensure the php file exists. Mitigates CVE-2019-11043
try_files $fastcgi_script_name =404;
# Security note: If you're running a version of PHP older than the
# latest 5.3, you should have "cgi.fix_pathinfo = 0;" in php.ini.
# See http://serverfault.com/q/627903/94922 for details.
include fastcgi_params;
# Block httpoxy attacks. See https://httpoxy.org/.
fastcgi_param HTTP_PROXY "";
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param QUERY_STRING $query_string;
fastcgi_intercept_errors on;
# PHP 5 socket location.
#fastcgi_pass unix:/var/run/php5-fpm.sock;
# PHP 7 socket location.
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
}
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
try_files $uri #rewrite;
expires max;
log_not_found off;
}
# Fighting with Styles? This little gem is amazing.
# location ~ ^/sites/.*/files/imagecache/ { # For Drupal <= 6
location ~ ^/sites/.*/files/styles/ { # For Drupal >= 7
try_files $uri #rewrite;
}
# Handle private files through Drupal. Private file's path can come
# with a language prefix.
location ~ ^(/[a-z\-]+)?/system/files/ { # For Drupal >= 7
try_files $uri /index.php?$query_string;
}
# Enforce clean URLs
# Removes index.php from urls like www.example.com/index.php/my-page --> www.example.com/my-page
# Could be done with 301 for permanent or other redirect codes.
if ($request_uri ~* "^(.*/)index\.php/(.*)") {
return 307 $1$2;
}
}
host file:
127.0.0.1 localhost
127.0.0.1 zeragames.localhost
# The following lines are desirable for IPv6 capable hosts
::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
My main question: How do I get the homepage screen to work showing Welcome to Drupal 8! instead of pointing to the NGINX homescreen? As stated above, every other page works and is accessible. Just the homepage itself isn't!

nginx match no found when using a query string

I am a little stuck with Nginx not behaving as I expect it to?
When making a curl request to curl -I http://example.com/schedule/ajax.php I get the expected output of HTTP/1.1 200 OK
However, when I add a query string it fails curl -I http://example.com/schedule/ajax.php?m=item with no matches found: http://example.com/schedule/ajax.php?m=item
Additionally:
this project has Drupal which is fully functioning and its Nginx root is at / (as
in Drupal's index.php file is in /app/web/)
then the schedule directory is not a Drupal and if files are in /app/web/schedule/
the ajax.php is a special case as all other requests are processed by
index.php so for example http://example.com/schedule/view is
processed be /schedule/index.php (yes not /app/web/index.php)
so the short version is /schedule is not Drupal but / is
So my question is why do requests to http://example.com/schedule/ajax.php?m=item fail?
My nginx config is
server {
listen ${NGINX_LISTEN:-8080} default_server;
include /etc/nginx/helpers/*.conf;
root /app/${WEBROOT:-};
index index.php;
## rewriting /index.php to / because after https://www.drupal.org/node/2599326
## autocomplete URLs are forced to go to index.php
rewrite ^/index.php / last;
location /schedule/ajax.php {
add_header X-debug-message-ajax "a: $args q:$query_string" always;
#return 403;
try_files $uri /schedule/ajax.php?$args;
}
location /schedule/ {
## Disallow access to any dot files, but send the request to wordpress
location ~* /\. {
try_files /dev/null #php;
}
## Direct Access to .php files is not alled and is sent to wordpress instead
location ~* ^.+\.php$ {
try_files /dev/null #php;
}
## Try to find a file with given URL, if not pass to wordpress
try_files $uri /schedule/$uri/ /schedule/index.php?$args;
}
## The 'default' location.
location / {
include /etc/nginx/conf.d/drupal/location_prepend*.conf;
## Do not allow access to .txt and .md unless inside sites/*/files/
location ~* ^(?!.+sites\/.+\/files\/).+\.(txt|md)$ {
deny all;
access_log off;
log_not_found off;
}
## Replicate the Apache <FilesMatch> directive of Drupal standard
## .htaccess. Disable access to any code files. Return a 404 to curtail
## information disclosure.
location ~* \.(engine|inc|install|make|module|profile|po|sh|.*sql|.*sql\.gz|theme|twig|tpl(\.php)?|xtmpl|yml)(~|\.sw[op]|\.bak|\.orig|\.save)?$|^\/(\.(?!well-known).*|Entries.*|Repository|Root|Tag|Template|composer\.(json|lock))$|^\/#.*#$|\.php(~|\.sw[op]|\.bak|\.orig|\.save)$ {
deny all;
access_log off;
log_not_found off;
}
## Expiring per default for four weeks and one second, Drupal will overwrite that if necessary
expires ${NGINX_DEFAULT_EXPIRES:-2628001s};
## Disallow access to any dot files, but send the request to Drupal
location ~* /\. {
try_files /dev/null #drupal;
}
### Directives for installing drupal.
location ~* ^(/install.php|/core/install.php) {
try_files /dev/null #php;
}
## Direct Access to .php files is not allowed and is sent to Drupal instead
location ~* ^.+\.php$ {
try_files /dev/null #drupal;
}
## Try to find a file with given URL, if not pass to Drupal
try_files $uri #drupal;
}
## Main Drupal Location
location #drupal {
add_header X-debug-message-drupal "1" always;
include /etc/nginx/conf.d/drupal/location_drupal_prepend*.conf;
include /etc/nginx/fastcgi.conf;
fastcgi_param SCRIPT_NAME /index.php;
fastcgi_param SCRIPT_FILENAME $realpath_root/index.php;
fastcgi_pass ${NGINX_FASTCGI_PASS:-php}:9000;
include /etc/nginx/conf.d/drupal/location_drupal_append*.conf;
}
## PHP Location.
## Warning: This allows to execute any PHP files, use with care!
location #php {
add_header X-debug-message-php "$realpath_root : $fastcgi_script_name : $args" always;
include /etc/nginx/conf.d/drupal/location_php_prepend*.conf;
include /etc/nginx/fastcgi.conf;
fastcgi_pass ${NGINX_FASTCGI_PASS:-php}:9000;
include /etc/nginx/conf.d/drupal/location_php_append*.conf;
}
## Trying to access private files directly returns a 404.
location /sites/default/files/private/ {
internal;
}
}
As pointed out in the comments the issue was not with Nginx it was actually an error in my curl request.

Unable to run the wordpress and laravel side by side on nginx according to specified url structure

I have to run wordpress and laravel side by side on the nginx server. The url structure required is example.com (to show the wordpress content) and example.com/testapp (for the laravel application). The config I am using for nginx currently, is doing just opposite.
server {
listen 80 default_server;
server_name default;
root /home/forge/default/public;
#root /home/forge/apen;
index index.html index.htm index.php;
charset utf-8;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
access_log off;
error_log /var/log/nginx/default-error.log error;
error_page 404 /index.php;
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
}
location ~ /\.ht {
deny all;
}
}
Its handling all the routes starting with example.com except for example.com/testapp through laravel. example.com/testapp is serving the wordpress content. Wordpress folder is saved inside public folder of laravel.
I installed the wordpress seprately and and tried to create a separate server names in /etc/nginx/sites-available one for example.com and another for example.com/testapp. After this example.com is showing the wordpress content but example.com/testapp is not loading laravel content.
Add this to your vHost and try again! Hope it will work!
location /testapp/ {
# Do nothing. nginx will serve files as usual.
}
Let me know if it works!It will ignore the test app Directory and Wordpress will be able to take control of the Routes Having the /testapp/ Theoretically!

NGINX not caching or saving static files

I have ubuntu 14 on AWS ngnix is point to a website. I have tried everything but it does not serve up the static images. when I try to cache them. I have tired every combo of this but every time I go there are no files.
location ~* \.(css|js|jpeg|jpg|gif|png|ico|xml)$ {
access_log off;
expires 30d;
}
When I go to the directory there is no files in the root path. Any ideas?
Here is an official block usage https://www.nginx.com/resources/wiki/start/topics/examples/server_blocks/#
server {
# Replace this port with the right one for your requirements
listen 80 default_server; #could also be 1.2.3.4:80
# Multiple hostnames separated by spaces. Replace these as well.
server_name star.yourdomain.com *.yourdomain.com; # Alternately: _
root /PATH/TO/WEBROOT;
error_page 404 errors/404.html;
access_log logs/star.yourdomain.com.access.log;
index index.php index.html index.htm;
# static file 404's aren't logged and expires header is set to maximum age
location ~* \.(jpg|jpeg|gif|css|png|js|ico|html)$ {
access_log off;
expires max;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_intercept_errors on;
# By all means use a different server for the fcgi processes if you need to
fastcgi_pass 127.0.0.1:YOURFCGIPORTHERE;
}
location ~ /\.ht {
deny all;
}

How to combine rewrites with different roots in location blocks

I'm struggling to understand how to control rewrites to PHP scripts when the location blocks that do the rewrites require different roots.
Here's the simplified example. My catch-all front controller must be in the web root, but the firewall.php script must not be.
The purpose of this is to provide gated access to download files not under the root.
server {
# Requests for media forced through firewall script outside web root
# /path/to/secure-area/firewall.php
#
location ^~ /downloads/ {
root /path/to/secure-area;
rewrite ^/.+$ /firewall.php last;
}
# Regular requests bootstrap front controller under web-root
# /path/to/web-root/index.php;
#
location / {
root /path/to/web-root;
index index.php
if ( -e $request_filename ) {
break;
}
rewrite ^.+$ /index.php last;
}
# Execute PHP via php-fpm
# rewrites hitting this are not mapping request_filename properly
#
location ~ \.php$ {
if ( !-f $request_filename ) {
return 404;
}
include /usr/local/nginx/conf/fastcgi_params;
fastcgi_pass unix:/tmp/php.sock;
fastcgi_index index.php;
}
}
The obvious solution is having a common root, but this is not possible in my situation. I cannot place the secure location under the web root and the web root must stay as-is.
It looks as if the root directive is only effective within the location block that defines it. The rewrites are individually working fine, but when the ~ \.php block is hit, the root is lost.
I'm obviously doing it wrong, so how should I achieve this?
Untested, but something like this ought to help you. It uses the http://wiki.nginx.org/XSendfile to serve the protected content from a different root. Also uses try_files which is a much better pattern for Front Controllers.
server {
# More here: http://wiki.nginx.org/XSendfile
#
# To serve /downloads/some.zip
# get php to set the http header:
#
# X-Accel-Redirect: /downloads/some.zip
#
# and then the file /path/to/secure-area/downloads/some.zip
# will be sent by nginx
location /downloads/ {
internal;
root /path/to/secure-area;
}
location / {
root /path/to/web-root;
index index.php
try_files $uri $uri/ /index.php;
}
# make sure you read http://wiki.nginx.org/Pitfalls
location ~* \.php$ {
try_files $uri =404;
fastcgi_pass unix:/tmp/php.sock;
fastcgi_index index.php;
include /usr/local/nginx/conf/fastcgi_params;
}
}

Resources