Use Puma to deploy your Rails APP with SSL
Background
We at peaq develop several Rails applications. Some of them are installed on premise on a customer server. Although such applications are not publicly accessible, you want to secure their connections by SSL though.
The typical recommendation for deploying Rails-Apps says, you should set up NGINX or Apache to serve the assets and use those web servers as reverse proxies for routing all dynamic requests to the Rails application-server (like Unicorn or Puma). But typically such private applications do not have heavy load and it would be overkill to deploy them with this approach. It would be handy to have an application server, which handles SSL directly. The good answer: It is possible with Puma!
Configure your Rails-App to use Puma
First you need to configure Puma to be your application server. There’s a good chance, that you can skip this step as Puma is the default application server since Rails 5. But for all which are still using Rails 4, add the following line to your Gemfile:
gem 'puma'
Create your SSL certificates
Once Puma is your default application server, it is time to create the SSL certificates. We are using openssl for this. There are 5 steps, you need to execute:
Step 1: Generate your private key
openssl genrsa -des3 -passout pass:x -out server.pass.key 2048
Step 2: Remove passphrase from key
openssl rsa -passin pass:x -in server.pass.key -out server.key
Step 3: Generate a CSR (Certificate Signing Request)
openssl req -new -key server.key -out server.csr
Step 4: Generating a Self-Signed Certificate
openssl x509 -req -sha256 -days 365 -in server.csr -signkey server.key -out server.crt
Step 5: Copy the CSR- and KEY-Files to your config directory
cp server.crt server.key /path_to_your/rails_app/config
Test: Start your Rails-App with SSL
Once Puma is your application server, simply start the server with the following options, and you have SSL connection to your Rails App:
puma -b 'ssl://127.0.0.1:3000?key=/path_to_your/rails_app/config/server.key&cert=/path_to_your/rails_app/config/server.crt'
Configure Puma
If the test is successful, Puma could be configured with a config file called config/puma.rb. The advantage of doing it this way is, that you don’t need to remember all the SSL-options for starting your server. Here is a working puma.rb configured for SSL:
# Config Parameters
app_root = ENV['APP_ROOT'] || '.'
rails_env = ENV['RAILS_ENV'] || 'production'
ip_addr = ENV['IP_ADDR'] || 'localhost'
port = ENV['PORT'] || 3000
ssl_key = ENV['SSL_KEY']
ssl_cert = ENV['SSL_CERT']
# Set Puma parameters
preload_app!
rackup DefaultRackup
environment rails_env
pidfile "#{app_root}/tmp/pids/puma.pid"
state_path "#{app_root}/tmp/pids/puma.state"
threads 0, 16
workers 2
stdout_redirect "#{app_root}/log/puma.log", "#{app_root}/log/puma.err", true if rails_env.downcase == 'production'
# HTTP or HTTPS
if ssl_key.present? && ssl_cert.present?
bind "ssl://#{ip_addr}:#{port}?key=#{ssl_key}&cert=#{ssl_cert}"
else
bind "tcp://#{ip_addr}:#{port}"
end