Custom Rails servers

Using Puma web server

Puma is a light-weight web server built for speed and parallelism.

Deploying with Puma

To run a Puma web server, add a line to your Procfile labeled as custom_web. Here is an example that relies on our sample config file below:

custom_web: bundle exec puma

You can change freely between other supported servers by simply updating your Gems and Procfile.

Don't daemonize custom_web

You should not daemonize the custom_web process. In other words, please do not use the -d or -daemon flags in your initialization string. Please also make sure your config file does not enable daemonization.

We do not support old-style daemonization because it is more reliable to allow the system's process manager (systemd) to handle persistent processes.

Sample config file for Puma

The following config file will work with Cloud 66. Please take careful note that it enables features like preload_app! and explicitly sets the number of workers. This will prevent you from using rolling restarts (see below), so will need to be changed if you intend to use that feature.

max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count }
threads min_threads_count, max_threads_count

port ENV.fetch("PORT") { 3000 }
environment ENV.fetch("RAILS_ENV") { "development" }
pidfile ENV.fetch("CUSTOM_WEB_PID_FILE") { "/tmp/" }

workers ENV.fetch("WEB_CONCURRENCY") { 2 }

directory ENV.fetch("STACK_PATH") { "." }
bind ENV.fetch("CUSTOM_WEB_SOCKET_FILE") { "unix:///tmp/web_server.sock" }

(We also have a commented plain-text version of this config with explanatory notes)

What does the directory block do?

The directory block in the above config ensures that Puma will use the latest version of your code when it is deployed. Without this block, some versions of Puma will continue to point to older versions of code until "hard" restarted. You can also find this in the init string below (--dir $STACK_PATH).

If you'd prefer to use Puma without having a config file, you can simply use this catch-all initialization string:

custom_web: bundle exec puma -e $RACK_ENV -b unix:///tmp/web_server.sock --pidfile /tmp/ --dir $STACK_PATH

Customizing shutdown and reload signals

The default shutdown command for Puma servers on Cloud 66 is USR2 and the default shutdown sequence for applications using systemd (our default process manager) is:

term, 90, kill

If you need your web server to shut down using a different command, or in a particular sequence, or with longer or shorter delays, you can define a custom restart sequence in the procfile_metadata section of your Manifest file.

For non-web process signals, please consult our systemd guide.

Achieving zero downtime reloads

If you'd like your application servers to be able to reload without any downtime then you need to make some changes to the configuration of your restart sequence.

Our default restart sequence for Puma servers uses the USR2 signal, which restart workers and reloads the Puma configuration file, if there is one. To achieve a rolling restart (i.e. zero downtime) you need to set your Puma servers to use the USR1 signal instead. See above for instructions on customizing your signals.

The result would look something like this:

      restart_signal: usr1

Please be sure you understand the tradeoffs of using USR1 - read this for more context. You may also need to make changes to your Puma config files as per the same doc. In short:

  • Don't use preload!
  • Use prune_bundler instead

Does not apply to env_vars

An important caveat here: this will not apply when you make changes to environment variables. That requires a full (hard) restart.

Controlling Puma via your terminal

Cloud 66 uses the following signals to control Puma via systemd:

Stop the web server

sudo systemctl stop cloud66_web_server.service

Start the web server

sudo systemctl start cloud66_web_server.service

Restart the web server

sudo systemctl restart cloud66_web_server.service
Unicorn web server