Puma-dev is one of my favourite tools
Running applications locally on your laptop is normally a doddle. Boot up a Rails app and point your browser at
http://localhost:3000
Easy peasy. But what if your application is not your average application. Suppose it’s multi-tenanted app with a hostname for each tenant and you want to try that locally. Well you could whack a load of entries in your /etc/hosts
/etc/hosts
##
# Host Database
#
# localhost is used to configure the loopback interface
# when the system is booting. Do not change this entry.
##
127.0.0.1 demo.fossa-are-great.org
127.0.0.1 demo.fossa-are-ok.org
127.0.0.1 localhost
255.255.255.255 broadcasthost
::1 localhost
Then you could visit…
http://demo.fossa-are-great.org:3000/
http://demo.fossa-are-ok.org:3000/
…with ease and everything would be fine, even if port 3000 is now a little jarring. It is possible to remove the port if we ran our own version of Nginx running on port 80 and configured it to proxy onto our running application on port 3000. I’m going to go out on a limb and say there are will be a high proportion of developers that won’t know how to configure Nginx to do this and it’s a bit overkill anyway. However, puma-dev makes pretty light work of this.
Puma-dev: A fast, zero-config development server for macOS and Linux - https://github.com/puma/puma-dev
On macOS it’s pretty easy to set up with brew
brew install puma/puma/puma-dev
# Configure some DNS settings that have to be done as root
sudo puma-dev -setup
# Configure puma-dev to run in the background on ports 80 and 443 with the domain `.test`.
puma-dev -install
Then in order to configure our hostnames we create a file the ~/.puma-dev per hostname we want to support with the port of the running application.
~/.puma-dev/demo.fossa-are-great
3000
~/.puma-dev/demo.fossa-are-ok
3000
This time we have to visit our domain with the .test Top-Level Domain as Puma Dev, by default, supports that TLD. Puma-dev runs on port 80 and 443 as standard and so there is no need to supply a port.
http://demo.fossa-are-great.test/
http://demo.fossa-are-ok.test/
The way this works is really neat and I’m a bit of a fan to be fair. Hostnames on macOS and Linux flavours uses /etc/resolver/. Puma creates a file /etc/resolver/test
to indicate that name resolution for .test domains should use a local nameserver running on port 9253 to resolve hostname blah.test
# Generated by puma-dev
nameserver 127.0.0.1
port 9253
In fact let’s try it
dig blah.test @127.0.0.1 -p 9253
; <<>> DiG 9.10.6 <<>> blah.test @127.0.0.1 -p 9253
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 2962
;; flags: qr rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; WARNING: recursion requested but not available
;; QUESTION SECTION:
;blah.test. IN A
;; ANSWER SECTION:
blah.test. 0 IN A 127.0.0.1
;; Query time: 0 msec
;; SERVER: 127.0.0.1#9253(127.0.0.1)
;; WHEN: Mon Feb 05 15:42:26 GMT 2024
;; MSG SIZE rcvd: 52
Yep, this returns and resolves our domain to 127.0.0.1, however visiting http://blah.test will result in the following because we haven’t configured puma-dev to point at an internal port.
unknown app
This is pretty neat huh? Well that’s not the end of the story. What if we wanted to use https://demo.fossa-are-great.test. Well that just works out of the box. Like I said it also runs on port 443. Puma manages the certificate authority for the .test domain locally and adds the certificate and key to the local keychain so now we have valid SSL. Magic.
% ls -la ~/Library/Application\ Support/io.puma.dev
total 16
drwx------ 4 rl staff 128 16 Jan 09:03 .
drwx------+ 62 rl staff 1984 29 Jan 02:06 ..
-rw-r--r-- 1 rl staff 1208 16 Jan 09:03 cert.pem
-rw------- 1 rl staff 1679 16 Jan 09:03 key.pem
I’ve been using this setup for years now and it has enabled us to run multiple applications locally and fully test running up to 5 different multi-tenanted Rails apps logging users in with the same cookie domain as an extreme example.
https://app1.blah.something.test
https://app1.club.something.test
https://app2.blah.something.test
https://app2.club.something.test
https://app3.blah.something.test
https://app3.club.something.test
I have only ever found one issue with this setup and that was today.
SSL Certificate seemingly invalid
Today’s issue involved building PDFs with Grover that had missing styles and as it turned out the this was only over SSL so there was an issue with the certificate which was fixed by re-configuring Puma-dev to presumably re-add the certificate to the keychain.
puma-dev -uninstall
sudo puma-dev -setup
puma-dev -install
puma-dev -stop
Thumbs up for puma-dev