23 Jul 2023

Caddy plus puma-dev with SSL

Last time, we talked about setting up Caddy as a reverse-proxy to puma-dev, providing automatically-managed local development Rails apps on their own dedicated .test domains. Either I missed this back then, or something inside puma-dev or Caddy changed in the meantime, but SSL requests stopped working inside Rails apps today, and it took me a while to figure out what was happening.

I started getting the exception HTTP Origin header (https://example.com) didn't match request.base_url (http://example.com), and tracked it down to the HTTP_X_FORWARDED_PROTO getting sent to Rails, which was being set to http. Unfortunately, just setting the header X-Forwarded-Proto: https doesn’t work, because both Caddy and puma-dev strip it out and set their own value before sending the request on to the Rails app.

After a bunch more fiddling around, I figured out how to get Caddy to generate an SSL certificate for the requesting domain, using its internal certificate authority, and make a request to puma-dev over SSL, without validating the (self-signed) certificate provided by puma-dev. With this slightly more complicated Caddy config block, SSL is again working:

*.test {
	tls internal {
		on_demand
	}
	reverse_proxy https://127.0.0.1:9283  {
		transport http {
			tls_insecure_skip_verify
		}
	}
	log
}

Caddy + puma-dev for local development with custom domains and HTTPS
Homebrew cask formula for private GitHub repo releases
My time to write is sponsored by Spinel. If your company could use some world-class expertise on gems, Rails, CI, or developer productivity, check out spinel.coop and hire us!