Nginx separate apps in subdirectories - nginx

I am trying to move an app from apache server to nginx. The problem is that there are multiple apps in subdirectories and I can't find a proper way to configure the server.
What I need:
www.example.com serves from /srv/app
www.example.com/sub1 serves from /srv/app/sub1
www.example.com/sub2 serves from /srv/app/sub2
Each of the apps need the same config, so I extracted that in a snippet:
# snippets/app.conf
index index.php index.html index.htm index.nginx-debian.html;
location /system {
return 403;
}
# [a couple of other 403s excluded]
# Pass non-file URI to index.php
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# Use PHP
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
}
# Hide .htaccess
location ~ /\.ht {
deny all;
}
And in the main server file:
# [non-www and http redirects]
server {
# [listen directives]
server_name www.example.com;
root /srv/app;
include snippets/app.conf;
location /sub1 {
root /srv/app/sub1;
include snippets/app.conf;
}
# [other sub-apps included in the same way]
# [ssl stuff]
}
However, this gives me an error:
nginx: [emerg] location "/system" is outside location "/sub1" in /etc/nginx/snippets/app.conf:5
It's obvious from the error that /system is interpreted as being "absolute" www.example.com/system instead of the nested www.example.com/sub1/system. Can I somehow specify that I want the nested locations to be considered relative? Or I just have to repeat the whole near-identical config for every sub-app changing the prefixes?

It turns out that most of the repeating is not necessary in nginx.
The directives to use fastcgi for .php and hide /.ht files were already regexes so they affect everything. It's enough to specify index once and the default there stuff was redundant if I only want to use index.php.
As all the apps are nested on the filesystem in the same way as on web, specifying root was not necessary either.
What surprised me was that location ^~ /(system|data)/ { ... } matches not only www.example.com/system/, but also www.example.com/sub1/system/. I thought that ^~ should match only if the location start matches the regex...
# [non-www and http redirects]
server {
# [listen directives]
server_name www.example.com;
root /srv/app;
index index.php;
location ^~ /(system|data)/ {
return 403;
}
# Use PHP
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
}
# Pass non-file URI to index.php for all locations
location /sub1/ {
try_files $uri $uri/ /sub1/index.php?$query_string;
}
location /sub2/ {
try_files $uri $uri/ /sub2/index.php?$query_string;
}
# [other sub-apps included in the same way]
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ /\.ht {
deny all;
}
# [ssl stuff]
}
I also tried to replace the separate locations with
location ^~ /(sub1|sub2)/ {
try_files $uri $uri/ /$1/index.php?$query_string;
}`
but didn't succeed with that - this location somehow didn't ever match and everything got passed to the /index.php in base instead.

Related

How to serve subfolder as root using Nginx?

This is my server block at /etc/nginx/sites-enabled/mydomain;
server {
listen 80;
root /var/www/html;
index index.php index.html index.htm index.nginx-debian.html;
server_name mydomain.com;
location / {
try_files $uri $uri/ =404;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
}
location ~ /\.ht {
deny all;
}
}
Inside my /var/www/html/ folder I have folder1 and folder2. I can access both of these at mydomain.com/folder1 and mydomain.com/folder2. folder1 is currently being served as mydomain.conf/folder1 so no issues on that one.
However, I want to server folder2 as my main domain. So when I access mydomain.com it should serve whatever insides /var/www/html/folder2.
I literally tried every single answer I could find online (and I'm aware there are dozens of similar questions online) yet none of them worked for me. Sorry I'm a bit rookie and I appreciate your understanding.
EDIT: Both folder1 and folder2 contain PHP apps.
Your first option is to use
root /var/www/html/folder2;
and put folder1 under the /var/www/html/folder2. If you can't do it for some reason, your second option is to use the following config (I omit the try_files directive from your root location since try_files $uri $uri/ =404 is a default behavior):
server {
listen 80;
root /var/www/html/folder2;
index index.php index.html index.htm index.nginx-debian.html;
server_name mydomain.com;
location / {}
location /folder1/ {
root /var/www/html;
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
}
}
location ~ /\.ht {
deny all;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
}
}
If you want the /folder1 URL to be workable too, you either change location /folder1/ { ... } to location /folder1 { ... } or add an explicit redirect (this won't needed if you put your folder1 under the /var/www/html/folder2, in that case this redirect will be issued automatically):
location = /folder1 {
return 301 /folder1/$is_args$args;
}
I prefer the second way since using the first one you made any route started with /folder1 prefix (but different from it, e.g. /folder10) unavailable for your root web app.

Nginx shows 404 error for sub link and paths

I have using nginx for laravel project. When I use the domain name it shows the home page. But When I click any one of the link it does not work. And shows 404 Not Found error.
http://www.myhomepage.com // working
http://www.myhomepage.com/about // not working
I have using the following configuration.
server {
listen 80;
root /var/www/abc-company-website/public;
index index.php index.html index.htm index.nginx-debian.html;
server_name myhomepage.com localhost;
location / {
try_files $uri $uri/ =404;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
}
location ~ /\.ht {
deny all;
}
}
You probably want to adjust the location / block to pass the query string, as per the documentation:
location / {
try_files $uri $uri/ /index.php?$query_string;
}
Laravel 5.8 Docs - Installation - Pretty URLs - Nginx

Getting 500 internal error on redirect rule of alias in nginx

I am newbie to nginx server. I am getting stuck in URL redirection. I have following lines to default file.
server {
listen 80;
root /home/ubuntu/web/server/current/public;
index index.php index.html index.htm index.nginx-debian.html;
server_name _;
error_log /home/ubuntu/web/error.log info;
location / {
# try_files $uri $uri/ /index.php?$query_string;
# try_files $uri $uri/ =404;
}
rewrite ^/web/(.*) /web/;
location /web/ {
alias /home/ubuntu/web/client/web/;
# try_files $uri $uri/ index.html;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
}
location ~ /\.ht {
deny all;
}
}
what I expect from above rewrite rule is - all URLs like - http://example.com/web/login, http://exmpale.com/web/dashboard will be redirected to /home/ubuntu/web/client/web/ and the default page to hit is index.html file.
When I open the error log file then i found error like -
rewrite or internal redirection cycle while internally redirecting to "/web/index.php", client: ip_address, server: _, request: "GET /web/ HTTP/1.1", host: "ipaddress"
What i am doing wrong here.
Answer credit goes to #RichardSmith, he provided possible error which is in right direction. I figure out my mistake in nginx rewriting rule.
rewrite ^/web/(.*) /web/;
location /web/ {
alias /home/ubuntu/web/client/web/;
# try_files $uri $uri/ index.html;
}
Instead of above I should have following-
rewrite ^/web/(.*) web/;
location web/ {
alias /home/ubuntu/web/client/web/;
# try_files $uri $uri/ index.html;
}
Server consider path as absolute whenever / placed before web. Thus rewrite statement tries to redirect to fallback file which is not existed in absolute path. Eventually, rewrite statement makes never ending loop.

Location not working for files but only for path

I have a nginx.conf that looks like this:
server {
...
root /var/opt/data/web;
...
location ~* \.(?:eot|woff|woff2|ttf|js)$ {
expires 1M;
}
...
location /one {
root /var/opt/data/alternatives;
try_files $uri $uri/ =404;
}
location /two {
root /var/opt/data/alternatives;
try_files $uri $uri/ =404;
}
}
when I curl http://localhost/one/ I get the content of index.html stored in /other. But when I curl .../localhost/one/foo.js the file is not found and I get this in the error.log:
open() "/default/foo.js" failed (2: No such file or directory)
I tried other variants like location ~ (one|two), location /one/ or even location ~ /(one|two) but all of them didn't work.
The complete config consists of a lot more locations, but I guess the cause of my problem is the location where I set up .js resources to expire -1 because this prevents changing the root to what I need.
If this matters: I use nginx 1.15.2. In case you are wondering why I have this strange alternatives directory: the web directory is created by a CMS software while alternatives is git pulled.
nginx chooses a one location to process a request. Your location ~* \.(?:eot|woff|woff2|ttf|js)$ block processes any URI that ends with .js, and its root value is inherited from the outer block as /var/opt/data/web.
Where you have multiple roots, you need to ensure that those location blocks take precedence, by using the ^~ modifier. See this document for details.
For example:
server {
...
root /var/opt/data/web;
...
location ~* \.(?:eot|woff|woff2|ttf|js)$ {
expires 1M;
}
...
location ^~ /one {
root /var/opt/data/alternatives;
try_files $uri $uri/ =404;
location ~* \.(?:eot|woff|woff2|ttf|js)$ {
expires 1M;
}
}
...
}
If you need your expires rule to apply to the other roots, you will need to repeat the location within that scope, as shown above.
As an alternative, the expires directive can be used in conjunction with a map. See this document for details.
For example:
map $request_uri $expires {
default off;
~*\.(eot|woff|woff2|ttf|js)(\?|$) 1M;
}
server {
...
root /var/opt/data/web;
expires $expires;
...
location ^~ /one {
root /var/opt/data/alternatives;
try_files $uri $uri/ =404;
}
...
}

nginx rewrite sub url

How can I solve this problem: I want to set up nginx conf file to meet below criteria:
http://www.example.com/site1/article/index.php?q=hello-world -> http://www.example.com/site1/article/hello-world
httb://www.example.com/site2/article/index.php?q=goodbye-world -> httb://www.example.com/site2/article/goodbye-world
httb://www.example.com/site3/article/index.php?q=open-new-world -> httb://www.example.com/site3/article/open-new-world
There are multiple sites after example.com, I want to make the url look clean by using nginx configuration.
But my below configuration doesn't work. Someone help me?
server {
listen 80;
listen [::]:80;
root /var/www/example.com/public_html;
index index.php index.html index.htm;
server_name www.example.com;
location ~ /article/ {
try_files $uri /site1/article/index.php?q=$1;
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
}
}
}
You would like the client to present a URL like /xxx/article/yyy which is then internally rewritten to /xxx/article/index.php?q=yyy.
You need to capture the components of the source URI in order to use them later. You have a $1 in your question, but you are missing the expression to actually give it a value. With the minimum number of changes, this works:
location ~ ^(.*/article/)(.*)$ {
try_files $uri $1index.php?q=$2;
location ~ \.php$ { ... }
}
However, you do not need to use a nested location for PHP, as long as the PHP regex location appears above the other regex location, it will process all php files. For example:
location ~ \.php$ { ... }
location ~ ^(.*/article/)(.*)$ {
try_files $uri $1index.php?q=$2;
}

Resources