rewrite rules for nginx and Codeigniter - nginx

I have implemented a php application in codeigniter and now want to deploy it to the nginx server. Before deploying I checked my nignx configuration on my localhost using MAMP server. It is working correctly. But, this configuration is not working on the live server. As a beginner in nginx, I am not understanding where is the mistake here. In live server, I can not write in the main nginx.conf file. I have a separate configuration file like "abc" for my application "abc". And all my application files are under "abc/xyz" directory. Here is my sample confuguration,
location /abc {
root /srv/www/htdocs/apps/;
index index.html index.htm index.php;
location /xyz {
try_files $uri $uri/ /abc/xyz/index.php;
}
location ~ \.php(\/(\w+))*$ {
try_files $uri =404;
rewrite (.+)\.php(\/(\w+))*$ $1.php break;
include /etc/nginx/fastcgi_params;
fastcgi_index index.php;
fastcgi_pass unix:/var/run/php-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
Here, I can see my welcome page https://myapplication/abc/xyz. But if I want to navigate other pages like https://myapplication/abc/xyz/other_pages, it is showing "404 Page not found". I have checked the other solutions but none of them is not working in this case. Thanks in advance for the help!

The location /xyz block is nested within the location /abc block. The nested block is required to precess URIs with a prefix of /abc/xyz.
If there are other regular expression location blocks surrounding your location /abc block, you should use the^~` modifier.
For example:
location ^~ /abc {
...
location /abc/xyz {
...
}
...
}
See this document for more.

Sorry for the late answer. It was actually very silly mistake. My controller page name was in small character. This is why it was not working. My configuration is okay. The first letter of the controller page should be in capital character. For example, my controller name is Home. So my php file name must be Home.php not home.php.

Related

How to prevent rewrite after deny

I have a website inside "/directory/", and a special variation of the website inside "/directory/subdirectory/" which should only be accessible by a few specific IP addresses. The subdirectory, however is a virtual URL, the website code is still in the parent directory called "directory" in this example. So I need rewrites.
This is the relevant part of my current nginx config file:
location /directory {
# here are various rewrites for my website
location /directory/subdirectory/ {
allow 10.0.0.0/8; # example range of IP addresses allowed
deny all; # disable access for others
rewrite ^/directory/subdirectory/(.*)$ /directory/$1 last; # the website location is still in the parent folder but the PHP code knows this specific version is to be used when the user surfs into subdirectory, which is why there is this rewrite
}
try_files $uri $uri/ /directory/index.php?q=$uri&$args;
}
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
include fastcgi.conf;
fastcgi_read_timeout 43200;
}
The problem I'm facing: I don't know how to stop the execution as soon as the "deny all" hits. If you're surfing into the subdirectory, the rewrite always executes, no matter if your IP is allowed or not by the directives above it. So someone surfing to the subdirectory with an IP address which is not allowed can see the website inside subdirectory, which is of course not what I want. If I comment out the rewrite, then the allow/deny directives work as they are supposed to.
So: how can I specify this rewrite is ONLY to be executed if the visitor is not denied?
Tried adding "error_page 403 /403.html;" to that location after the "deny all;" directive but it only changes the 403 page (and can only be seen again when commenting the rewrite rule in the subdirectory). Been searching the net for days already with various search terms to make this happen, and been fiddling with variations of the config, but to no avail.
Also: the "deny all" doesn't work anymore as soon as I surf to an URL inside subdirectory, ending with ".php". I assume it is because of the "location ~ .php$" directive, getting priority for some reason over the nested location directives above. I could get around this by doing:
location ^~ /directory/subdirectory/ {
allow 10.0.0.0/8; # example range of IP addresses allowed
deny all; # disable access for others
rewrite ^/directory/subdirectory/(.*)$ /directory/$1 last;
}
location /directory {
# here are various rewrites for my website
try_files $uri $uri/ /directory/index.php?q=$uri&$args;
}
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
include fastcgi.conf;
fastcgi_read_timeout 43200;
}
Now the "location ^~ /directory/subdirectory/" directive gets priority over the "location ~ .php$" directive which makes the "deny all" work but I don't know if that's the way to go since it doesn't seem like the most "clear to read" solution because I move something from within the "directory/" location out of that location block. And also, that still doesn't solve my main problem (only making the "rewrite ^/directory/subdirectory/(.*)$ /directory/$1 last;" execute for allowed IP addresses and not those getting denied by the "deny all".
Thank you.
The issue you are facing is related to the precedence/order in which nginx handles it's directives. A detailed explanation can be found here (hats off to the author!):
In their execution order the phases are post-read, server-rewrite,
find-config, rewrite, post-rewrite, preaccess, access, post-access,
try-files, content, and finally log
Since "rewrite" comes before "access", the "rewrite" directive is handled first.
Since "if" is handled in "rewrite"-phase as well, one could write:
location ~ \.php$ {
if ($remote_addr != "172.17.0.1") {
return 403;
}
rewrite ^ /your-redirect last;
}

Yii2 adanced application and nginx configuration (index directive configuration)

I'm trying to build proper server configuration for nginx serving Yii2 advanced template where backend hosted in a subfolder inside same domain name as frontend.
In this case path_to_yii2 contains whole Yii2 application template and we have these requirements:
path_to_yii2/frontend/web -> should be webroot of / location
path_to_yii2/backend/web -> should be webroot of /backend location
Static content in both folders should be properly served. PHP files should work in both cases.
I wrote and tested such configuration:
server {
listen 80;
server_name localhost;
root <path_to_yii2_application>;
location ~* ^/backend/(.+)$ {
try_files /backend/web/$1 /backend/web/$1/ /backend/index.php?$args;
index /backend/$1/index.php; # not working in case of exact /backend/ request
location ~* ^/backend/(.+\.php)$ {
#fastcgi_pass 127.0.0.1:9000;
fastcgi_pass unix:/var/run/php5-fpm.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root/backend/web/$1;
}
}
location / {
try_files /frontend/web/$uri /index.php?$args;
index /$uri/index.php; # not working at all, but / location is served by php even without this line
}
location ~ \.php$ {
#fastcgi_pass 127.0.0.1:9000;
fastcgi_pass unix:/var/run/php5-fpm.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root/frontend/web/$fastcgi_script_name;
}
}
And I have some unresolved problems with such configuration. I tested six different options:
FRONTEND:
Static content under / location should be served directly from frontend/web subfolder of yii2 application folder.
Nonexistent content here should be redirected to frontend/web/index.php?$args and served using ~ .php$ location with fastcgi.
Directories under / location should return indexes, if needed served with ~ .php$ location and fastcgi.
BACKEND:
Static content under /backend location should be served directly from backend/web subfolder of yii2 application folder.
Nonexistent content here should be redirected to backend/web/index.php?$argsand served using ~ .php$ location with fastcgi.
Directories under /backend location should return their indexes, if needed served with ~ .php$ location and fastcgi.
I have troubles with directories and their indexes (3 and 6).
First of all, directories for frontend section not working at all, seems that index /$uri/index.php; is wrong for some reason.
Secondly, directories for backend working except exact /backend/ url. Nginx doesn't serve index directive in =/backend/ case.
As a temporarily workaround for backend I added few lines for this exact url:
location = /backend {
return 301 https://$server_name/backend/index.php;
}
location = /backend/ {
return 301 https://$server_name/backend/index.php;
}
How to fix these indexes correctly and what I'm doing wrong?
P.S. There are some similar questions, like Migrating Yii2 from Apache to Nginx - failed on backend app (doesn't provide correct answer, recommends using subdomain) and Nginnx config for Yii 2 Advanced App Template (suggested to move backend content inside yii2 application to frontend folder). I believe that nginx configuration is a proper way of congiguring yii2-application template.
There is also https://github.com/mickgeek/yii2-advanced-one-domain-config repositary which not works in nginx > 1.8.1.
Interesting that apache just needs a symbolic link to make this work. Nginx before 1.8.1 too.
Yii2 application template can be git cloned from here: https://github.com/yiisoft/yii2-app-advanced.git

NGINX rewrite requests to file outside root

Currently I'm running webprojects with the following directory structure (simplified):
project_folder/
public/
root/
index.php
What I want to do is set the root in the server block to:
root /project_folder/root/;
But when a request location does not exists I want it to forward the request to project_folder/index.php. I tried the following:
try_files $uri ../index.php?$query_string;
But this doesn't seem to work.
The same goes for a request that starts with $document_root/public/* which need to be forwarded to: $document_root/../public/*
I did manage this by adding a index.php in the /project_folder/root/ folder which includes the /project_folder/index.php. For the public folder I created a symlink. I could probably solve this by adding an alias for the location /public/ however I'm trying to keep my config as generic as possible.
I'm trying to prevent setting the project_folder as a root folder as it sometimes contains files I prefer not to be accessed from the web. Introducing the 'root' folder is new but I'm trying to do this as efficient as possible. Existing webprojects do not have the root folder yet.
Is what I'm trying to do possible and how would I be able to achieve this.
Thanks in advance.
Usually PHP files are processed by a location ~ \.php$ block (or similar). I assume that index.php is not the only PHP file in your application, and to process PHP files within the /root/ directory structure, that location will need to use root /project_folder/root.
You can specify a different root for URIs which begin /public and use a named location to execute the out-of-root index.php file.
Something like this:
root /project_folder/root;
location / {
try_files $uri $uri/ #index;
}
location /public {
root /project_folder;
}
location #index {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME /project_folder/index.php;
fastcgi_pass ...;
}
location ~ \.php$ {
try_files $uri =404;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass ...;
}
It is simple to add an alias:
location /public {
alias /absolute/path/to/public;
}

Nginx location: 403 error / File not found

I set up my domain on my server using nginx. So far so good my homepage works. But now I wanna add some locations for later test of programming. My plan is to call diffrent projects like mydomain.com/php/myprogramm.php
So I add some folder in /var/www/mydomain.com/php (my side index is in /var/www/mydomain.com/html)
Entering www.mydomain.com/php/ leads to an 403 error and mydomain.com/php/myprogramm.php says File not found...
this is my nginx file:
server {
listen 80 default_server;
#listen [::]:80 default_server ipv6only=on;
# Make site accessible from http://localhost/
server_name mydomain.com www.mydomain.com;
location / {
root /var/www/mydomain.com/html;
index index.html index.htm;
}
location /php/ {
root /var/www/mydomain.com;
}
location /js/ {
root /var/www/mydomain.com;
}
location /node/ {
root /var/www/mydomain.com;
}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
# # NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
#
# # With php5-cgi alone:
# fastcgi_pass 127.0.0.1:9000;
# # With php5-fpm:
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
}
}
Of course when I set up my domain I also set sudo chown -R www-data:www-data /var/www/mydomain.com/html and sudo chmod 755 /var/www
Some ideas someone? :/
Problems analysis
The first golden rule is:
nginx always serves request from a single location only. (Re-)read http://nginx.org/en/docs/http/request_processing.html.
Based on your configuration:
Requests to (www.)mydomain.com/php/<whatever> for files not ending with .php will be served by location /php/ from /var/www/mydomain.com/php/<whatever>
Requests to (www.)mydomain.com/<whatever>.php will be served by location ~\.php$ from <default root ('html' by default)>/<whatever>.php
The first problem here is that you are not serving .php files from where you think you are. Learn from location documentation how the location block serving a request is chosen.
You will note that the 'File not found' error was not an nginx error, but a message generated by PHP. That helps to know whether the problem comes from (frontend or backend).
Now about that 403: it seems nginx has trouble accessing the location where it is supposed to serve content from. Check /var/www/mydomain.com/php/ (directory + contents) rights.
Proposed pieces of advice
Your configuration looks suboptimal.
If you use the same root in lots of location blocks, why not moving it one level upper so it becomes the default (which yo ucan override in specific locations where needed)?
You can used nested locations, ie to solve you PHP files serving problem. Note that it is always a good idea to enclose regex locations inside prefix locations (What is the difference? Read location documentation). The reason is regex locations are order-sensitive, which is bad for maintenance. Prefix locations are not since only the longest match with a request URI will be chosen.
Here is a propsed updated version of part of your configuration:
root /var/www/mydomain.com;
location / {
root /var/www/mydomain.com/html;
index index.html index.htm;
}
location /php/ {
location ~ \.php$ {
# Useless without use of $fastcgi_script_name and $fastcgi_path_info
# Moreover, requests ending up here always end with .php...
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
# You seem to have copy-pasted this section without understanding it.
# Good understanding of what happens here is mandatory for security.
}
}
I suggest you read the documentation about fastcgi_split_path_info, $fastcgi_script_name and $fastcgi_path_info.
For my testing right now I fixed the issue quite simply.
I forogt to check my php.ini and change the cgi.fix_pathinfo to 0
Also I changed the group for my folders (still had root inside) to www-data.
At the end I updated my configuration: I set root /var/www/mydomain.com; in my server block (server{})
That's all I did.
But I will keep your advice in mind for later issues.
Thanks for your help I appreciate it.

Nginx root directive inside location block is not working as I expect

I'm having a big headache while configuring Nginx to work inside a location block.
I'm developing a web application with Laravel, and it is located at /srv/http/zenith. With Laravel, the index is inside the public folder, so I'm trying to reach it using the following configuration:
location /zenith/ {
root /srv/http/zenith/public;
try_files $uri $uri/ /index.php?$query_string;
location ~ \.php$ {
fastcgi_pass unix:/run/php-fpm/php-fpm.sock;
fastcgi_split_path_info ^(.+\.php)(.*)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
But it gets me 404 error everytime. As I read from Nginx documentation, Nginx does not remove the path from the URI, so even inside /zenith/ block, all URIs still start with /zenith/. This way, example.com/zenith points to /srv/http/zenith/public/zenith when I want /srv/http/zenith/public.
How do I fix this error? I expected that Nginx removed this unwanted part automatically, but it seems to be not this way.
You need to understand the difference between a root and alias. A root maps the URI / to the directory mentioned and expects all URI parts after it to match the on disk tree. Alias maps the location of the block it's part of to the directory mentioned and expects all URI parts after this location to match the on disk tree. Since root inside a location block still maps the / URI, the part after / needs to exist on disk for things to work. In the common case you will use root for the document root and alias for location blocks.

Resources