Nginx rewrite throws out 404 Not Found - nginx

After adding rewrite block, the Ubuntu 12.04 server hosting Rails 3.2.12 app throws out 404 Not Found error when entering mysite.com/nbhy.
Here nbhy is a symlink under root /var/www/ pointing to /var/www/nbhyop/current/public and it is for hosting rails app. The purpose of the rewrite is to rewrite to /nbhy/authentify/sigin when user entering /nbhy or /nbhy/
Here is server block in nginx.conf:
server {
listen 80;
server_name mysite.com;
root /var/www/;
passenger_enabled on;
rails_env production;
passenger_base_uri /nbhy;
}
location / {
rewrite "/nbhy" /nbhy/authentify/signin last;
rewrite "/nbhy/" /nbhy/authentify/signin last;
}
}
The error.log on nginx for the error is:
2013/06/09 21:36:31 [error] 32505#0: *1 open() "/var/www/nbhy/authentify/signin" failed (2: No such file or directory), client: 67.173.143.107, server: mysite.com, request: "GET /nbhy HTTP/1.1", host: "mysite.com"
Before adding rewrite location block, the system could bring up login page with url mysite.com/nbhy/authentify/signin. But now it throws out error after adding the rewrite block. What's wrong with the rewrite?

The location block must be within the server block:
server {
listen 80;
server_name mysite.com;
root /var/www/;
passenger_enabled on;
rails_env production;
passenger_base_uri /nbhy;
location / {
# Matches /nbhy /nbhy/ /nbhy////////////...
location ~ ^/nbhy/*$ {
return 301 /nbhy/authentify/signin;
}
# Other rules (regex) goes here
}
}
The symbolic link is from no concern at this stage of processing.
You are using rewrite, were the first pattern is always a regular expression. Mohammad AbuShady was absolutely right with his answer of using a more specific location. But using a rewrite is not necessary, a return is better because we want nginx to abort execution and simply—well—return.
Also note how I enclosed the regular expression within the generic block location / {} which matches all locations. This is the proper way to write location blocks according to Igor Sysoev. See this forum post for more info.
My configuration above is also catching URLs with more than one slash (hence the *) and is meant as a more user friendly matching because a user might simply type too many slashes. No need to punish them, instead answer with a proper redirect.
I hope this helps!
Related Links
How nginx processes a request

If I understand correctly, you have a URI your-host/nbhy which you want to rewrite to your-host/nbhy/authentify/signin, which should be linked to /var/www/nbhy/authentify/signin, which is symlinked to /var/www/nbhyop/current/public/authentify/signin?
It looks like nginx is complaining about not finding /var/www/nbhy/authentify/signin. Since you have a symlink from /var/www/nbhy to /var/www/nbhyop/current/public, there has to be a folder /var/www/nbhyop/current/public/authentify/signin. Are you sure there is one, and that your www-data user (or whatever user you're using) has rights to the directories above it?
Also, nginx has an option for disabling symlinks. Try setting that to off. That's the default, I know, but there might be another file that sets it to on.
It might also be that nginx doesn't follow the symlink because you added last to your rewrites. Try removing that, and see if it works then.

why not try adding a more specific location block
location ~ /nbhy/?$ {
rewrite ^ /nbhy/authentify/signin last;
}
or you could remove the regex but it would match longer urls like /nbhy/one/two
location /nbhy {
rewrite ^ /nbhy/authentify/signin last;
}

Related

Serving static website in nginx, wrong path for static files

I'm trying to use nginx to serve a static website that was given to me. Its folder structure is like this:
static_website/
index.html
www.example.com/
resources.example.com/
uploads.example.com/
The index.html file in the root is the one generated by httrack and it simply contains a redirect to www.example.com/index.html.
Inside the folder www.example.com are all the html files, in the other two folders are the css, javascript and image files.
Here is the nginx configuration:
server {
index index.php index.html index.htm;
server_name example.com;
location / {
root /var/www/static_website/www.example.com;
try_files $uri $uri/ =404;
index index.html;
}
}
I can navigate through the pages, but the css, javascript and image files are not loaded.
The path to one of the css files inside the html is like this:
href="../resources.example.com/style.css"
The only way I managed to get this working was to have the have the url like this:
example.com/www.example.com/
This way, all the path are correct. I'd like to avoid this and have simply example.com.
Is there a way to do this?
It looks like the site was originally intended to operate with ugly URLs like //example.com/www.example.com/.
But the path-relative URIs for the resources should work just fine relative to /, you just need to provide a location block which matches /resources.example.com/.
For example:
location / {
root /var/www/static_website/www.example.com;
try_files $uri $uri/ =404;
index index.html;
}
location /resources.example.com/ {
root /var/www/static_website;
}
I originally commented that you should try this:
location ~ \.(css|js|jpg|png|svg)$ {
root /var/www/static_website;
}
Which achieves a similar goal, but Nginx will process prefix locations more efficiently that regular expression locations.
I want to share my experience with this problem for others encountering similar issues as the solution was not so obvious to me
My setup and problem in particular had to do with cloudlflare settings which i was using to leverage TLS instead of handling it on the origin server for one of my 2 sites. if you are serving your site from a CDN that supports encryption and you use nginx on your origin consider the following setup:
# static1.conf
{ server_name static1.com; root: /var/www/static1/public; listen 80; listen 443; }
# static2.conf - no tls setup in nginx, figured id let cloudflare handle it
{ server_name static2.com; root: /var/www/static2/public; listen 80; }
static1 was setup at the origin with letsencrypt to handle tls connections
static2 was setup at the origin without any tls configuration
from left to right, here are the appropriate cloudlfare TLS modes which allowed me to access the correct files thru nginx
The distinction between full and flexible is that full mode lets the origin handle the certificate.
Initially I had the static2 site misconfigured as full, which lacked a listen directive for 443 causing nginx to serve static1 instead.
I realize the original question has nothing to do with cdn's or cloudflare but this scheme / protocol mismatch cost me a few hours and I am hoping to save someone else from similar grief
Honestly I am surprised nginx doesn't stick to matching on server_name and that oit implicitly matches on scheme as a fallback (or atleast appears to), even without a default_server specified - and without any meaningful messages in the logs to boot! Debugging nginx is a nightmare sometimes.

Nginx rewrite requests to subdomain.tld/files/* to external domain

I'd like to rewrite all requests to Nginx matching http://*.examle.tld/files/* to http://$1.otherdomain.tld/files/?file=$2. I'd also like to rewrite the same request without the subdomain i.e. http://example.tld/files/* to http://otherdomain.tld/files/?file=$1
The reason for this is to use production files from local development without having to sync folders.
This is what I've got so far, however without success:
location / {
...
rewrite ^http://(\w+)\.(.*)/files/(.*) http://$1.otherdomain.tld/inc/reader.php?file=$3;
rewrite ^.*/files/(.*) http://$1.otherdomain.tld/inc/reader.php?file=$1;
...
}
Thank you for any assistance.
You cannot use the server name as part of the rewrite directive's regex. If you have a server block with a wild card server_name as described here, you can use a named capture for use later within the block.
For example:
server {
server_name ~^(?<sub>\w+\.)?example\.tld$;
location /files/ {
rewrite ^/files(.*)$ http://${sub}otherdomain.tld/files/?file=$1 permanent;
}
}
See this document for details.

stuck on nginx location directive

I am working on windows and using Winginx, modifying the nginx.conf file under conf folder. I have changed up the server block listening to port as follows:
server{
listen 127.0.0.1:80;
log_not_found off;
charset utf-8;
access_log logs/access.log main;
location /images/ {
root home/localhost/public_html;
index index.php index.html;
}
}
The images folder is under the home folder in winginx and is added as a domain through the hostseditor. However, when I use the URL http://images, I get the 404 error.
If the location directive is changed to:
location / {
}
Everything works fine then. Neither do any regular expressions work except if I match the '/'. I have read up on location directive but could not find any relevant reason. Would be great help if anyone could point out the error. Thanks.
The reason is that the location directive matches URI (absolute path of the Request-URI to be more precise), not Host.
When you use http://images, your browser sends request like this:
GET / HTTP/1.1
Host: images
Notice that request URI is /.

Nginx 502 when serving error page content?

I've been setting up Nginx as a reverse proxy for an app on the server. Part of this includes a maintenance page that has external content (like images). I was able to find a method for setting up an error page with images returning 200, but it looks like a reverse proxy will change the whole environment. Here's the original solution from nginx maintenance page with content issue
error_page 503 #maintenance;
location #maintenance {
root /path_to_static_root;
if (!-f $request_filename) {
rewrite ^(.*)$ /rest_of_path/maintenance.html break;
}
return 200;
}
The Reverse Proxy is configured as:
location / {
proxy_pass http://127.0.0.1:9007/;
proxy_redirect off;
}
The Problem is that when a file is found to exist in the "maintenance" root, something goes wrong and the server returns a 502. Anyone know what the cause could be?
Some speculation I'm wondering if server listens on port 80, it somehow passes any good file request back into the proxy. If that were true, how would that be avoided?
Edit
Here's the error in the nginx log. I am directly trying to access 50x.html. Not sure why this would occur?
2012/02/17 19:39:15 [error] 21394#0: *13 connect() failed (111: Connection refused) while connecting to upstream, client: (my ip address), server: _, request: "GET /50x.html HTTP/1.1", upstream: "http://127.0.0.1:9007/50x.html", host: "domain.com"
It looks like it is indeed trying to GET from the app and not the root. How can I bypass this?
Edit 2
I originally thought I had found an answer where a change was made for nginx v1.0.12 but it did not solve the problem. It involved a similar situation but my guess is the fix was too specific.
You shouldn't need to involve the backend (I.E., shouldn't use proxy pass) since your maintenance page should be a static html file that Nginx can serve directly.
Assuming you have a setup configured as ...
server {
listen 80;
server_name example.com;
root /path/to/webroot;
# Regular locations etc
...
}
Create a folder called "503_status" and put your maintenance page in there as "503.html".
With that in place, create a file called "maintenance.default" under the Nginx directory with the following content ...
error_page 503 /503_status/503.html;
# Candidate for redirection if not ending with one of these extensions.
if ( $request_uri !~ \.(jpg|gif|png|css|js)$ ) {
set $maint "Tr";
}
# Candidate for redirection if not a request for the maintenance page
if ( $request_uri !~ ^/maintenance/$ ) {
set $maint "${maint}ue";
}
# Redirect to a location where the status code will be issued
if ( $maint = True ) {
rewrite ^ /maintenance/ redirect;
}
# Due to Nginx quirk, issue the status code in a location context.
# Make "internal" to prevent direct browsing.
location /maintenance {
internal;
return 503;
}
# 503_status folder as "internal" so no direct browsing
location 503_status {
internal;
alias /server/path/to/503_status/folder;
}
Whenever you put to put the site into maintenance, just include the file as follows ...
server {
listen 80;
server_name example.com;
root /path/to/webroot;
include /server/path/to/maintenance.default;
# Regular locations etc
...
}
This will serve your maintenance page as well as any resources it needs (just make sure extension is in the list). The backend server does not come into play at all.

Nginx redirect if cookie present

I've seen some limited resources on checking for cookies with Nginx, but I couldn't really find the answer I was looking for, hopefully some of you Nginx masters can give me a hand.
Essentially I have a vhost that I'd like to redirect to a different domain unless the user has a cookie, here is what I've created:
server {
listen 80;
server_name example.com;
if ($http_cookie ~* "dev_cookie" ) {
root /home/deploy/apps/example/current/public;
passenger_enabled on;
rack_env production;
break;
}
rewrite ^/(.*) http://beta.example.com/$1 permanent;
}
But it doesn't seem to work, I get the error:
[emerg]: "root" directive is not allowed here in /opt/nginx/conf/nginx.conf:45
I'm not sure how to proceed here, any ideas guys?
That makes sense.
I would define another virtual host (beta.example.com) with that different root folder
and upon encountering cookie - do a rewrite
You can't set different roots for a domain conditionally, but you can redirect (rewrite) to another domain conditionally
This guy's example helped me a bit ago
http://nicknotfound.com/2009/01/12/iphone-website-with-nginx/

Resources