You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
131 lines
4.9 KiB
Markdown
131 lines
4.9 KiB
Markdown
---
|
|
draft: false
|
|
title: "Automating Caddy on my DigitalOcean Droplet"
|
|
date: "2023-01-05"
|
|
author: "Nick Dumas"
|
|
authorTwitter: "" #do not include @
|
|
cover: ""
|
|
tags: ["webdev", "devops"]
|
|
keywords: ["", ""]
|
|
summary: "Automation ambitions fall flat"
|
|
showFullContent: false
|
|
---
|
|
|
|
## Defining units of work
|
|
I've got a few different websites that I want to run: this blog, my portfolio, and my about page which acts as a hub for my other sites, my Bandcamp, and whatever else I end up wanting to show off.
|
|
|
|
To keep things maintainable and reproducible, I decided to stop attempting to create a monolithic all-in-one configuration file. This made it way harder to keep changes atomic; multiple iterations on my blog started impacting my prank websites, and it became harder and harder to return my sites to a working state.
|
|
|
|
## Proof of concept
|
|
|
|
The first test case was my blog because I knew the Hugo build was fine, I just needed to get Caddy serving again.
|
|
|
|
A static site is pretty straightforward with Caddy:
|
|
|
|
```
|
|
blog.ndumas.com {
|
|
encode gzip
|
|
fileserver
|
|
root * /var/www/blog.ndumas.com
|
|
}
|
|
```
|
|
|
|
And telling Caddy to load it:
|
|
|
|
```bash
|
|
curl "http://localhost:2019/load" \
|
|
-H "Content-Type: text/caddyfile" \
|
|
--data-binary @blog.ndumas.com.caddy
|
|
```
|
|
|
|
This all works perfectly, Caddy's more than happy to load this but it does warn that the file hasn't be formatted with `caddy fmt`:
|
|
|
|
```
|
|
[{"file":"Caddyfile","line":2,"message":"input is not formatted with 'caddy fmt'"}]
|
|
```
|
|
|
|
## The loop
|
|
|
|
Here's where things went sideways. Now that I have two unit files, I'm ready to work on the tooling that will dynamically load my config. For now, I'm just chunking it all out in `bash`. I've got no particular fondness for `bash`, but it's always a bit of a matter of pride to see whether or not I *can*.
|
|
|
|
```bash
|
|
# load-caddyfile
|
|
#! /bin/bash
|
|
|
|
function loadConf() {
|
|
curl localhost:2019/load \
|
|
-X POST \
|
|
-H "Content-Type: text/caddyfile" \
|
|
--data-binary @"$1"
|
|
}
|
|
|
|
loadConf "$1"
|
|
```
|
|
|
|
```bash
|
|
# load-caddyfiles
|
|
#! /bin/bash
|
|
|
|
source load-caddyfile
|
|
|
|
# sudo caddy stop
|
|
# sudo caddy start
|
|
for f in "$1/*.caddy"; do
|
|
echo -e "Loading $(basename $f)"
|
|
loadConf "$f"
|
|
echo
|
|
done
|
|
```
|
|
|
|
After implementing the loop my barelylegaltrout.biz site started throwing a 525 while blog.ndumas.com continued working perfectly. This was a real head scratcher, and I had to let the problem sit for a day before I came back to it.
|
|
|
|
After some boring troubleshooting legwork, I realized I misunderstood how the `/load` endpoint works. This endpoint completely replaces the current config with the provided payload. In order to do partial updates, I'd need to use the `PATCH` calls, and look who's back?
|
|
|
|
## can't escape JSON
|
|
|
|
The `PATCH` API *does* let you do partial updates, but it requires your payloads be JSON which does make sense. Because my current set of requirements explicitly excludes any JSON ( for now ), I'm going to have to ditch my dreams of modular code.
|
|
|
|
|
|
|
|
Not all my code has gone to waste, though. Now that I know `POST`ing to to `/load` overwrites the whole configuration, I don't need to worry about stopping/restarting the caddy process to get a clean slate. `load-caddyfile` will let me keep iterating as I make changes.
|
|
|
|
## Proxies
|
|
|
|
In addition to the static sites I'm running a few applications to make life a little easier. I'll showcase my Gitea/Gitlab and Asciinema configs. At the moment, my setup for these are really janky, I've got a `tmux` session on my droplet where I've manually invoked `docker-compse up`. I'll leave cleaning that up and making systemd units or something proper out of them for a future project.
|
|
|
|
Reverse proxying with Caddy is blessedly simple:
|
|
```
|
|
cast.ndumas.com {
|
|
encode gzip
|
|
reverse_proxy localhost:10083
|
|
}
|
|
```
|
|
|
|
```
|
|
code.ndumas.com {
|
|
encode gzip
|
|
reverse_proxy localhost:3069
|
|
}
|
|
```
|
|
|
|
With that, my gitea/gitlab is up and running along with my Asciinema instance is as well:
|
|
|
|
[![asciicast](https://cast.ndumas.com/a/28.svg)](https://cast.ndumas.com/a/28)
|
|
|
|
## Back to Square One
|
|
After finally making an honest attempt to learn how to work with Caddy 2 and its configurations and admin API, I want to take a swing at making a systemd unit file for Caddy to make this a proper setup.
|
|
|
|
## Finally
|
|
|
|
Here's what's currently up and running:
|
|
- [My blog](blog.ndumas.com)
|
|
- [Asciinema](blog.ndumas.com)
|
|
- [Gitea](blog.ndumas.com)
|
|
|
|
I've had loads of toy projects over the years ( stay tuned for butts.ndumas.com ) which may come back, but for now I'm hoping these are going to help me focus on creative, stimulating projects in the future.
|
|
|
|
The punchline is that I still haven't really automated Caddy; good thing you can count on `tmux`
|
|
[![asciicast](https://cast.ndumas.com/a/aWYCFj69CjOg94kgjbGg4n2Uk.svg)](https://cast.ndumas.com/a/aWYCFj69CjOg94kgjbGg4n2Uk)
|
|
|
|
The final code can be found [here](https://code.ndumas.com/ndumas/caddyfile). Nothing fancy, but troublesome enough that it's worth remembering the problems I had.
|