-
-
Notifications
You must be signed in to change notification settings - Fork 709
Caddy
Caddy is a web server written in Go. It is known for being simple to install, and has batteries included. It won't hurt to look over the documentiation but here I'm going to give us a "quick start" as it pertains to using it in Sandstorm apps instead of Nginx. I will say that while I did have frustrations in the process of figuring this out, it was less than with Nginx.
Batteries include very useful things like load balancing. That sounds like overkill but it's actually useful for us. They also include things like automatic HTTPS and Let's Encrypt, which are very cool but only get in our way for Sandstorm development, so we disable them.
Caddy is known for being "fast enough" but not quite as fast as Nginx. This is no problem for Sandstorm. Easy is what we're going for, even for developers.
You can install in setup.sh
like Nginx:
apt install caddy
service caddy stop
systemctl disable caddy
If you want a more updated version, you can look at options here appropriate for build.sh
or setup.sh
.
Caddy offers a few options for configuration. For Sandstorm, we will use what's called a Caddyfile
.
Here's a basic Caddyfile
that works for Sandstorm:
# This is the "global options block". Certain options only belong here.
{
# Caddy by default supports https (and even handles ACME certs). For our
# purposes this is annoying at best.
auto_https off
# The admin API would let you edit this config over http (!) at localhost:2019.
# Sandstorm presumably wouldn't allow outside requests to hit it, but why add the risk?
admin off
}
# This is a "site block" which handles requests to port :8080 (See ":8080 questions" below)
:8080 {
log {
output stdout
format json
# If you want to log every request, remove this line or replace it with "level info"
level error
}
# `handle_path` will trip the prefix. (if you don't want this, use `handle`)
# Ex: /static/img/cat.png -> /img/cat.png
handle_path /static/* {
file_server {
# Ex: /img/cat.png -> /opt/app/static/img/cat.png
root /opt/app/static
# Allow directory browsing (with a nice interface!)
browse
}
}
reverse_proxy :8081 {
# See: https://caddyserver.com/docs/caddyfile/directives/reverse_proxy#load-balancing
# If Caddy starts before our app does, we want it to stall any incoming
# requests instead of returning an error. We can do this using Caddy's
# built-in load balancer (this may be overkill but it's a very simple
# solution).
# Retry for up to 5 seconds if the app hasn't started yet.
lb_try_duration 5s
# By default lb_try_interval is .250. To match 5 seconds we want 20 retries.
lb_retries 20
}
}
Again, for your specific needs, you will likely want to consult the documentiation. I could be recalling my struggles with Nginx wrong, but I think Caddy was a lot easier to understand with path editing directives in particular: rewrite and uri
A few things that I'm unsure of related to this (that I would like to sort out and remove from this doc)
- It's not 100% clear to me why this clause applies to http rather than https, but that is what we want and it's less verbose than
http://:8080
. If it's something that tends to be be finicky, maybe we should just recommendhttp://8080
to avoid debugging problems. - If you put
localhost:8080
instead of:8080
, the server will receive requests from Sandstorm (i.e. I can get log entries), but the page does not show up in the browser. I guess:8080
means0.0.0.0:8080
, which I hope is safe. (It must be safe, it's Sandstorm, right?)
Like with Nginx, we start the app on the port that Caddy expects, we run the app in the background, and we run Caddy in the foreground.
However, unlike with Nginx, we have no need to have a retry loop to wait for the app to start before starting Caddy. We already told Caddy's built-in load balancer to do this job for us!
For this example, we will place the Caddyfile
in the .sandstorm
directory, but you can put it anywhere.
#!/bin/bash
set -euo pipefail
# Set your app to work on port 8081. How it is done depends on your
# app of course, but in our example we'll pretend that it's an
# environmental variable.
export MY_APP_PORT=8081
# <Other app configs go here>
cd /opt/app
my-app&
# Caddy saves certs and admin-API generated configs in the home
# directory. We don't care about either of these things.
FAKE_CADDY_HOME=/tmp/fake-caddy-home
mkdir -p $FAKE_CADDY_HOME
# Don't export the fake HOME; only apply it to caddy.
# By default caddy looks for `Caddyfile` in the current directory, but
# we are currently in /opt/app so we pass it in explicitly.
HOME=$FAKE_CADDY_HOME caddy run --config .sandstorm/Caddyfile
exit 0
If we decide that it's useful, we can update vagrant-spk
to use this instead of Nginx.
Perhaps we'll want the Caddyfile
in the service-configs
directory, but unlike Nginx I don't think we'll need a separate mime.types
file.
One global option we could add is turning off "persisting" configs.
persist_config off
This appears to be unavailable in Debian Bookworm, but if you use a newer version it might be worth considering.
This setting would stop Caddy from wanting to save the admin API config to disk (see above). Since we use the "fake home" trick anyway, this would amount to one less log entry for us. Still if we could also stop Caddy from wanting to save the cert, perhaps we could do away with the "fake home" hack. Something to consider.