diff --git a/README.md b/README.md index 4677f54df3..a52b7ae97f 100644 --- a/README.md +++ b/README.md @@ -339,6 +339,11 @@ $ bundle exec cap puma:stop $ bundle exec cap puma:phased-restart ``` +See +[docs/systemd](https://github.com/puma/puma/blob/master/docs/systemd.md), +including the last section, if using this in conjunction with systemd +(all recent, major distributions of Linux). + ## Contributing To run the test suite: diff --git a/docs/systemd.md b/docs/systemd.md index 0571b2f9a6..530e0b849e 100644 --- a/docs/systemd.md +++ b/docs/systemd.md @@ -3,10 +3,21 @@ [systemd](https://www.freedesktop.org/wiki/Software/systemd/) is a commonly available init system (PID 1) on many Linux distributions. It offers process monitoring (including automatic restarts) and other -useful features for running Puma in production. Below is a sample -puma.service configuration file for systemd: +useful features for running Puma in production. -~~~~ +## Service Configuration + +Below is a sample puma.service configuration file for systemd, which +can be copied or symlinked to /etc/systemd/system/puma.service, or if +desired, using an application or instance specific name. + +Note that this uses the systemd preferred "simple" type where the +start command remains running in the foreground (does not fork and +exit). See also, the +[Alternative Forking Configuration](#alternative-forking-configuration) +below. + +~~~~ ini [Unit] Description=Puma HTTP Server After=network.target @@ -21,22 +32,21 @@ Type=simple # Preferably configure a non-privileged user # User= -# Specify the path to your puma application root -# WorkingDirectory= +# The path to the puma application root +# Also replace the "" place holders below with this path. +WorkingDirectory= # Helpful for debugging socket activation, etc. # Environment=PUMA_DEBUG=1 -# The command to start Puma -# Here we are using a binstub generated via: -# `bundle binstubs puma --path ./sbin` -# in the WorkingDirectory (replace below) -# You can alternatively use `bundle exec --keep-file-descriptors puma` -# ExecStart=/sbin/puma -b tcp://0.0.0.0:9292 -b ssl://0.0.0.0:9293?key=key.pem&cert=cert.pem - -# Alternatively with a config file (in WorkingDirectory) and -# comparable `bind` directives +# The command to start Puma. This variant uses a binstub generated via +# `bundle binstubs puma --path ./sbin` in the WorkingDirectory +# (replace "" below) +ExecStart=/sbin/puma -b tcp://0.0.0.0:9292 -b ssl://0.0.0.0:9293?key=key.pem&cert=cert.pem + +# Variant: Use config file with `bind` directives instead: # ExecStart=/sbin/puma -C config.rb +# Variant: Use `bundle exec --keep-file-descriptors puma` instead of binstub Restart=always @@ -50,14 +60,16 @@ for additional details. ## Socket Activation systemd and puma also support socket activation, where systemd opens -the listening socket(s) in advance and provides them to the puma master -process on startup. Among other advantages, this keeps listening -sockets open across puma restarts and achieves graceful restarts. To -use socket activation, configure one or more `ListenStream` -sockets in a companion `*.socket` systemd config file. Here is a sample -puma.socket, matching the ports used in the above puma.service: - -~~~~ +the listening socket(s) in advance and provides them to the puma +master process on startup. Among other advantages, this keeps +listening sockets open across puma restarts and achieves graceful +restarts, including when upgraded puma, and is compatible with both +clustered mode and application preload. To use socket activation, +configure one or more `ListenStream` sockets in a companion `*.socket` +systemd config file. Here is a sample puma.socket, matching the ports +used in the above puma.service: + +~~~~ ini [Unit] Description=Puma HTTP Server Accept Sockets @@ -169,29 +181,71 @@ Apr 07 08:40:19 hx puma[28320]: * Activated ssl://0.0.0.0:9234?key=key.pem&cert= Apr 07 08:40:19 hx puma[28320]: Use Ctrl-C to stop ~~~~ -## Alternative background process configuration - -If Capistrano and [capistrano3-puma](https://github.com/seuros/capistrano-puma) tasks are used you can use the following configuration. In this case, you would skip systemd Socket Activation, since Puma handles the socket by itself: +## Alternative Forking Configuration + +Other systems/tools might expect or need puma to be run as a +"traditional" forking server, for example so that the `pumactl` +command can be used directly and outside of systemd for +stop/start/restart. This use case is incompatible with systemd socket +activation, so it should not be configured. Below is an alternative +puma.service config sample, using `Type=forking` and the `--daemon` +flag in `ExecStart`. Here systemd is playing a role more equivalent to +SysV init.d, where it is responsible for starting Puma on boot +(multi-user.target) and stopping it on shutdown, but is not performing +continuous restarts. Therefore running Puma in cluster mode, where the +master can restart workers, is highly recommended. See the systemd +[Restart] directive for details. + +~~~~ ini +[Unit] +Description=Puma HTTP Forking Server +After=network.target -~~~~ [Service] # Background process configuration (use with --daemon in ExecStart) Type=forking -# To learn which exact command is to be used to execute at "ExecStart" of this -# Service, ask Capistrano: `cap puma:start --dry-run`. Your result -# may differ from this example, for example if you use a Ruby version -# manager. `` is short for "your working directory". Replace it with your -# path. +# Preferably configure a non-privileged user +# User= + +# The command to start Puma +# Replace "" below, with the application root or working directory ExecStart=bundle exec puma -C /shared/puma.rb --daemon -# To learn which exact command is to be used to execute at "ExecStop" of this -# Service, ask Capistrano: `cap puma:stop --dry-run`. Your result -# may differ from this example, for example if you use a Ruby version -# manager. `` is short for "your working directory". Replace it with your -# path. +# The command to stop Puma +# Replace "" below ExecStop=bundle exec pumactl -S /shared/tmp/pids/puma.state stop -# PIDFile setting is required in order to work properly +# Path to PID file so that systemd knows which is the master process PIDFile=/shared/tmp/pids/puma.pid + +# Should systemd restart puma? +# Use "no" (the default) to ensure no interference when using +# stop/start/restart via `pumactl`. The "on-failure" setting might +# work better for this purpose, but you must test it. +# Use "always" if only `systemctl` is used for start/stop/restart, and +# reconsider if you actually need the forking config. +Restart=no + +[Install] +WantedBy=multi-user.target ~~~~ + +### capistrano3-puma + +By default, +[capistrano3-puma](https://github.com/seuros/capistrano-puma) uses +`pumactl` for deployment restarts, outside of systemd. To learn the +exact commands that this tool would use for `ExecStart` and +`ExecStop`, use the following `cap` commands in dry-run mode, and +update from the above forking service configuration accordingly. Note +also that the configured `User` should likely be the same as the +capistrano3-puma `:puma_user` option. + +~~~~ sh +stage=production # or different stage, as needed +cap $stage puma:start --dry-run +cap $stage puma:stop --dry-run +~~~~ + +[Restart]: https://www.freedesktop.org/software/systemd/man/systemd.service.html#Restart= diff --git a/tools/jungle/README.md b/tools/jungle/README.md index 0907f95d8e..d4ef36e82b 100644 --- a/tools/jungle/README.md +++ b/tools/jungle/README.md @@ -7,3 +7,7 @@ See `/tools/jungle/init.d` for tools to use with init.d and start-stop-daemon. ## Upstart See `/tools/jungle/upstart` for Ubuntu's upstart scripts. + +## Systemd + +See [/docs/systemd](https://github.com/puma/puma/blob/master/docs/systemd.md).