猫Rails

ねこー🐈

Pumaの使い方 まとめ

  • 自分用のメモを公開したものです。ドキュメント/ソースコード等をまとめただけで試していないコードも多いので、信頼性は低いです。

感想

  • 新規にRailsアプリ作るならpuma使えば良さそう。でも、unicornやpassengerから乗り換えるほどではないかも(ケースバイケースだがパフォーマンスの顕著な差はないっぽい)
  • Heroku使う場合はメモリ使用量が少なくて良さそう。メモリ500MBプランだとunicornで2worker動かすの辛かった記憶

スレッドベース

参考

unicornはプロセスベース

  • workerプロセスが2つあったら、2つのリクエストを同時に処理できる
  • メリット
    • シンプル(理解しやすい + コードが綺麗になりやすい)
    • スレッドの知識がなくても安心
    • スレッドセーフなコードを意識しなくても良い(普通にRailsアプリを書いていれば問題なさそうだけど、スレッドの知識が浅いので不安)

pumaはスレッドベース

  • スレッドが2つあったら、2つのリクエストを同時に処理できる
  • 実際には本番環境ではマルチプロセス + マルチスレッドで動かす(Clustered mode)。workerプロセスが2つ + スレッドが2つだったら、4つのリクエストを同時に処理できる
  • ただし実際には、MRIではGILがあるため1プロセスで1スレッドしか実行されない
  • メリット
    • (MRIだとしても)IO時に別スレッドに処理させることができる
    • スロークライアントの影響を受けにくい
    • メモリ使用量が少ない(参考: http://puma.io/)

MRIのスレッド

  • スレッドは複数持てるが、同時に実行できるスレッドは1つ。GIL(Global Interpreter Lock)のため。
  • ただし、Bocking IO(ファイルIO、ネットワークIO等)になった際に、別のスレッドに切り替えて処理を進める。MRIでもスレッドベースの恩恵は部分的にある。
  • IOはだいたい総時間の10~25%程度らしい(参考: https://techracho.bpsinc.jp/hachi8833/2017_11_13/47696)

Jruby・Rubiniusのスレッド

  • スレッドをフルに使える
  • pumaにはJrubyやWindows特有の成約がいくつかある(別項目)
  • MRI以外使うことはないかなー

スロークライアント

  • 回線の遅いクライアント(3Gのモバイル端末など)
  • Pumaはスレッドベースなので、IOの際に(MRIだとしても)別のスレッドに処理をさせることができる。なのでネットワークIOが長いスロークライアントには都合がよい

railsへの導入

# Gemfile

gem 'puma'
$ bundle install
# 起動

# $ rails s Puma
$ rails s

設定

参考URL

設定ファイルの読み込み

  • 3つの起動コマンド(rails spumactl startpuma)は、以下の設定ファイルを自動で読み込む
    • 環境指定がない場合: config/puma.rb
    • 環境指定がある場合: config/puma/<environment_name>.rb
  • pumactl -F config/puma.rb startのように、オプションで指定することも可能

設定項目

bind: バインド

  • URI指定しかないので、シンプル
  • デフォルト: "tcp://0.0.0.0:9292"
# TCPソケットを使う場合
bind 'tcp://0.0.0.0:9292'

# UNIXソケットを使う場合
# TCPより若干パフォーマンスが上がる(場合がある)
bind 'unix:///var/run/puma.sock'

# UNIXソケットのパーミッションを変更する必要がある場合、umaskパラメーターを利用する
bind 'unix:///var/run/puma.sock?umask=0111'

# SSLを利用する場合
bind 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert'

port: バインド(portとhost)

  • bind使えばok
# bind 'tcp://0.0.0.0:9292' と同じ
port '9292', '0.0.0.0'

ssl_bind: バインド(SSL)

  • bind使えばok
# bind 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert' と同じ
ssl_bind '127.0.0.1', '9292', {
  key: path_to_key,
  cert: path_to_cert
}

workers: ワーカー数

  • ワーカー数を指定するとclustered modeになる
  • master processからworkerをforkする
  • workerプロセスはそれぞれスレッドプールを持つ
  • デフォルト: 0
# ワーカー2スレッド16の場合、スレッドは合計で32になる
workers 2

threads: スレッド数のmin・max

  • プールで利用できるスレッドの数
  • スレッド数はtrafficによって自動で増減する
  • maxを大きくしすぎるとマシンリソースを食いつくしてしまう可能性があるので、注意
  • ここで指定したスレッド以外にも、スロークライアントの処理等のpuma自体の内部的な処理にもスレッドが作られるので注意。なので-t 1:1で指定しても、実際には7スレッドくらいが作成される。
  • デフォルト: 0:16
threads 16, 16

environment: 環境

  • デフォルト: "development"
environment 'production'
environment ENV.fetch("RAILS_ENV") { "development" } # railsで使う場合は、環境変数RAILS_ENVを使うのが良さげ

demonize: デーモン化

  • デフォルト: false
  • pidfile、stdout_redirectと一緒に使う
daemonize true

pidfile: pidファイル置き場

pidfile '/u/apps/lolcat/tmp/pids/puma.pid'
pidfile "#{Dir.pwd}/tmp/pids/puma.pid" # Railsの場合、tmp/pids/puma.pidに置くと良さげ

stdout_redirect: 標準出力/標準エラーを出力するファイル

  • 第三引数は追記モード
stdout_redirect '/u/apps/lolcat/log/stdout', '/u/apps/lolcat/log/stderr'
stdout_redirect '/u/apps/lolcat/log/stdout', '/u/apps/lolcat/log/stderr', true

preload_app!: プリロード

  • 全てのアプリコードをfork前にロードする。これによりRuby 2.0+の場合、OSのcopy-on-writeが効く。そのためメモリ使用量が下がる
  • Cluster modeでしか使えない
  • phased-restartとpreloadは同時には使えない
preload_app!

before_fork{}: 各ワーカーのフォーク前の処理

before_fork do
  ActiveRecord::Base.connection_pool.disconnect!
end

on_worker_boot{}: 各ワーカーのboot前の処理

  • ブート前のセットアップはここで行う
  • アプリ固有ではなく、puma固有の処理はここで行う
  • DB接続はここでやっておく
on_worker_boot do
  ActiveSupport.on_load(:active_record) do
    ActiveRecord::Base.establish_connection
  end
end

prune_bundler: phased_restart時にbundlerのコンテキストを新しいものに切り替えてくれる

  • これによりphased_restart(1つずつ再起動)した時に最新のGemfileを見に行ってくれる
  • phased_restartを行いたい時にほぼ必須のオプション
  • デフォルト: off
prune_bundler

plugin: プラグイン読み込み

plugin :tmp_restart

activate_control_app: コントロールサーバのURL

  • pumactlコマンドでpumaを操作するのに利用する
  • 詳しくは コントロールサーバ を参照
# デフォルト: localhostのport 9293
activate_control_app

# unixソケット
activate_control_app 'unix:///var/run/pumactl.sock'

# tokenによる認証
# トークンを指定すると、クエリパラメータにそのトークンを指定しなければいけなくなる
activate_control_app 'unix:///var/run/pumactl.sock', { auth_token: '12345' }
activate_control_app 'unix:///var/run/pumactl.sock', { no_token: true }

state_path: stateファイルのパス

  • stateファイルはサーバの状態の情報
  • pumactlコマンドでpumaを操作するのに利用する
state_path '/u/apps/lolcat/tmp/pids/puma.state'
state_path "#{Dir.pwd}/tmp/pids/puma.state" # Railsの場合、tmp/pids/puma.stateかな

directory: 起動ディレクトリ

  • defalut: カレントディレクトリ
directory '/u/apps/lolcat'

on_worker_shutdown: 各ワーカーのshutdown前の処理

on_worker_shutdown do
  puts 'On worker shutdown...'
end

tag: プロセスリストでの追加情報

  • tagを指定しない場合は、推測する
  • tagを追加したくない場合は、空文字を指定する
tag 'app name'

worker_timeout: 全てのワーカーがマスタープロセスにチェックインする、タイムアウト時間

  • タイムアウトしたら、workerはリスタートされる
  • デフォルト: 60秒
worker_timeout 60

worker_boot_timeout: ワーカーのブートのタイムアウト時間

  • デフォルト: worker_timeoutの値
worker_boot_timeout 60

lowlevel_error_handler{}: アプリ外の例外のエラーハンドリング

  • デフォルト: 500とエラーテキストを返す
lowlevel_error_handler do |e|
  Rollbar.critical(e)
  [500, {}, ["An error has occurred, and engineers have been informed. Please reload the page. If you continue to have problems, contact support@example.com\n"]]
end

app: Rackアプリ

  • config自体がRackアプリになる
app do |env|
  puts env

  body = 'Hello, World!'

  [200, { 'Content-Type' => 'text/plain', 'Content-Length' => body.length.to_s }, [body]]
end

rackup: アプリ起動ファイルのパス

  • デフォルト: "config.ru"
rackup '/u/apps/lolcat/config.ru'

quiet: リクエストロギングをdisable

  • デフォルト: false
quiet

log_requests: リクエストロギングをenable

restart_command: pumaの再起動に使用するコマンド

restart_command '/u/app/lolcat/bin/restart_puma'

load: 追加のconfigファイルをロード

on_restart{}: リスタート前の処理

  • 例: ログファイルを閉じる、DBコネクションを閉じる、Redisコネクションを閉じる
on_restart do
  puts 'On restart...'
end

persistent_timeout: persistent connectionsのタイムアウト

first_data_timeout: 受信無しでtcpソケットを開き続ける際のタイムアウト

tcp_mode!: pumaをTCPモードで起動

queue_requests: リクエストをキューする

shutdown_debug: shutdown時にバックトレースを出力

debug: デバグ情報を出力

early_hints: Early Hintsのサポートを有効にする

他にも色々

プロセス管理

シグナル

  • masterプロセスにシグナルを送ることで、pumaの停止/再起動等が可能
  • pumactlコマンドがいい感じにラップしてくれてるので、そっちを使うのが良さそう

シグナル一覧

INT: 停止

  • Ctrl+C

QUIT: 停止

TERM: 停止

USR2: 再起動

  • 設定ファイルをリロードする

USR1: 再起動(Phased Restart)

  • 設定ファイルをリロードしない

TTIN: ワーカー1増やす

TTOU: ワーカー1減らす

HUP: ログファイルをリオープン

  • ログファイルはstdout_redirectの設定を見る
  • stdout_redirectがなければINTのようにふるまう

pumaコマンド

  • pumaコマンドのオプションは設定ファイルに対応する項目がある。詳細については 設定項目 を参照
  • ただし設定ファイルとは設定方法が微妙に違う項目もあるので注意

オプション

-C, --config PATH: 設定ファイル読み込み(loadに対応)

# デフォルト値(config/puma.rb)
$ puma

# 指定
$ puma -C config/puma.rb

# ファイルを指定したくない場合(デフォルト値が使われるのを防ぐ)
$ puma -C "-"

-b, --bind URI: バインド(bindに対応)

# TCPソケットを使う場合
$ puma -b tcp://127.0.0.1:9292

# UNIXソケットを使う場合
# TCPより若干パフォーマンスが上がる(場合がある)
$ puma -b unix:///var/run/puma.sock

# UNIXソケットのパーミッションを変更する必要がある場合、umaskパラメーターを利用する
$ puma -b 'unix:///var/run/puma.sock?umask=0111'

# SSLを利用する場合
$ puma -b 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert'

-t, --threads INT: スレッド数(threadsに対応)

$ puma -t 8:32

-w, --workers COUNT: workers数(workersに対応)

$ puma -w 3

-d, --daemon: デーモン化(daemonizeとquietに対応)

-e, --environment ENVIRONMENT: 環境(environmentに対応)

-p, --port PORT: bind(portに対応)

-q, --quiet: リクエストロギングをdisable(quietに対応)

-v, --log-requests: リクエストロギングをenable(log_requestsに対応)

-R, --restart-cmd CMD: pumaの再起動に使用するコマンド(restart_commandに対応)

-S, --state PATH:stateファイルのパス(state_pathに対応)

--tcp-mode: TCPモード(tcp_mode!に対応)

--early-hints: Early Hintsのサポートを有効にする(early_hintsに対応)

--debug: デバグ情報を出力(debugに対応)

--dir DIR: directory: 起動時ディレクトリ(directoryに対応)

--pidfile PATH: PIDファイルパス(pidfileに対応)

--preload: プリロード(preload_app!に対応)

--prune-bundler: bundler切り替え(prune_bundlerに対応)

--tag NAME: プロセスリストでの追加情報(tagに対応)

--redirect-stdout FILE: 標準出力のリダイレクト先ファイル(stdout_redirectに対応)

--redirect-stderr FILE, 標準エラー出力のリダイレクト先ファイル(stdout_redirectに対応)

--[no-]redirect-append: 追記モード(stdout_redirectに対応)

--control-url URL: コントロールサーバのurl(activate_control_appに対応)

# pumaの場合
$ puma --control-url tcp://127.0.0.1:9293 --control-token foo

# pumactlの場合
$ pumactl --control-url 'tcp://127.0.0.1:9293' --control-token foo restart

--control URL: --control-urlと同じ(activate_control_appに対応)

--control-token TOKEN: コントロールサーバの認証用トークン(activate_control_appに対応)

-I, --include PATH: $LOAD_PATHに追加

-V, --version: バージョン

-h --help: ヘルプ

pumactlコマンド

pumactl

  • コントロールサーバを使ってpumaのプロセス管理を行うコマンド
  • コントロールサーバのurlが指定されている場合は、HTTPリクエストを使う。urlが指定されていない場合は、シグナルを使う。
  • url指定は、設定ならactivate_control_app、オプションなら--control-url
  • ctlはcontrolの略なんだね
  • pumactlのメリット
    • pumaのプロセス管理はpumaコマンド(起動/状態確認など)、シグナル(停止/再起動など)、PID/stateファイル管理などで色々面倒だった。pumactlコマンドでプロセス管理の統一的なインタフェースを用意したってことらしい。(参考: http://ruby-journal.com/digesting-pumactl/)
  • 参考: https://github.com/puma/puma/blob/master/lib/puma/control_cli.rb

コントロールサーバ

  • HTTPリクエスト受け付けて、pumaの再起動などを行うRackアプリのサーバ
  • HTTPリクエストを送るにはpumactlコマンドを使う
  • tokenを使えば簡易的な認証が可能
  • 使い方
    • 設定ファイルならactivate_control_app
    • pumaコマンドなら--control-url
  • 参考: https://github.com/puma/puma/blob/master/lib/puma/app/status.rb
# puma + コントロールサーバ 起動
$ puma --control-url tcp://127.0.0.1:9293 --control-token foo

# HTTPリクエストでpuma再起動
$ pumactl --control-url 'tcp://127.0.0.1:9293' --control-token foo restart

コマンド

start: 起動

$ pumactl start

stop: 停止(TERM)

$ pumactl stop

halt: 停止(QUIT)

# $ kill -QUIT `(cat tmp/pids/server.pid)` 相当
$ pumactl halt

restart: 再起動(USR2)

$ pumactl restart

phased-restart: 再起動(USR1)

  • phased-restart
$ pumactl phased-restart

status: PID確認

$ pumactl status

# 起動している場合
PID 2557 is running

# 起動してない場合
No puma process

stats: worker等の情報

gc: ガベージコレクション開始

gc-stats: ガベージコレクションの情報

reload-worker-directory: ?

オプション

-S, --state PATH: stateファイルのパス

-F, --config-file PATH: 設定ファイルのパス

-P, --pidfile PATH: pidファイルのパス

-p, --pid PID: pid

-C, --control-url URL: control serverのurl

-T, --control-token TOKEN: control serverの認証トークン

-H, --help: ヘルプ表示

-V, --version: バージョン表示

-Q, --quiet: 表示を止める

railsコマンド

起動

$ rails s
$ rails s Puma

結局どうすれば?

  • 設定は全て設定ファイルに書いて、pumactlコマンド使うのが簡単そう。

その他メモ

2つのモード

Single mode: プロセスは1つだけ

  • もともとはpumaはSingle modeのみでスレッド専用として開発された

Clustered mode: masterプロセス1つ + workerプロセス複数

  • master-workerモデル
  • 設定でworkersを指定するとこっちになる
  • 本番環境ではClustered modeで使うべき

2つのリスタート

参考

Hot Restart: リスタート時に、サーバーのソケットを開きっぱなしにする

  • 処理が完了するのを待ってから再起動する
  • unicornとかのホットデプロイとは違うっぽい(ダウンタイムなしという意味ではPhased Restartが近い?)

メリット

  • リクエストの取りこぼしがなくなる
  • preloadと併用できる

デメリット

  • ダウンタイムあり(リスタートが完了するまで、リクエスト処理は止まる)

使い方

  • pumactl restart
  • USR2シグナル

Phased Restart: 1つずつworkerを再起動する

  • ワーカーを1つずつ再起動するので、どこかのワーカーがリクエスト処理をしてくれる

メリット

  • ダウンタイムなし(常にどこかのworkerが生きているので、リクエスト処理が止まらない)

デメリット

  • Clustered mode(復数worker)のみ
  • preloadは使えない(workerを1つずつkillして、1つずつ再起動するため)
  • DBスキーマは新しいのに、アプリコードは古いという自体になりうる(新しいコードと古いコードが共存するので)。なのでマイグレーションをするような環境ではHOT Restartを利用すべき。あるいは古いバージョンのアプリコードと互換性がないといけない。

使い方

  • pumactl phased-restart
  • USR1シグナル

プラグイン

  • Pumaに機能を追加できる
  • Puma3.0から導入

使い方

# Gemfile
gem 'puma-heroku' # プラグイン
$ bundle install
# config/puma.rb
plugin :heroku

有名プラグイン

tmp_restart: tmp/restart.txtをtouchするとリスタートする

heroku: heroku向けの設定を用意してくれる

自分で実装

  • configやstart等のフックメソッドをオーバーライドすれば実装できるっぽい
  • 上の2つのプラグインを参考にする

worker数、thread数の目安

worker数の目安

  • CPUの観点
    • とりあえずworker数 = CPUコア数。実際にはさらに最適化すべき。コア数以上にしたほうが良い場合もある。CPUコア数の1.5倍まで増やしてもいいかも
    • cpu使用率70%くらいが目安
  • メモリの観点
    • worker数 = RAM / (1プロセスのメモリ使用量 * 1.2) # Railsアプリだと1プロセス200MB~400MB程度が基準
    • メモリ使用量70%くらいが目安
  • ロードバランシングの観点
    • 最適なロードバランシングのためにはworker数は3以上

thread数の目安

  • thread数決めるのは難しい。5程度にして後は忘れるのがいいという意見も。
  • デフォは16。これはそこそこ妥当らしい。
  • ちなみにMRIの場合はIOだけ並列化可能。これはだいたい総時間の10~25%程度らしい
  • Unicornから移行する場合
    • workerをunicornの半分にする + thread数を2にする -> これでメモリ使用量が50%になる
    • スレッドに慣れてきたら、workerを減らしてthreadを増やして調整すると良い

puma + Systemd

puma + Nginx

puma + heroku

Rails5からRailsのデフォルト

  • Rails5でActionCableの導入に伴い、development環境のアプリケーションサーバがWebrickからpumaへ変更

Mongrelから派生

  • pumaはMongrelから派生した
  • 改善点
    • Rackアプリにした
    • スレッドベースにした

プラットフォームによる成約

JRuby, Windows

restart時にソケットを必ず閉じる

ディスクリプタを受けわたせないため

cluster modeがない

fork(2)がないため

Windows

daemon modeがない

fork(2)がないため

puma関係のgem

puma_worker_killer: 定期的にworkerをkillするgem

  • workerを長時間放置しておくと、メモリ使用量が徐々に増えてきて、サーバ全体の処理が遅くなる可能性がある。 -> puma_worker_killerを使い、定期的にworkerをkillして新しいworkerを立ち上げる
  • Ruby Webアプリのプロセスは時間とともにメモリ使用量が増加する。生成後の2倍から3倍に達することもある。
  • unicorn_worker_killerのpuma版
  • 当然cluster modeでしか使えない

導入

1. インストール

# Gemfile
gem 'puma_worker_killer'
$ bundle install

2. 設定

# config/puma.rb
before_fork do
  PumaWorkerKiller.config do |config|
    # サーバのメモリ(1024MB)
    config.ram           = 1024

    # 確認頻度(5秒毎)
    config.frequency     = 5

    # workerを再起動する閾値(メモリ使用量が65%になったらkill)
    # 一番メモリ使用量の多いworkerを再起動する
    config.percent_usage = 0.65

    # rolling_restartの頻度(12時間に1回)
    # rolling_restart: メモリ使用量に関係なく、順番にworkerを再起動する仕組み
    config.rolling_restart_frequency = 12 * 3600

    # falseにすると監視ログを止める
    # 普通のログに混ざって紛らわしい
    config.reaper_status_logs = true

  end
  PumaWorkerKiller.start
end

puma-dev: powのpuma版

  • powのpuma版。powと同等の機能が利用できる
  • 開発時のサーバとして利用すると便利

対応OS

  • OS X
  • Linux

powの知識

pros

  • シンボリックリンクを貼るだけでバーチャルホストで切って開発できる
  • "rails s"で起動することなく、アクセスすると自動で起動する
  • 同一LAN内からアクセス可能
  • 設定が不要(Zero-configuration)

cons

  • もうメンテされていない
  • 起動が遅い
  • フォアグラウンドじゃないのでbinding.pryできない(pry-remoteやプロキシ使えばいける)

使い方

# ローカルからアクセス
http://[project名].dev/

# 同一LAN内からアクセス
http://[project名].[LANのIP-ADDRESS].xip.io

xip.io: IPアドレスをサブドメインに与えることでIPアドレス自身を返す、グローバルなDNS

  • 37signalsがpowのために作ったらしい
  • puma-devもxip.ioを利用できる
ワイルドカードDNS
  • IPアドレスをサブドメインに与えることで、IPアドレス自身を返す、グローバルなDNS
  • 例: "192.168.100.200.wild.card" は "192.168.100.200" を返す

powよりpuma-devを使うべき

  • powがメンテされていない
  • https対応
  • WebSocket対応
  • powder(pow用のコマンドツール)相当の機能が付属している
  • MacとLinuxをサポート

導入(mac)

0. powをインストール済みの場合は、アンインストールする

  • 色々問題があるっぽい
$ curl get.pow.cx/uninstall.sh | sh

1. brewでインストール

  • gemでも可能
$ brew install puma/puma/puma-dev

2. DNS設定

  • resolverを使い、ローカルのMacにpuma-dev用のDNSサーバ設定を追加
$ sudo puma-dev -setup

3. セットアップ

  • ".dev"ではなく".test"にする
$ puma-dev -install -d test

4. シンボリックリンクを貼る

# puma-devコマンドを使う場合
$ cd my_app
$ puma-dev link -n my_app

# 自分でシンボリックリンク貼ってもokらしい
$ cd ~/.puma-dev/
$ ln -s my_app

5. リスタート

touch tmp/restart.txt

デフォルトの設定

port: 80と443

domain: .test

  • 昔は.devドメインだったが、2017年にGoogleが所有してからHSTS onlyになってしまったため、.testに変わった
  • ChromeのVer.63から、.devにはHTTPSが必須

コマンド

# puma-devコマンドを使う場合
$ cd my_app
$ puma-dev link -n my_app

# 自分でシンボリックリンク貼ってもokらしい
$ cd ~/.puma-dev/
$ ln -s my_app

touch tmp/restart.txt: アプリ再起動

puma-dev -stop: 全アプリを再起動

  • puma-devにUSR1シグナルを送っている
# これと同じ
$ pkill -USR1 puma-dev

puma-dev: 起動(フォアグラウンド)

  • ~/.puma-devを使う

puma-dev -h: ヘルプ

sudo puma-dev -setup: 設定(macのみ)

puma-dev -pow: ~/.powを使う

  • By default, puma-dev uses the domain .test to manage your apps. If you want to have puma-dev look for apps in ~/.pow, just run puma-dev -pow.

環境変数

環境変数一覧

CONFIG: pumaの設定ファイルのパス
  • デフォルト: なし
  • config/puma-dev.rbとかを指定する
THREADS: pumaのスレッド数
  • デフォルト: 5
WORKERS: pumaのworker数
  • デフォルト: 0

環境変数の読み込み順(上から順)

  • ~/.powconfig
  • .env
  • .powrc
  • .powenv

シンボリックリンク

  • "~/.puma-dev/"配下にサブディレクトリを置けば、使える
  • cool-frontend.testの場合、以下の2つを探す
    • ~/.puma-dev/cool-frontend
    • ~/.puma-dev/cool/frontend

HTTPS

  • デフォルトでport443を使う
  • 自動でオレオレ証明書を作ってくれるっぽい: "~/Library/Application Support/io.puma.dev/cert.pem."

ログ

  • ログのパス: ~/Library/Logs/puma-dev.log