Caddy inside Docker with Redirects
Caddy is a web server that boasts with easy configuration and great defaults, such as automatic HTTPS support by default. While I didn't need https, I was curious about how configuring some redirects and static file serving would go. You can find out more about caddy at caddyserver.com.
If you want to get the full source for this repository, the link is at the bottom.
As so often I needed redirects, as I was moving one of my websites to become a static site. Inside my docker container I would have a rendered directory structure that has the paths of the html files and of course some assets.
While migrating away from a CMS, I knew that I would break some of the links on the website. Blog posts like /peaches
would become /blog/peaches
, so redirects were important to me, optimally in an external file that I can load into the main config.
Caddy in the Dockerfile
The simplest way in which you can use caddy in a dockerfile to serve static assets might be this:
FROM alpine
EXPOSE 5000
RUN apk add --no-cache caddy
RUN mkdir -p /var/www/html
COPY pages/ /var/www/html/
WORKDIR /var/www/html
CMD ["caddy", "file-server", "--listen", ":5000"]
Given we have some html files in the pages
directory like so:
pages
├── blog
│ ├── eggplant
│ │ └── index.html
│ ├── ice-cream
│ │ └── index.html
│ └── peaches
│ └── index.html
└── index.html
we can serve the files by building the Dockerfile and running it:
docker build . -t caddy_test
docker run -i -p 127.0.0.1:5000:5000 -t caddy_test
Now visiting localhost:5000 we can see our HTML files.
For me it looks like this with some very minimal example HTML:
While this will serve our files, we're missing out on the redirects we need to apply.
Load your Caddyfile
The common config file for a caddy server is the Caddyfile
, so let's create that one:
# file: caddy-config/Caddyfile
# global directive
{
# turn off https, we're in a trusted environment
auto_https off
}
:5000 {
# import redirects
import /var/app/caddy-config/redirects
# set the root for our served files
root * /var/www/html
# Enable the static file server.
file_server {
precompressed zstd br gzip
}
}
This one will also listen on port 5000
and through the file_server
directive serve the files with some compression enabled.
We can place the file in a sub-directory like caddy-config
if we don't want to clutter the root of our project.
Now to add redirects we could insert a few lines above the root
directive, like so:
redir /ice-cream /blog/ice-cream permanent
Loading an External Redirects File
For the redirects, we're creating a separate file, which I chose to just call redirects
without any specific file ending.
# redirect to front page
redir /tag/* / permanent
redir /author/* / permanent
# old post structure from /[name] to /blog/[name]
# exact match
redir /ice-cream /blog/ice-cream permanent
# match path and path with trailing slash
redir /peaches /blog/peaches permanent
redir /peaches/ /blog/peaches permanent
# match prefix, every route starting with /eggplant will be redirected
redir /eggplant* /blog/eggplant permanent
Please note that depending on how you want your redirects to work you might either want to match explicit paths, or use some of the wildcards you can pick up in the caddy matcher documentation.
To check if everything works to our satisfaction, we can run docker build
and docker run
again:
docker build . -t caddy_test
docker run -i -p 127.0.0.1:5000:5000 -t caddy_test
We should see output similar to this:
# [...] redacted
Successfully tagged caddy_test:latest
2024/06/16 11:54:18.241 INFO using provided configuration {"config_file": "/var/app/caddy-config/Caddyfile", "config_adapter": "caddyfile"}
2024/06/16 11:54:18.241 WARN Caddyfile input is not formatted; run 'caddy fmt --overwrite' to fix inconsistencies {"adapter": "caddyfile", "file": "/var/app/caddy-config/Caddyfile", "line": 1}
2024/06/16 11:54:18.242 INFO admin admin endpoint started {"address": "localhost:2019", "enforce_origin": false, "origins": ["//localhost:2019", "//[::1]:2019", "//127.0.0.1:2019"]}
2024/06/16 11:54:18.242 WARN http.auto_https automatic HTTPS is completely disabled for server {"server_name": "srv0"}
2024/06/16 11:54:18.242 INFO tls.cache.maintenance started background certificate maintenance {"cache": "0xc0001f6200"}
2024/06/16 11:54:18.242 INFO http.log server running {"name": "srv0", "protocols": ["h1", "h2", "h3"]}
2024/06/16 11:54:18.242 WARN tls unable to get instance ID; storage clean stamps will be incomplete {"error": "open /root/.local/share/caddy/instance.uuid: no such file or directory"}
2024/06/16 11:54:18.242 INFO autosaved config (load with --resume flag) {"file": "/root/.config/caddy/autosave.json"}
2024/06/16 11:54:18.242 INFO serving initial configuration
2024/06/16 11:54:18.243 INFO tls cleaning storage unit {"storage": "FileStorage:/root/.local/share/caddy"}
2024/06/16 11:54:18.243 INFO tls finished cleaning storage units
Now when visiting the example links we can see that we're being redirected 🙌!
Summary
This was a very short introduction to redirects in caddy and how to load a config file with imported redirects from an external file. Thank you for reading! Let me know what you're using caddy for 👀!
Full source for this example can be found here: github.com/JonathanMH/stream-kitchensink/tree/master/caddy-docker