
A year or so ago I got intrigued about how to “properly” implement custom HTTP errors on NGINX after watching this rather funny DEFCON talk. The speaker talks about returning “weird” HTTP codes since browsers usually seem to display anything they receive regardless of the HTTP status code in the return. The idea being that scanners used by script kiddies are usually poorly written and has a high chance of failing if they get an unexpected “rare” HTTP status code.
This got me thinking, returning arbitrary status codes instead of the correct ones seems a little drastic, and relies on undocumented “features” in web browsers, so the risk of something completely breaking down the line is rather high. But I thought that instead of returning obscure HTTP status codes for valid requests, what about returning really weird but still valid HTTP status codes instead of 404 errors?
The ones among you that happen to know what HTTP Error 418 is are probably chuckling a bit at this point, since 418 is probably the definition of a “weird but still valid HTTP status code”, but for the ones of you that don’t know, 418 is the code for “I’m a teapot”. Now, you might be wondering why you’d ever need a web server to respond “I’m a teapot”, and you’d be right in thinking “never”.
Error 418 came about as an April fools joke by the IETF back in 1998. RFC 2324 was published on 1th of April 1998, describing a standard called Hyper Text Coffee Pot Control Protocol (HTCPCP/1.0) that is an implementation for controlling coffee machines over HTTP. The whole RFC was basically a demonstration for how to not use HTTP for insane applications. Along with this standard a new HTTP status code was standardised, HTTP 418 “I’m a Teapot”, which is aptly used by said teapot when you ask it to brew coffee using HTCPCP. That the standard doesn’t implement any support for teapots isn’t really explained, neither is the need for an unsupported teapot to implement HTCPCP. This was later rectified in 2014 by RFC 7168 which extends HTCPCP to allow brewing of teas. However, this being real standards means that HTTP 418 is a very real standardised error. This was later reaffirmed back in 2015 by the save418.com movement when some dimwit with the mission to eradicate any joy from the world got the bright spark to try and have 418 re-purposed for something more “useful”.
So, we have the idea, we have our obscure but correct error, now how do we go about getting NGINX to cooperate?
I did a quick google search to see if anybody has had the same bright spark as I before and found this short snippet of code:
server { listen 80 default_server; location / { default_type text/plain; return 418 "418 I'm a teapot\n"; } }
This was clearly intended as a joke, and I couldn’t for the life of me get this configuration to work, no matter what I tried.
The main problem I had was that I want my server to actually send the status code 418, not just redirect to an error page for 418 but with the jolly status code 200.
This is what I came up with
server { listen 80 default_server; location / { return 418; } error_page 418 /custom_418.html; location = /custom_418.html { root /var/www/html/errors; internal; }
As you can see, we have a bit more going on. First, we do the same thing and return a 418 if we can’t find anything more appropriate, basically what NGINX does by default but with a different status code. Then outside the location block we define a custom 418 error page, as NGINX sadly doesn’t ship with a default error page for 418, so that we can get a lovely facsimile of the NGINX default error page, along with the aforementioned code and the message “I’m a Teapot” to further vex any script kiddie that pulls it up in his browser after wondering what in the world on that error page made his überl33t script crash. Here’s my version, I’m sure you can come up with something much more spectacular. Please post a comment with a link to your error if you do make one, I’d love to see them!
<html>
<head><title>418 I'm a teapot</title></head>
<body bgcolor="white">
<center><h1>418 I'm a teapot</h1></center>
<hr><center>Russell's teapot/1.2.11</center>
</body>
</html>
The following snippet has been thoroughly tested on NGINX, and actually returns a status code of 418 along with the page, just as Mr. L. Masinter intended. No guarantees of course, the above code is provided free at charge with no warranties, use at your own risk.
Hope you enjoyed this little useless bit of knowledge, and I hope it might also serve as an example of how just because something probably shouldn’t be done doesn’t mean it can’t be done. It also serves as a neat primer if you want to implement your own error pages in NGINX. And we have also proved that NGINX is indeed, still awesome!
Categories: Tech
Actually the first snippet works too. But maybe because I had recompiled nginx with `ngx_string(“418 I’m a teapot”)` in ngx_http_header_filter_module.c haha
That would do it, but I wanted to get a generic version! It was basically just a fun exercise, instead of watching TV for a couple hours I did something equally pointless 🙂