“...I've been working since 2008 with Ruby / Ruby on Rails, love a bit of Elixir / Phoenix and learning Rust. I also poke through other people's code and make PRs for OpenSource Ruby projects that sometimes make it. Currently working for InPay...”

Rob Lacey
Senior Software Engineer, UK

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

GPK of the Day Wrappin' RUTH