I serve hjr265.me from an S3-like bucket hosted on Linode Object Storage. I have a Caddy instance that serves some of my Hugo-built websites, including this one.
I use Hugo’s deployment function and
s3cmd to deploy these websites.
Hugo’s deployment function uses the blob package from the Go Cloud Development Kit. This package comes with a limitation by design. It cannot set S3 access control lists (ACLs) for the uploaded objects. So neither can Hugo.
I have been using
s3cmd to apply the “public-read” ACL for all the objects uploaded by Hugo.
I am using Caddy to serve the website using Linode (referral) Object Storage’s website endpoint.
The catch? Unless the objects had a “public-read” ACL set, Caddy would serve 404.
And that meant, between the time
hugo deploy was run and
s3cmd setacl was run, updated parts of my site would return 404.
It doesn’t work well for this use case unless you hold its hands.
Hugo can set different
cache-control headers based on filename patterns. S3cmd cannot unless you upload the files in separate batches and add these details to the command line for each set of files.
Hugo can gzip the files before they are uploaded. S3cmd cannot.
If I can configure
caddy to retrieve files from the S3-like bucket using an access key ID and secret pair instead of using Linode Object Storage’s website endpoint, I can avoid some of these workarounds.
First, to add a module to
caddy, I build it with
This Caddy module by Márk Sági-Kazár is what I needed: github.com/sagikazarmark/caddy-fs-s3
Here’s a Dockerfile to build Caddy with the
I now need a Caddyfile that could use this module with a
- I am gzipping the responses. I had to stop making Hugo upload gzipped objects since Caddy doesn’t set the
content-encodingheader based on the S3 response.
- I use the
file_serverdirective with the
- The module is configured to use a specific credential profile from the
file_serverdirective uses “index.html” for the index file.
The above Caddyfile almost works the way I wanted. Except it wasn’t serving the site’s 404 page (/404.html) when accessing a non-existent URL.
To solve that, I need to add a
- I moved the
file_serverdirective to a snippet of its own. I can use it again inside
handle_errorswithout duplicating the
handle_errorsdirective is set to serve the “/404.html” page for 404 responses (or the corresponding error page for any non-200 response).
Now, I can say goodbye to
s3cmd from my Hugo-built site deployment pipelines and not worry about setting a public-read ACL on uploaded objects.
The pipelines now have to do half as much work as before.
comments powered by Disqus