2026年8月24日

2026年8月24日

Capistranoを使ったRailsのデプロイ自動化|設定からロールバックまで

Capistrano を使うと、Rails アプリのデプロイ作業(コードの取得、gem のインストール、アセットのビルド、マイグレーション、アプリの再起動)を cap production deploy の1コマンドにまとめ、失敗したときも1つ前のリリースへすぐ戻せるようになります。この記事では、Capistrano 3 系の導入、設定ファイルの書き方、サーバー側の準備、初回デプロイで詰まりやすい点、ロールバックの注意点までを順に説明します。

Capistrano の仕組み

Capistrano は手元のPC(またはCI)から SSH でサーバーに接続し、決められた順番でコマンドを実行する Ruby 製のツールです。サーバー上には次のようなディレクトリが作られます。

/var/www/myapp/
├── current -> releases/20261018093000   # 公開中のリリースへのシンボリックリンク
├── releases/
│   ├── 20261017120000/
│   └── 20261018093000/
├── shared/                              # リリースをまたいで共有するファイル
│   ├── config/master.key
│   ├── log/
│   └── storage/
└── repo/                                # Git リポジトリのキャッシュ

デプロイのたびに releases/ の下に新しいディレクトリが作られ、準備がすべて終わった最後に current のリンクが切り替わります。準備の途中で失敗しても公開中のリリースには影響せず、ロールバックはリンクを1つ前に戻すだけで済みます。これが手作業の git pull と比べた最大の利点です。

なお、Rails 8 では新規アプリに Kamal(コンテナでデプロイするツール)の設定が標準で含まれるようになりました。コンテナを使わず、Puma を systemd で動かす従来型のサーバー構成なら、Capistrano は今も素直な選択肢です。

前提となるサーバー環境

Capistrano はサーバーの構築まではしません。デプロイ前に、次の準備が済んでいる必要があります。

  • デプロイ用のユーザー(例: deploy)と、手元からの SSH 鍵認証
  • rbenv などで入れた Ruby と bundler
  • データベース(PostgreSQL や MySQL)と、アプリ用のユーザー
  • Puma を起動する systemd のユニットと、前段の Nginx
  • サーバーから Git リポジトリを読めること(読み取り専用のデプロイキーを推奨)

サーバーの初期構築を自動化したい場合は、Ansible などの構成管理ツールと組み合わせると、Capistrano はデプロイだけに集中できます。

Capistrano をインストールする

Gemfile の development グループに追加します。

group :development do
  gem "capistrano", require: false
  gem "capistrano-rails", require: false
  gem "capistrano-rbenv", require: false
  gem "capistrano-bundler", require: false
end
bundle install
bundle exec cap install

cap install で Capfile、config/deploy.rb、config/deploy/production.rb、config/deploy/staging.rb などが作られます。config/deploy.rb の先頭にある lock の行は、インストールした Capistrano のバージョンに合わせて生成されるので、そのまま残してください。チームで版がずれると動作が変わることを防ぐための行です。

Capfile で使う機能を読み込む

# Capfile
require "capistrano/setup"
require "capistrano/deploy"

require "capistrano/scm/git"
install_plugin Capistrano::SCM::Git

require "capistrano/rbenv"
require "capistrano/bundler"
require "capistrano/rails/assets"
require "capistrano/rails/migrations"

Dir.glob("lib/capistrano/tasks/*.rake").each { |r| import r }

capistrano/rails/assets はデプロイ時に assets:precompile を、capistrano/rails/migrations は db:migrate を実行します。アセットのビルドに Node.js や Yarn が必要な構成(jsbundling-rails など)では、サーバー側にもそれらを入れておく必要があります。

deploy.rb に共通設定を書く

# config/deploy.rb(lock の行は cap install が生成したものを残す)
set :application, "myapp"
set :repo_url, "git@github.com:your-org/myapp.git"
set :branch, ENV.fetch("BRANCH", "main")
set :deploy_to, "/var/www/myapp"

set :rbenv_type, :user
set :rbenv_ruby, File.read(".ruby-version").strip

# リリースをまたいで共有するファイルとディレクトリ
append :linked_files, "config/master.key"
append :linked_dirs, "log", "tmp/pids", "tmp/cache", "tmp/sockets", "public/system", "storage"

set :keep_releases, 5

linked_files と linked_dirs は、shared/ の下の実体を各リリースにシンボリックリンクで見せる設定です。config/master.key のように Git に入れないファイルや、アップロードされた画像(Active Storage のローカル保存先 storage など)をここに入れておかないと、デプロイのたびに消えてしまいます。

production.rb にサーバーを書く

# config/deploy/production.rb
server "203.0.113.10", user: "deploy", roles: %w[app db web]

roles は、どのサーバーでどの処理を行うかの区分です。マイグレーションは db ロールを持つサーバーで実行されます。サーバーが複数台ある場合でも、db ロールは1台に絞ってください。

アプリの再起動タスクを追加する

Puma の再起動は構成によって方法が違うため、ここでは systemd のサービスを再起動するタスクを自分で書く例を示します。

# lib/capistrano/tasks/puma.rake
namespace :deploy do
  desc "Restart Puma via systemd"
  task :restart do
    on roles(:app) do
      execute :sudo, :systemctl, :restart, "puma-myapp"
    end
  end
end

after "deploy:publishing", "deploy:restart"

deploy ユーザーにパスワードなしの sudo を広く与えるのは避け、このコマンドだけを許可します。visudo で編集し、文法エラーで sudo 自体が使えなくなる事故を防いでください。

# /etc/sudoers.d/deploy(visudo -f /etc/sudoers.d/deploy で編集)
deploy ALL=(root) NOPASSWD: /usr/bin/systemctl restart puma-myapp

Puma の再起動を gem(capistrano3-puma など)に任せる方法もあります。gem のメジャーバージョンによって設定方法が大きく変わっているので、使う場合はその版の README に沿って設定してください(2026年10月現在)。

初回デプロイの前に check を通す

いきなり deploy せず、まず必要なディレクトリの作成と前提条件の確認を行います。

bundle exec cap production deploy:check

初回は多くの場合、linked_files のファイルが無いというエラーで止まります。shared/config/master.key をサーバーに手動で置いてから、もう一度実行してください。このファイルは権限を 600 にし、デプロイユーザー以外が読めないようにします。

# サーバー側で
mkdir -p /var/www/myapp/shared/config
chmod 700 /var/www/myapp/shared/config
# master.key を安全な経路でコピーしたあと
chmod 600 /var/www/myapp/shared/config/master.key

check が通ったらデプロイします。

bundle exec cap production deploy

失敗したときの見方

Capistrano は失敗したコマンドとその出力を表示して止まります。よくある原因は次のとおりです。

  1. Git の取得に失敗する:サーバーからリポジトリへの SSH 接続を、デプロイユーザーで ssh -T git@github.com のように試す
  2. bundle install で失敗する:ネイティブ拡張のビルドに必要なライブラリ(データベースのクライアントライブラリなど)がサーバーに無い
  3. assets:precompile で失敗する:Node.js や Yarn が無い、またはメモリ不足。小さいVPSではスワップの追加も検討する
  4. db:migrate で失敗する:config/database.yml や環境変数の接続情報、データベースユーザーの権限を確認する

再実行の前に、詳しいログを見たい場合はサーバーの shared/log/ と、systemd のジャーナル(journalctl -u puma-myapp)も確認します。

ロールバックの注意点

直前のリリースに戻すには次を実行します。

bundle exec cap production deploy:rollback

ここで注意したいのは、ロールバックで戻るのはコードだけで、データベースのマイグレーションは戻らないことです。カラムの削除や名前の変更を含むマイグレーションの後にコードだけを戻すと、古いコードが新しいテーブル構造で動けずエラーになります。

これを避けるには、マイグレーションを「古いコードでも新しいコードでも動く」形に分けて出すのが有効です。たとえばカラムの削除は、まずコードから参照を外してデプロイし、次のリリースで削除する、という2段階にします。本番データベースに影響するリリースの前には、バックアップを取っておいてください。

まとめ

  • Capistrano は releases/ に新しいリリースを用意し、最後に current を切り替えるため、途中で失敗しても公開中のサイトは止まらない
  • linked_files / linked_dirs で master.key やアップロードファイルをリリースをまたいで共有する
  • 再起動は systemd を呼ぶタスクを書き、sudo は必要なコマンドだけ許可する
  • 初回は deploy:check を通してからデプロイする
  • ロールバックはコードだけが戻るので、マイグレーションは段階的に出す

お気軽にご相談ください

お見積りへ お問い合わせへ
▲