Multiple 404 error pages in nginx - nginx

I am running nginx server. I want to serve a custom error page for a particular request only. For-example for request
http://localhost/abc1 & http://localhost/abc2
if these pages are not there I want to serve a custom error page. This custom error page should appear only for above two mentioned links, rest of the page errors can show the default error page. I have tried different configuration but nothing seems to work. Thoughts
Regards,
Farrukh Arshad.

Your answer is quite correct, but as you said, you only defined them for the html's, remove the extension and it should work for the whole directory, no need to repeat the root, just define it in the server block scope
server {
listen 80;
root /var/www/nginx-default;
location /abc1 {
error_page 404 /special_error.html;
}
location /abc2 {
error_page 404 /special_error2.html;
}
}

Ok, I found the answer. The trick is you have to define error_page explicitly for all those special locations. Here is the configuration which worked for me.
location / {
root /var/www/nginx-default;
index index.html index.htm;
error_page 404 /404.html;
}
location /abc1.html {
root /var/www/nginx-default;
error_page 404 /special_error.html;
}
location /abc2.html {
root /var/www/nginx-default;
error_page 404 /special_error2.html;
}
I am not good with nginx, but I have noticed it depends on the search pattern you give in "location" tag. I have tried different things and those failed . Forexample the above rules will ONLY work for
http://localhost/abc1.html
and fail for
http://localhost/abc1
so your "location" search pattern should be good if you want to cover second case. Probably some nginx guru can shed some more light on this. Thanks.

Related

How to set Nginx 404 page not affecting other directory?

I need to set these two Urls redirect to a custom 404 page:
https://example.com/frontend/#/,
https://example.com/frontend/
the Nginx config below works fine:
server{
listen 80;
server_name example.com;
error_page 404 /404.html;
location = /404.html {
root /opt/app/nginx/html;
internal;
}
location = /frontend/ {
return 404;
}
}
However this setting makes URLs with the same prefixes go to 404 as well, which is a pain in the ass!
https://example.com/frontend/#/abc,
https://example.com/frontend/#/123
all redirect to 404.
I use exact matching (= modifier) for the 404 settings,
why does it still affect others and how can I fix it?
Thank you for any help! :D
Edited
I found the reason thanks to the answers given down there! So the # sign is processed by the browser only, the browser never passes # to the server, that's why Nginx treats https://example.com/frontend/#/abc,
https://example.com/frontend/#/123 all as https://example.com/frontend/.
In this case, if I wanna set https://example.com/frontend/#/ to the 404 page, what I need to do is to create an index page under /frontend folder in the project, and put 404 content inside the index page, There's nothing Nginx could do with redirecting URL contains hash sign.
You can't do that because the hash part isn't sent to the server. It's for client side processing only.
Try using two location without the "/" in each.
location = /frontend {
return 404; }
location = /frontend/# {
return 404; }

return custom error pages in nginx, flask

I tried other answers in SO, like :
Return custom 403 error page with nginx
nginx + uwsgi + flask - disabling custom error pages
nginx not serving my error_page
and
references:
http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_intercept_errors
http://nginx.org/en/docs/http/ngx_http_core_module.html#error_page
but still not able to return custom error pages - nginx keeps to return its own pages.
Working in local env, flask returns custom html pages.
When published in nginx, no more.
This is what I want to have:
if user hit /js/, route will return 403, while allowing to internal files /js/myJS.js
If file /js/myJS.js does not exist, return 404
If something goes awry, say an API in flask that break (it shouldn't :) ) > return 500
My flask configuration is like:
#application.errorhandler(404)
def error_404(e):
application.logger.error('Page Not Found: %s', (request.path))
#return render_template('404.html'), 404
return render_template("404.html", error = str(e)), 404
// other errors are handled similarly
and the 404.html template, is within var/www/mysite/templates folder.
The error page are static files, there are no assets served from flask but the html template.
Now, in my nginx configuration I am handling errors like this:
root var/www/mysite;
# update: tried to handle custom errors with proxy_intercept_errors on;
# still no success
proxy_intercept_errors on;
# static is the directory that serve the subdirectory /js
# HOW COULD I RETURN 403 if /js is hit directly, but not /js/myfile.js ?
# I tried to add deny all and allow only my server up, but did not worked out
location /static {
expires 1M;
alias /var/www/mysite/static;
access_log off;
add_header Cache-Control "public";
allow #myserverip;
deny all;
}
error_page 403 /403.html;
location = /403.html {
root /var/www/mysite/templates/;
internal;
}
error_page 404 /404.html;
location = /404.html {
root /var/www/mysite/templates/;
# internal;
allow all;
}
# also with the following no success: nginx white internal page is still displayed
error_page 404 http://example.com/404.html;
That I try to set internal or comment it out; that I try to set allow all (as in answer in above SO answer) , no matter what, nginx will return its custom page 404 - not from my templates folder.
I also tried to set up a folder for fallback, like:
## Fallback Directory
location #error {
root /var/www/error;
}
but still no success - always the white 404 page from nginx.
What is wrong in my configuration ?
I would like to better understand how flask and nginx dialogue for errors.
I understood that once published, nginx will handle the error - but did not understood how the raised error are handled between flask and nginx: what happen when user hit route of a "wrong" resource ? is it nginx that intercept it? is it flask? is it uwsgi ? how do they pass the ball?
Also, please share a tip:
how could I query error pages in nginx, e.g. for testing bad requests 403 and 500 ?

Nginx URL rewrite

I have a website that has laravel setup to run under http://www.example.com/lara/
So, most Laravel pages have URLs of type http://www.example.com/lara/page/23 OR http://www.example.com/lara/category/23 etc.
Nginx is the underlying server and it has the following configuration to handle these requests:
location /lara/ {
try_files $uri $uri/ /lara/index.php?$query_string;
}
Everything works ok.
Now, I need to setup a special page with the URL http://www.example.com/mystuff/ which actually is handled by
http://www.example.com/lara/category/29
To get this working I added the following rewrite right below location /lara/, that is:
rewrite ^/mystuff/(.*)$ /lara/category/29/$1 last;
Unfortunately, I get a page not found error. Any insights?
Further investigation & research:
1)
location /mystuff/ {
return 301 /lara/index.php/category/29;
}
worked although that's not (browser address bar changes to) what I actually want.
2) Looks like Laravel is not seeing the updated REQUEST_URI.
Try this
server {
...
rewrite ^/lara/(.*)\..*$ $1/mystuff last;
return 403;
...
}

How to return no body / content for errors / error_page in nginx?

If a file is not found, or forbidden, etc. -- I'd really like to just return the HTTP status code and no body content.
Something like:
error_page 403 404 body="";
What are the current (2015) best practices?
I am not sure if this is the best practise but it still works even without creating actual empty file.
error_page 403 404 /__empty-error-page__.html;
location = /__empty-error-page__.html {
internal;
return 200 "";
}
The best I've come up with is to create a zero-byte file:
$ touch _.json
set that location to be internal in my nginx config, and point the error_page to it:
location /_.json {
internal;
}
error_page 403 404 /_.json;
Depending on your content-type, replace _.json with your desired _.mime-type-extension.
Realistically, all current options imply location per error code wich isn't a clean solution. When you compile your nginx, simply deal with bodies in src/http/ngx_http_special_response.c

Custom Bad Gateway Page with Nginx

Is it possible to serve a custom "Bad Gateway" error page in Nginx?
Similar to having custom 404 pages.
There are three pieces that must be in place in order for your custom error page to display instead of the generic "Bad Gateway" error.
You must create an html file named something like "500.html" and place it in the root. In the case of Rails running behind Nginx, this means putting it at public/500.html.
You must have a line in your config file that points at least the 502 errors to that 500.html page like this:
error_page 502 /500.html;
You must have a location block for /500.html in your config file. If your root is already defined, this block can be empty. But the block must exist nonetheless.
location /500.html{
}
It's similar to setting up the custom 404 pages. Here's what I've got.
#site-wide error pages
error_page 404 /404.html;
error_page 500 502 503 504 /500.html;
using debian (9.3 stretch actually) i did following steps:
create /var/www/html/502.html with the content for the 502 error page
edit /etc/nginx/sites-enabled/mywebsite.conf
so it looks similar like this:
server {
listen 80; listen [::]:80;
server_name www.mywebsite.com;
error_page 502 /502.html;
location /502.html {
root /var/www/html;
}
}
then restarted nginx using service nginx restart
While #Larsenal's answer is technically correct for the minimum configuration, there are common configurations that will make it not work. #Jack Desert's answer touches on this but doesn't provide a full explanation of why that's needed.
Suppose we have this configuration (simplified from #Jack).
error_page 502 504 /my-error-page.html;
What this is saying is, in the case of a 502 or 504 error internally, rewrite the original URI as /my-error-page.html.
What I think most people miss is that this then goes through the same processing chain that happens as if you requested that page directly. This means that it goes through all the same location block checks.
Since a common method of doing a reverse proxy on nginx is to configure a location / { block, that location matches /my-error-page.html and thus nginx tries to use the proxy to serve the error file. Since a common use case is serving a static file in the case that the backend is down, serving this error page from the backend will likely also fail, making nginx default to serving its own internal error page that we were trying to replace in the first place.
So, a common solution, the one #Jack Desert suggests, is to include another location block that will match the /my-error-page.html URL before the location / block. Note that the order of location blocks in nginx configuration has no effect; There is a very specific set of rules for picking precedence of location blocks based on the URL. That location block needs to have whatever is necessary to serve that file like any other static file that nginx might serve. This means a root directive is needed somewhere and that /my-error-page.html will be loaded relative to that (root can be set at nearly any level of the nginx configuration).
Yes it is possible
Type this in your terminal
cd /etc/nginx
sudo nano nginx.conf
and under http add these lines
error_page 500 Path_to_your_custom_error_page;
error_page 503 Path_to_your_custom_error_page;
error_page 504 Path_to_your_custom_error_page;
Now restart nginx by typing this command:
sudo service nginx restart
Bingo now you can see custom error message on gateway error
The question doesn't say, but it's quite common to hit this problem when API's are behind an nginx pass through proxy, so in that case you want the response to be JSON not HTML.
My favorite approach is to just use the redirect functionality of the error_page directive to redirect back to an error page on the same site:
error_page 502 503 $scheme://$server_name/500.json;
It's one line, you can reuse the same 500.json for different location's, and there is no need for a mysterious empty location. You place your error message in the 500.json file at the root of your site. I assume that you already have a location / {...} directive there that serves up static files.
You can of course use this same approach to serve an HTML error page too.

Resources