force nginx to rewrite 403 response with document - nginx

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

Related

Can I configure nginx with proxy_pass to use an error document on the proxied server?

I've configured nginx with proxy_pass to proxy URLs like /uploads/foo.png to fetch from an S3 bucket, but obviously missing files result in ugly XML errors, and I want to return a static HTML file.
I tried using the "static website" feature of S3, but it always returns (incorrect) 403 status codes with the error doc, and it seems there's no way to alter that via proxy_pass.
For various reasons, using a local file on the nginx server isn't an option. This nginx instance only does proxying.
Can I have nginx re-request an error document from the proxied S3 bucket?
Yes. First place 404.html in your S3 bucket. Then configure your location block like this:
location /uploads {
proxy_pass YOUR_S3_BUCKET_URL;
proxy_intercept_errors on;
error_page 403 404 /uploads/404.html;
}
proxy_intercept_errors will tell nginx to handle error codes in the proxied response.
The error_page will handle the S3 error code by internally changing the request to /uploads/404.html
And finally your existing location /uploads block will fetch that 404 doc from the proxied server!
Presumably you could even fetch the error doc from a different origin:
location /uploads {
proxy_pass ORIGIN_A_URL;
proxy_intercept_errors on;
error_page 403 404 /error-docs/404.html;
}
location /error-docs {
proxy_pass ORIGIN_B_URL;
}

NGINX Ingress 404 redirect to URI

I want to redirect all my 404s to another URI. The problem is that my other URI has a response code of 404. So when I use error_page 404 URI, the redirection occurs in a loop. Example server snippet is shown below
if ($request_uri != URI) {
proxy_intercept_errors on;
error_page 404 URI;
}
Direct 404 Errors to the Custom 404 Page
Use the error_page directive so that when a 404 error occurs (when a requested file is not found), the custom page you created is served. We will create a location block for the file, where we are able to ensure that the root matches our file system location and that the file is only accessible through internal Nginx redirects (not requestable directly by clients):
error_page 404 /custom_404.html;
location = /custom_404.html {
root /usr/share/nginx/html;
internal;
}
and at custom_404.html file
use any redirect like
<meta http-equiv="refresh" content="0;URL='http://thetudors.example.com/'" />

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 ?

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