Custom Bad Gateway Page with Nginx - 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.

Related

force nginx to rewrite 403 response with document

I want to rewrite 403 response that already has document from app. And use my document or just plain text response instead of detailed application data.
I tried doing :
error_page 403 /40x.html; location = /40x.html { }
but since document is already served by app, error_page doesn't work.
I was lacking the:
proxy_intercept_errors on;
option in server config.
After adding it and modifying default_headers it started working as desired

path based routing as a reverse proxy

We were looking to use the AWS application load balancer (ALB) to direct incoming requests to specific servers where a "tenant" may reside. For example - customerA signs up to our free trial and we provision them a new instance of our application on webserver1 and we send them a link to their app, eg. https://trial.our.app/customerA
What we need is for our automated deployment that we will design and develop to ensure that when that person hits the load balancer it directs them to the appropriate server. However, from what we understand the AWS ALB has a rule limit of 100 rules therefore if we hit 100 free trials we would have run out of rules :
if path is '/customerA/*' then forward to webserver1
if path is '/customerB/*' then forward to webserver1
...
if path is '/customerX/*' then forward to webserver2
if path is '/customerY/*' then forward to webserver3
etc.
Also, if the customer browses to the "root" https://trial.our.app it redirects them to our website free trial page (different URL, eg. https://ourwebsite.io/freetrial)
We're not looking to load balance, it will simply be a case of redirecting the customer to their appropriate webserver where they have been provisioned.
We're considering NGINX (and are new to it!) and have spun it up to test this out and it mostly works, however we are unsure of a few things:
what would a basic/sample configuration of this look like? what he have so far on our test is as follows:
server {
listen 80;
listen [::]:80;
server_name _;
root /usr/share/nginx/html;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
error_page 404 /404.html;
location = /404.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
location = / {
return 301 https://ourwebsite.io/freetrial;
}
location /customerA {
proxy_pass http://10.101.1.149/;
}
location /customerB {
proxy_pass http://10.101.2.34/;
}
}
how do we ensure the location path is case insensitive, processes and includes everything after the path , eg. https://trial.our.app/customerA/#/app
how would you go about automating this so that the nginx config is updated when a new customer signs up and is added to the list of "locations" in the nginx.conf file?
any other suggestions of how best to approach this? are we using the right approach?

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 ?

Multiple 404 error pages in 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.

opening other websites links in nginx server

I am new to Nginx and I have set up the server using this tutorial. Now when I add links to other sites like http://www.anotherwebsite.com and when I click on this link from my page the server directs me to http://www.mywebsite.com/http://www.anotherwebsite.com. The server is appending the other link to my website link. How do I change that. I have looked into these places
How to redirect a url in NGINX,
Rewrite to pretty links with nginx
but I just cant make it work. Any help will be appreciated. Thanks
server {
listen 80;
server_name $hostname;
location /static {
alias /var/www/<app-name>/static;
}
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
location / {
include uwsgi_params;
uwsgi_pass unix:/tmp/uwsgi.sock;
uwsgi_param UWSGI_PYHOME /var/www/<app-name>/env;
uwsgi_param UWSGI_CHDIR /var/www/<app-name>/project;
uwsgi_param UWSGI_MODULE <project-name>.wsgi:application;
}
}
you're not doing any redirecting at all from your posted nginx config,
everything except /static/ and /50x.html is passed on to the uwsgi app
consequently the redirecting has to be happening in the uwsgi app
As far as redirecting from within nginx goes, the simple case goes like this:
location /redirected-path {
#for 302 redirect
rewrite ^ http://anotherwebsite.example.com/path-on-other-site redirect;
#for 301 redirect
# rewrite ^ http://anotherwebsite.example.com/path-on-other-site permanent;
}
(the more complicated cases involve regexes more complicated then ^)
UPDATE:
right, so from the code you linked in the comment below, what you really want to do is change the href value of the outputted html code anchor tag.
The proper place to do so is in the backend code (i.e. in the uwsgi app you're connecting to)
You could do it with the following rewrite:
location /main {
rewrite ^/main(.*) http://www.mysite.com$1 permanent;
}
BUT this has the big drawback of requiring an extra roundtrip to the server, a client then does:
request to your server
response with redirect to the other server
request to the other server
response from the other server
whereas if you change it in the backend code steps 1 and 2 are no longer needed.
Besides causing a potentially (depending on connection speed and server load) noticable delay. It will also increases your server load.
Doing it with a server-rewrite is a hack you really should skip unless you have no access to the backend code

Resources