🔥

railsアプリをEC2とRDS(PostgreSQL)でデプロイする

に公開

はじめに

以前、todoアプリ開発の備忘録でRailsアプリを作成しました。今回は、EC2とRDSを使いこのアプリをAWS上にデプロイしてみようと思います。
このアプリをEC2上で動かし、ブラウザで表示できるようにすることを、本記事のゴールとしたいと思います。

todoアプリ開発の備忘録の状態から見た目や機能面にいくつか手を加えています。

画像はローカルで開発したアプリの画面

1.EC2インスタンスの起動

以下の内容でEC2インスタンスを起動。

  • 名前:application_server
  • OSイメージ:AmazonLinux
  • AMI:AmazozLinux2023 AMI 64ビット(x86)
  • インスタンスタイプ:t2.micro
  • キーペア:新規に作成
  • ネットワーク(VPCを新規に作成)
    • サブネット:public1-ap-northeast-1a
    • パブリックIPの自動割り当て:有効化(インターネットから接続可能にする)
    • セキュリティグループ
      • セキュリティグループ名:task_app_security_group
      • インバウンドグループ(構築中は自PCからの接続のみ許可する)
        • タイプ:すべてのトラフィック
        • ソース:マイIP
  • ストレージ:30GB(gp3)

EC2の起動が完了。

2.EC2インスタンスにssh接続する

EC2インスタンスにssh接続する。

% ssh -i "app_key.pem" ec2-user@ec2-<ec2-ipaddress>.ap-northeast-1.compute.amazonaws.com

※EC2 Instance Connectで直接CLIを開いてもいい

3.ユーザーの作成

EC2インスタンスを起動するとec2-userというユーザーがデフォルトで作成される。デフォルトのため不正攻撃の標的になる可能性もあるので、別のユーザーを作成しec2-userは削除する事を推奨。今回はrailsというユーザーを作成しec2-userは削除する。

% sudo useradd rails
% sudo passwd rails
Changing password for user rails.
New password: 
BAD PASSWORD: The password fails the dictionary check - it is based on a dictionary word
Retype new password: 
passwd: all authentication tokens updated successfully.

キーペアの公開鍵をrailsにコピー。
鍵ファイルの所有者やグループをrailsに変更。

% sudo mkdir /home/rails/.ssh
% sudo cp -a ~/.ssh/authorized_keys /home/rails/.ssh
% sudo chown rails /home/rails/.ssh
% sudo chgrp rails /home/rails/.ssh/authorized_keys

ec2-userを削除する。

% sudo usermod -aG wheel rails
% sudo userdel -r ec2-user
[sudo] password for rails: 

以降はrailsユーザーで作業していく。

4.環境のセットアップ

ec2にrailsアプリが動く環境を整えていく。
インストールするバージョン以下の通り。
ruby:3.4.4
Rails:8.0.2

rbenvのインストール

まずrubyのパッケージ管理ツールであるrbenvをインストールする。

  • githubからインストール
  • 併せてruby-buildもgitからインストールしておく
% sudo dnf -y install git

% git clone https://github.com/sstephenson/rbenv.git ~/.rbenv
Cloning into '/home/rails/.rbenv'...
remote: Enumerating objects: 3395, done.
remote: Counting objects: 100% (289/289), done.
remote: Compressing objects: 100% (123/123), done.
remote: Total 3395 (delta 228), reused 166 (delta 166), pack-reused 3106 (from 4)
Receiving objects: 100% (3395/3395), 723.62 KiB | 3.91 MiB/s, done.
Resolving deltas: 100% (2086/2086), done.

% echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
% echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
% source .bash_profile

% git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
Cloning into '/home/rails/.rbenv/plugins/ruby-build'...
remote: Enumerating objects: 17031, done.
remote: Counting objects: 100% (4204/4204), done.
remote: Compressing objects: 100% (337/337), done.
remote: Total 17031 (delta 4055), reused 3893 (delta 3863), pack-reused 12827 (from 3)
Receiving objects: 100% (17031/17031), 3.37 MiB | 14.51 MiB/s, done.
Resolving deltas: 100% (12021/12021), done.

rbenvのバージョンが表示されればOK。

% rbenv -v
rbenv 1.3.2-6-g0f65ff7

rubyのインストール

続いてrbenvコマンドを使用してrubyをインストール。

  • rubyインストールに必要なパッケージをdnfコマンドでインストール
  • 容量の関係でruby保存先にTMPDIR="${PWD}/tmp"を指定
  • rubyのインストールには時間がかかる(今回は10分くらい)
  • rubyのデフォルトバージョン3.4.4に設定
% sudo dnf groupinstall "Development Tools"
% sudo dnf install -y \
  gcc \
  bzip2 \
  bzip2-devel \
  readline-devel \
  zlib-devel \
  libffi-devel \
  openssl-devel \
  make \
  autoconf \
  automake \
  libyaml-devel \
  libedit-devel \
  sqlite-devel \
  git \
  curl \
  patch \
% TMPDIR="${PWD}/tmp" rbenv install 3.4.4

rubyのバージョンが表示されればOK。

% rbenv global 3.4.4
% ruby -v
ruby 3.4.4 (2025-05-14 revision a38531fd3f) +PRISM [x86_64-linux]

railsのインストール

そしてrailsをインストール。

  • Railsアプリの依存関係を管理するのにbundlerが必要
% gem install bundler
Fetching bundler-2.6.9.gem
Successfully installed bundler-2.6.9
1 gem installed

A new release of RubyGems is available: 3.6.7 → 3.6.9!
Run `gem update --system 3.6.9` to update your installation.

% gem install rails

railsのバージョンが表示されればOK。

% rails -v
Rails 8.0.2

5.RDS(PostgreSQL)を作成

以下の内容でデータベースを作成。

  • データベース:PostgreSQL
  • エンジンバージョン:17.4-R1
  • テンプレート:無料利用枠
  • 可用性と耐久性:シングルAZ DBインスタンスデプロイ
  • DBインスタンス識別子:todo-database
  • マスターユーザ名:postgres
  • 認証情報の設定:セルフマネージド
  • パスワード:自動生成
  • インスタンス:db.t4g.micro
  • ストレージ:汎用SSD(20GiB)
  • 接続:EC2(application-server)に接続する
  • ネットワークタイプ:IPv4
  • DB サブネットグループ:自動セットアップ
  • パブリックアクセス:なし
  • VPCセキュリティグループ:既存の設定
  • データベース認証:パスワード認証
  • モニタリング:スタンダート
  • Performance Insights:無効化

postgreSQLユーザーのパスワードを自動生成した場合、データベース作成時のポップアップをクリックする事で確認可能。この「認証情報の詳細の表示」は後で再確認できず、このタイミングでパスワードを控えておく必要があるので要注意

rdsが作成された。

6.ローカル環境からEC2にデプロイ

ローカルで作成したアプリケーションをscpコマンドでEC2にコピーする。

scp -i ~/.ssh/app_key.pem -r <ローカルAPPのパス> rails@<EC2のIPアドレス>:/home/rails/

7.データベースの作成

続いてEC2からRDSに接続できることを確認していく。
config/database.ymlのproductionセクションの記述を変更。
また、config/database.ymlでは、hostとportは任意項目となっているが、RDSなどの外部DBに接続する場合は明示的に指定する必要がある。

database.yml
production:
  primary: &primary_production
    <<: *default
    database: todo_database # ← RDSで作成したDB名にする
    username: postgres      # ← RDSのユーザー名
    password: <%= ENV["TODO_DATABASE_PASSWORD"] %> # ← .envに環境変数を設定
    host: <エンドポイント>.rds.amazonaws.com  # ← RDSのエンドポイント
    port: 5432

.envにtodo_databaseのユーザーパスワードを追記する。

% echo "TODO_DATABASE_PASSWORD=<ユーザーのパスワード>" >> .env

さらにRDSへの接続確認を行う。EC2からpsqlコマンドを使用してRDSにpostgresでログインできるかを確認する。
まずpostgresqlをインストール(psqlコマンドを使用するため)

% sudo dnf -y install postgresql17.x86_64

postgresqlにログインできればOK。

% psql -h <RDSエンドポイント> -U postgres -d postgres
Password for user postgres: 
psql (17.5, server 17.4)
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, compression: off, ALPN: postgresql)
Type "help" for help.

postgres=> 

作成したRDS(todo-database)内にデータベースを作成していく。

% psql -h <RDSエンドポイント> -U postgres -d postgres
Password for user postgres: 
psql (17.5, server 17.4)
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, compression: off, ALPN: postgresql)
Type "help" for help.

postgres=> CREATE DATABASE todo_production;
CREATE DATABASE

bundle installを行った後、pg_configが存在すればOK。
これによりpg gem のインストールが通るようになり、「bundle install」 → 「RAILS_ENV=production rails db:migrate」 の流れが実行できるようになる。

% sudo dnf -y install postgresql-devel
% bundle install
% which pg_config
/usr/bin/pg_config

shellの環境変数にRDSのパスワードを登録。

% export TODO_DATABASE_PASSWORD='ユーザーのパスワード'

本番環境用のデータベースの初期化処理。
※rails db:prepareはdb:createとdb:migrateを同時に実行するコマンド

% RAILS_ENV=production bundle exec rails db:prepare
Created database 'todo-database-1'
Created database 'todo_production_cache'
Created database 'todo_production_queue'
Created database 'todo_production_cable'

8.サーバーを公開

必要な設定が済んだため、インターネット上にアプリを公開する。
※ローカル開発では単純に「rails s」でサーバーを起動できるが、本番用は以下のコマンドで行う。

RAILS_ENV=production bundle exec rails s -b 0.0.0.0
/home/rails/todo/Gemfile:45: warning: key :require is duplicated and overwritten on line 45
/home/rails/todo/Gemfile:45: warning: key :require is duplicated and overwritten on line 45
=> Booting Puma
=> Rails 8.0.2 application starting in production 
=> Run `bin/rails server --help` for more startup options
Puma starting in single mode...
* Puma version: 6.6.0 ("Return to Forever")
* Ruby version: ruby 3.4.4 (2025-05-14 revision a38531fd3f) +PRISM [x86_64-linux]
*  Min threads: 3
*  Max threads: 3
*  Environment: production
*          PID: 176088
* Listening on http://0.0.0.0:3000

http://<EC2のIPアドレス>:3000/tasksに接続する。

ブラウザで確認できた。

さいごに

EC2上にデプロイが完了し、インターネットに無事公開する事ができました。
特に難しいと感じたのは、RDS上でデータベースを構築した後のEC2との接続手順でしょうか。あまり慣れない作業のため、かなり苦労しました。
今後はAWSの冗長化やRoute53のDNS設定などにもトライしていきたいと思います。

Discussion