Browse Source

Better Puma configuration + documentation for systemd unit

Jérémy Lecour 1 year ago
4 changed files with 85 additions and 27 deletions
  1. +24
  2. +4
  3. +21
  4. +36

+ 24
- 4 View File

@ -11,7 +11,7 @@ We are usually running Chexpire on typical POSIX servers like :
- Linux Debian 9, Ruby 2.5.4, NodeJS 8.11 and MariaDB 10.1
- macOS High Sierra, Ruby 2.5.4, NodeJS 10.2.1 and MariaDB 10.2
It probably works on any system that supports Ruby >2.3, NodeJS >6 and MySQL >5.5. Feel free to report any unexpected incompatibilities.
It probably works on any system that supports Ruby >= 2.5.4, NodeJS >= 6 and MySQL >= 5.5. Feel free to report any unexpected incompatibilities.
If you use rbenv, chruby or RVM, you can set your prefered Ruby version in the `.ruby-version` file at the root of the project.
@ -34,7 +34,7 @@ If you want to do manual installations, you can use our Wiki documentations for
Execute `# bundle install` to install Ruby gems (including Rails itself).
Execute `# yarn install` to install Javascript/NodeJS packages.
Execute `# yarn install --check-files` to install Javascript/NodeJS packages.
Depending on what is already installed on your OS or not, you might need to install a few system packages to be able to have everything working.
@ -45,15 +45,21 @@ To use elliptic curve SSH keys, we need to have `libsodium` and its headers.
* on macOS with Homebrew : `# brew install libsodium`.
## Rails configuration
## Application configuration
After cloning this repository, you have to create and edit a few files for your local development/test configuration. Theses files will be ignored by git.
### Environment variables
A handful of settings can be set by environment variables. If you use Heroku-like platforms they offer a simple way to set them.
If you use Rbenv, there is the `rbenv-vars` plugin. That is what we recommend on POSIX servers. You have to put an `.rbenv-vars` file at the root of the project. If you use Capistrano, put it in the shared directory and have it linked in the `current` directory at deploy time.
### Database configuration
Create the file if missing : `cp config/database.example.yml config/database.yml`. If you change the settings in the `defaults` section it applies to the `development` and `test` sections. More information is available at "":
Note that on Debian 9 with MariaDB, the database socket is at `/var/run/mysqld/mysqld.sock`, which is not the default in the configuration file.
Note that on Debian 9+ with MariaDB, the database socket is at `/var/run/mysqld/mysqld.sock`, which is not the default in the configuration file.
### Rails secrets
@ -113,3 +119,17 @@ You can use the `script/to_staging` and/or `script/to_production` scripts.
* with `to_production` you deploy the `master` branch to production.
On the remote servers – where the application will be deployed – you have to copy the configuration files just as you've just did for your development setup. The files has to go in the `shared/config/` directory, relative to your `deploy_to` path. They will be symlinked to the proper destination by Capistrano.
If an `.rbenv-vars` file is found in the shared directory, it will be linked to help loading environment files (by Ruby via Rbenv, systemd…).
### systemd
If you want to use systemd to manage your Puma process, there are [a few different ways]( We've prepared a systemd unit file (`config/deploy/puma-chexpire@.service`) but you can adjust to better suit your needs.
If you deploy your application to `/home/chexpire_<environment>`, the systemd unit can be used as a template, for example : `puma-chexpire@production.service`. This template is compatible with systemd actions like `systemctl stop puma-chexpire@production.service` and also with Capistrano tasks like `cap production puma:stop`.
To install the systemd unit :
$ cp config/deploy/puma-chexpire@.service /etc/systemd/system/puma-chexpire@.service
$ systemctl enable puma-chexpire@<environment>.service

+ 4
- 0
config/deploy.rb View File

@ -24,12 +24,16 @@ set :repo_url, ""
# Default value for :linked_files is []
append :linked_files,
# Default value for linked_dirs is []
# append :linked_dirs, "log", "tmp/pids", "tmp/cache", "tmp/sockets", "public/system"
append :linked_dirs,
# Default value for default_env is {}
# set :default_env, { path: "/opt/ruby/bin:$PATH" }

+ 21
- 0
config/deploy/puma-chexpire@.service View File

@ -0,0 +1,21 @@
Description=Puma Server for Chexpire (%i)
ExecStart=/home/chexpire_%i/.rbenv/bin/rbenv exec bundle exec puma -C /home/chexpire_%i/www/current/config/puma.rb --daemon
ExecStop=/home/chexpire_%i/.rbenv/bin/rbenv exec bundle exec pumactl -F /home/chexpire_%i/www/current/config/puma.rb stop
ExecReload=/home/chexpire_%i/.rbenv/bin/rbenv exec bundle exec pumactl -F /home/chexpire_%i/www/current/config/puma.rb phased-restart

+ 36
- 23
config/puma.rb View File

@ -8,31 +8,44 @@ 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
# Specifies the `port` that Puma will listen on to receive requests; default is 3000.
port ENV.fetch("PORT") { 3000 }
# Specifies the `environment` that Puma will run in.
environment ENV.fetch("RAILS_ENV") { "development" }
rails_env = ENV.fetch("RAILS_ENV") { "development" }
environment rails_env
# Specifies the `pidfile` that Puma will use.
pidfile ENV.fetch("PIDFILE") { "tmp/pids/" }
app_dir = File.expand_path("../..", __FILE__)
directory app_dir
shared_dir = "#{app_dir}/tmp"
# Specifies the number of `workers` to boot in clustered mode.
# Workers are forked web server processes. If using threads and workers together
# the concurrency of the application would be max `threads` * `workers`.
# Workers do not work on JRuby or Windows (both of which do not support
# processes).
# workers ENV.fetch("WEB_CONCURRENCY") { 2 }
if %w[production staging].member?(rails_env)
# Logging
stdout_redirect "#{app_dir}/log/puma.stdout.log", "#{app_dir}/log/puma.stderr.log", true
# Use the `preload_app!` method when specifying a `workers` number.
# This directive tells Puma to first boot the application and load code
# before forking the application. This takes advantage of Copy On Write
# process behavior so workers use less memory.
# preload_app!
# Set master PID and state locations
pidfile "#{shared_dir}/pids/"
state_path "#{shared_dir}/pids/puma.state"
# Change to match your CPU core count
workers ENV.fetch("WEB_CONCURRENCY") { 2 }
# Set up socket location and port
bind "unix://#{shared_dir}/sockets/puma.sock"
port ENV.fetch("PORT") { 3000 }
before_fork do
# Allow puma to be restarted by `rails restart` command.
plugin :tmp_restart
on_worker_boot do
ActiveSupport.on_load(:active_record) do
db_url = ENV.fetch('DATABASE_URL')
# puts "puma: connecting to DB at #{db_url}"
elsif rails_env == "development"
# Specifies the `port` that Puma will listen on to receive requests; default is 3000.
port ENV.fetch("PORT") { 3000 }
plugin :tmp_restart