It's possible to replace puma-dev with 2 off-the-shelf programs:
puma-dev has been great! But the nature of HTTP servers & local development has fundamentally changed since it was first created:
puma-devonly supports HTTP/1, when apps are expecting to run HTTP/2 in production. This means that your development environment is probably slower than production (when it comes to handling requests)caddyships with a ton of features out of the box, including:- Compression encoding
- Header manipulation
- Automatic HTTPS certificate issuing (including using a local CA)
- Live reloading (via the
--watchcommand) - Nested
importsupport
puma-dev's approach of auto-booting processes in the background does not play well with containerized apps or running servers in foreground processespuma-devdoes have a reverse proxy functionality, which I've used and love, but the other problems above still stand.
I've noticed the performance slowdown when working with apps that expect HTTP/2 support (especially for resource loading), and I've been genuinely impressed by caddy as a development server.
This setup is composed of the following components/bits:
- A record in your DNS resolver (
/etc/resolver/*on macOS) to point everything thetestTLD to your local machine - Running
dnsmasqas a service, with a rule to route all.testaddresses to localhost- You can actually run whatever DNS server you want; I just chose
dnsmasqbecause it is installable via Homebrew and is easy to configure
- You can actually run whatever DNS server you want; I just chose
- A
caddyinstance that runs with.caddy-dev/Caddyfileas its config file and auto-reloads any changes- This is what the
caddy-devscript does!
- This is what the
You can see the individual files that build up to this in the repo, and I'll explain them in a bit of detail below:
This is where you'll store all the Caddyfiles you want to use for local development. Similar to puma-dev, you can create as many as you need. However, you have a few distinct advantages over puma-dev:
- You can
importother Caddyfiles, such as importing a repo-shared Caddyfile - You can customize the server per target
- You don't have to make a file for every domain. If you just want a massive Caddyfile, go for it!
The great thing about this setup is that you're just running Caddy. A configuration change didn't apply? Reload!
cd ~/.caddy-dev
caddy reloadThere is a very pre-alpha Homebrew formula you can use to:
- Install the
caddy-devscript (anddnsmasq/caddyas dependencies) - Add the
dnsmasqconfiguration file - Get instructions for how to finish the installation in the "Caveats" section
You can install it using:
brew install practical-computer/tap/practical-computer-caddy-devThe name is godawful because this is pre-alpha, and I do eventually want to get a nicer version of this shipped into homebrew/core.
Currently, dnsmasq via Homebrew on macOS requires it to be run as root. You can setup its service using:
sudo brew services start dnsmasqIf you've been using puma-dev, you do not need to uninstall the puma-dev package to use this. You will, however, need to uninstall the service that runs puma-dev in the background. This is because both puma-dev and caddy will try to use the standard HTTP/HTTPS ports, so you will run into conflicts.
puma-dev -uninstallUntil I write a more expanded version of the script to finish the installation on-demand, you will need to manually finish the installation due to Homebrew's sandboxing instructions.
There's nothing specific about the Homebrew installation; you can also manually install it and customize this setup to your heart's desire.
This record tells your operating system to send any DNS queries for the test domain to 127.0.0.1, so that your computer can resolve them using its own DNS server (dnsmasq in my case).
The file is here: /blob/main/resolver.test. It actually needs to be named /etc/resolver/test for your system to use it for routing the test domain
The dnsmasq configuration routes all *.test requests to localhost, with some barebones configurations to keep the server focused.
The file is here: /blob/main/caddy-dev.conf. If you're using Homebrew, you need to in ${BREW_PREFIX}$/etc/dnsmasq.d/caddy-dev.conf
caddy-dev itself is (currently) a one-line script that tells caddy to run, using
caddy run --config ~/.caddy-dev/Caddyfile --watchIt's meant to act as an aid. You could run this command yourself, but I've written the script to make it easier.
Here's a quick series of shell commands to bootstrap .caddy-dev
mkdir ~/.caddy-dev/
touch ~/.caddy-dev/.keep
mkdir ~/.caddy-dev/imports
touch ~/.caddy-dev/imports/.keep
echo "import imports/*" >> ~/.caddy-dev/CaddyfileIf you'd like to help, reach out!
puma-dev: https://github.com/puma/puma-dev- https://andre.arko.net/2023/03/05/caddy-puma-dev-for-local-development-with-custom-domains-and-https/
- https://maxschmitt.me/posts/local-subdomains-dnsmasq-caddy
- https://vninja.net/2020/02/06/macos-custom-dns-resolvers/
- https://tobiasmaier.info/posts/2024/10/27/linux-puma-dev-caddy.html
- https://mvogelgesang.com/blog/20240419/creating-a-simple-homebrew-formula/