Drop #234 (2023-04-04): Are You Being Served?
404 Not Found; Location, location, location; Caddy-Tailscale
Today is April 4, making it “404” day
, so we'll start off with some light discourse on, example of, and guidance for the dreaded “resource not found”, followed by some nginxlocation
tip/tricks, and a neat new Caddy plugin by Tailscale.404 Not Found
As you no doubt know, a 404 page is an error page that appears when a user attempts to access a page that doesn't exist or has been removed from the website. The name “404” comes from the HTTP status code that the server returns to indicate that the requested page was not found.
At work (greynoise.io) we've been having fierce discussions on the app-equivalent of a 404 page for when folks use our visualizer to hunt for things in our vast data swamp. Not finding an IP address in our topical data does not mean that there's nothing to know about it, and we're working to make that page far more useful than it is at the moment.
A good 404 page can be a lifesaver for your website visitors. It can turn a frustrating experience into a positive one by providing helpful information and guiding them back to your site. A well-designed 404 page can also improve user engagement, reduce bounce rates, and increase the likelihood of visitors staying on your site to find what they need.
There's a pretty practical idiom for these pages:
be brief: the message on the 404 page should be straightforward and easy to understand, informing the user that the page they were trying to access is not available.
be contrite: the tone of the 404 page should be friendly and apologetic, acknowledging the user's inconvenience and expressing empathy.
be helpful: provide links to other areas of the website or a search box that can help users find what they're looking for quickly and easily.
be informative: include contact information, such as a feedback form, social media account, or email address to give users an alternative way to reach out to you for assistance.
be you: incorporate your brand's visual identity, including logos and colors, to help reinforce brand recognition and create a cohesive user experience.
These are some great examples:
This is work's '404' equivalent that we are working on leveling up, and this is mine.
What's your fav 404?
Location, location, location
The free tiers of hosting at the likes of GitHub, Netlify, and Vercel, combined with automated publishing idioms crafted by large communities across various tools/languages, means that many folks do not run their own web servers anymore. However, those same folks may use Docker for various services, and said many of said containers use nginx (1 billion+ pulls).
Nginx's location is a super powerful tool, but I use it infrequently enough that I always have to refer to notes. I figured there has to be a sufficient percentage of readers who may be in the same boat, so I'm taking some liberties with today's Drop to, er, drop some of them here.
The hieroglyphics that one can put before the URI component in a location
directive always trip me up for some reason. They're really not that hard to grok/remember:
=
: Exact match. Matches the URI exactly and only processes requests that exactly match the specified URI. This operator is useful for serving static files and other resources that have a fixed URL.
Example: location = /logo.png { … }
~
: Case-sensitive regular expression match. Matches the URI using a case-sensitive regular expression. This operator is useful for matching URIs that have a consistent pattern, such as all blog posts URLs.
Example: location ~ /blog/(.*)\.html { … }
~*
: Case-insensitive regular expression match. Matches the URI using a case-insensitive regular expression. This operator is useful for matching URIs that have inconsistent capitalization, such as URLs with mixed-case characters.
Example: location ~* /IMAGES/(.*)\.jpg { … }
^~
: Exact match with priority. Matches the URI exactly and gives it higher priority than any other location block that might match the same URI. This operator is useful for specifying locations for static files or other resources that should be served with the highest priority.
Example: location ^~ /images/ { … }
You can do some fun things with them, like return actual content from nginx vs. the filesystem or app route/proxy. This “fakes” a JSON API result:
location /fake-api {
# Set custom HTTP status code and content type for JSON response
add_header Content-Type "application/json";
return 201 '{"message": "Data created successfully"}';
}
This one returns the client's remote IP address directly as just plain text.
location /remote-ip {
default_type text/plain;
return 200 '$remote_addr\n';
}
And, this one returns a “web page”:
location /fake-web-page {
add_header "Access-Control-Allow-Origin" "*";
default_type text/html;
return 200 '<body>Hi $remote_addr</body>';
}
You can even add a CORS-frienldy header to those:
add_header "Access-Control-Allow-Origin" "*";
to make them easier to access anywhere.
Want to serve up different content based on features in the request, such as browser type?
location /rick {
if ($http_user_agent ~* (MSIE|Trident)) {
return 302 https://r.mtdv.me/drop-rick;
}
try_files $uri $uri/ /index.html;
}
And, remember, you have access to all the active nginx variables to use when crafting location
directive response content.
This is a great, curated list of all things nginx, and this is something everyone new to nginx should watch.
Caddy-Tailscale
Longtime readers of the Drop know I 💙 Tailscale.
While I do not use Caddy (solely due to negative interaction with the developers a few years ago that I should very likely get over), it is an up-and-coming infrastructure web server that I’m seeing used in tons more projects.
Tailscale just made it super easy to have Caddy be part of your Tailscale network, and serve content to the Tailnet, or proxy content from the Tailnet. Which means I actually do have to get over it and dive back in to Caddy (so we’ll cover that in a future Drop).
I will be poking more at this over the coming weekend and report back.
FIN
What's your default web server when you have to deploy a new web-thing? ☮
yep, we both agree that it is a total stretch pun