Switching From Pow To Puma for Rails development
Thanks to the recent changes with how Chrome handles the Google-owned
.dev TLD, it is no longer recommended to run Ruby on Rails apps with Pow in development in OSX/macOS. Pow doesn’t support HTTPS and Basecamp have ceased development of it after 7 years, so it’s time to move on.
I’ve researched a few alternatives (eg. powprox, Invoker, docker, nginx), but the most effective one by far for quickly switching from Pow is Puma-dev. This operates in a similar way to Pow, but uses the Rails-recommended Puma to serve your app in development. The guide below is designed specifically for migrating from Pow to Puma-dev with minimal impact to your environment, so if you’re starting fresh you may want to review their suggested defaults instead.
This guide will assume you have been using Pow, but haven’t tried any other ways of supporting HTTPS on your dev machine (such as Powprox or Invoker). If you have, please make sure you have removed any files they may have installed as there is a potential for conflicts here. You will also need Homebrew installed.
1. Uninstall Pow
This is important! It also means all your current projects will need migrating at the same time, so make sure anyone else working on a project is also ready to follow this guide. Here’s the rather-sketchy uninstall command for a standard Pow installation:
curl get.pow.cx/uninstall.sh | sh
It was also possible to install Pow with Homebrew, so you did that, you’ll need:
brew uninstall pow
2. Add Puma to your Rails app
Update your project’s
Gemfile to include
gem 'puma' in the development group – newer Rails apps will have this by default. You should remove any existing dev server, such as Unicorn. Be sure not to change anything that will affect your production environment!
bundle install to get the gem and its dependencies.
3. Install puma-dev
The following commands do the install and will make sure the DNS resolver can be set up properly later. It also generates the root CA certificate that will be used to seamlessly generate valid SSL certificates for your projects.
brew install puma/puma/puma-dev sudo puma-dev -setup
4. Start puma-dev
We’re going to install Puma-dev as a background service, using the
.dev extension, and refer to the
~/.pow/ directory for matching domain names to project folders.
If you’d rather run Puma-dev only when you need it, then don’t pass the
-install option. Make yourself a simple bash script or alias instead, to ensure you always start with the correct options.
puma-dev -install -d dev -dir ~/.pow/
Note: Because we’re trying to achieve the simplest migration with the fewest changes, we are continuing to use the
.dev TLD – you may want to take this opportunity to change to using a more appropriate
.localhost TLD. You will definitely want to do this if your project doesn’t support SSL.
4a. How to link new projects in future
As with Pow, Puma-dev needs to know where to find the app code for each domain you want to use. If you used the
-dir ~/.pow/ option above then your existing Pow projects are already linked. For all new projects, a helper method is provided:
cd ~/projects/my-project puma-dev link
This will link
my-project.dev to the app in
~/projects/my-project. To use a different domain or project path, there are two options, eg.
puma-dev link -n other-name ~/projects/other-path
This will link
5. Tail the log
To see debug information about Puma-dev’s operation, you can tail the log:
tail -f ~/Library/Logs/puma-dev.log
6. Environment variables
Your project’s environment variables will be loaded (in order, using
source) from the following files in the project root path:
It will also
source ~/.powconfig first if it exists. Note that any
POW_* variables you may have used in the past will have no effect on Puma-dev’s operation.
You can configure the Puma server by setting the following variables in your
These don’t appear to have any effect when set per project, just globally for all Puma instances started by Puma-dev. So what should these be set to? In short, I only recommend setting
THREADS=3 and leaving the other two unset.
Note: I tried setting
WORKERS=3 and ran into system stability problems which I think was related to too many
fsevent_watch processes running after a few hours of development work, preventing any forking. This may be something to do with
ActiveSupport::EventedFileUpdateChecker and how the
listen gem monitors changes to your source code per process. With
WORKERS set to zero, there’s no real need to set
CONFIG either (for example to the Rails-provided
config/puma.rb). If you really want to use workers, be sure to read the comments in your
config/puma.rb file relating to pre/post fork actions – but it’s probably overkill for most apps.
7. Refresh DNS and SSL
To ensure Puma-dev can capture and serve your web requests, now do the following:
- Toggle your WiFi/Ethernet off and on to force an update the DNS resolver
- Fully quit your web browser and re-open it to get the updated root certificate
- Visit one of your project domains, eg. https://my-project.dev
If everything is working, after a short delay for the app to boot first-time (watch this happening by tailing the log) your project homepage should now be loaded with a valid SSL certificate.
If you have problems, here are how I solved the ones I ran into…
Invalid SSL certificate
If your browser complains about an untrusted root certificate, please do the following:
- Open Keychain Access
- Click the ‘login’ keychain in the left pane, then find the ‘Puma-dev CA’ certificate in the right pane
- Double-click it and expand the ‘Trust’ section, and make sure it says ‘Always Trust’
- Drag it into the ‘System’ keychain in the left pane
- Restart your computer
- Try https://my-project.dev again!
If you get this message on a blank page, check the Puma-dev log and the Rails log for errors preventing the app from booting. Perhaps you forgot to install the Puma gem? I know I definitely didn’t forget to do that the first time round.
If you get this message on a blank page, then the URL you are using isn’t linked to a project path. Go to
~/.pow/ and make sure there is a symlink (of the same name as your URL, excluding the
.dev) to a valid project path.
Browser timeout / no response
If you don’t get a response, check the state of Puma-dev:
curl -H "Host: puma-dev" localhost/status
You should get a bit of JSON back, read that for more details. If you get an error, make sure Puma-dev is active by re-running the install command from Step 4 and monitoring the log for errors.