HTTP 301 redirects in Eleventy
This is well-trodden ground, but this how I do HTTP 301 redirects in Eleventy, mostly to have a reference for the Apache vs. nginx syntax. I’m sticking with the Hugo aliases
convention in the front-matter data:
---
title: My post
aliases:
- /my-previous-url/
- /my-other-previous-url/
---
Here’s the Eleventy configuration to gather all the aliases in a collection of { from, to }
objects. All trailing slashes are removed from the paths, to make their usage clearer in the redirects.
function stripTrailingSlashes(str = '') {
return str.replace(/^\/|\/$/g, '');
}
config.addCollection('aliases', function (api) {
return api
.getAll()
.map(page => {
return (page.data.aliases ?? []).map(alias => {
return {
from: stripTrailingSlashes(alias),
to: stripTrailingSlashes(it.page.url)
};
};
})
.flat();
});
With the collection in place, it becomes a matter of producing a server-specific redirects file. Apache can use a .htaccess
file in the website’s root, produced by the Nunjucks template below:
---
permalink: /.htaccess
eleventyExcludeFromCollections: true
---
ErrorDocument 404 /404.html
<IfModule mod_alias.c>
RewriteEngine On
{% for alias in collections.aliases %}
RedirectMatch 301 ^/{{ alias.from }}/?$ /{{ alias.to }}/{% endfor %}
</IfModule>
When it comes to nginx, producing the set of redirects is only half the story. Let’s first generate a 301.redirects
file in the website root:
---
permalink: /301.redirects
eleventyExcludeFromCollections: true
---
{% for alias in collections.aliases %}
rewrite ^/{{alias.from}}/?$ /{{alias.to}}/ permanent;{% endfor %}
This file does nothing by default. It needs to be included in the nginx configuration:
server {
include path/to/301.redirects;
}
There’s a number of ways to go about it, which I won’t document here. But if the technique invovles leaving the physical 301.redirects
file in the website’s root directory, you’ll probably want to make it inaccessible to the outside world with something along the lines of:
location = /301.redirects {
internal;
}
One gotcha is that aliases added to pages having eleventyExcludeFromCollections: true
won’t be included in the redirects file, an aspect I noticed when moving some Atom feeds around. Eleventy doesn’t yet have an API to grab excluded pages, so for now I’ve added manual entries to .htaccess
.