はじめに
Amazon EC2は良いけど高いので、Railsアプリを動かすのに安いVPSを探していたところ、VultrというVPSを見つけました。月額3.50ドルから、と格安で使えますし、東京リージョン(こちらは月額$5から)もあります。
激安VPSのVultrで紹介者からのリンク経由でアカウント登録すると$100のクレジットをもらえるので、早速作ってみました。このキャンペーンはいつ終わるか分からないので、興味のある方は以下のリンクからアカウント登録してください。あなたはクレジットをもらえるし、私にも多少のクレジットが入るらしいので、Win-Winです。
このリンクで$100もらえます
私もリファラー経由でアカウントを作ったので$100もらえました。これで最初にあれやこれや試すのは無料でできます。
使った環境
サーバOS: CentOS7 (Kernel 3.10.0-1062.12.1.el7.x86_64)
ローカルOS: macOS Catalina Version 10.15.3
Ruby 2.5.3 on rbenv
Rails 6.0.2.1
puma 4.3.3
bundler 2.1.2
Capistrano 3.12.0
MySQL 5.7.29
1. Vultr VPSインスタンス作成
(1)Products→Instances→+でインスタンス追加画面を出します。
(2)VPSをメニューから選びます。
今回は一番安い$3.50のプランにしたかったのでアメリカ New YorkをLocationに選びました。
(3)OSは情報を検索しやすいCentOS7にしました。
(4)IP V6はたぶん使わないのですが、無料なので選んでおきました。
(5)Start UpスクリプトにはGitHubのSSH公開鍵を読み込むスクリプトを仕込みました。これは後でCapistranoでデプロイする時にGitHubからコードを持って来るのに必要となります。
(6)SSH公開鍵を仕込んでおくと後で楽です。
(7)SSH鍵の作り方
暗号強度の強いed25519
で作りました。以下はMacの例です。
$ ssh-keygen -t ed25519 -N "" -f ~/.ssh/vultr -C あなたのメルアド
Generating public/private ed25519 key pair.
Your identification has been saved in /Users/あなた/.ssh/vultr.
Your public key has been saved in /Users/あなた/.ssh/vultr.pub.
念の為、ssh-addしておきます。
$ ssh-add
Identity added: /Users/あなた/.ssh/id_rsa (/Users/あなた/.ssh/id_rsa)
(8)インスタンス作成
ここまで来たらDeploy Now
ポチッと押します。
インスタンスにOSインストールが終わるまで数分待ちます。
OSインストールが終わってStatus
がRunning
になればインスタンス生成は完了です。
2. ログインアカウントの作成
(1)OSインストールが終わってStatus
がRunning
になったら・・・
をクリックしてServer Details
画面を出します。
(2)画面右上のView Console
アイコンをクリックしてコンソールを出します。
(3)コンソールが出たらServer Details
画面のrootパスワードでrootログインします。
(4)後でCapistranoで使うアカウントを追加します。
# adduser deploy
# passwd deploy
# gpasswd -a deploy wheel
# mkdir /home/deploy/.ssh
# chmod 700 /home/deploy/.ssh
# vi /home/deploy/.ssh/authorized_keys
> 公開鍵を貼り付ける(Macで作った/Users/あなた/.ssh/vultr.pubの中身を貼り付けます。)
# chmod 600 /home/deploy/.ssh/authorized_keys
# chown -R deploy:deploy /home/deploy/.ssh/
(5)SSHでログインできるか確認する。
$ ssh -i ~/.ssh/vultr deploy@あなたのVPSのIPアドレス
deploy@あなたのVPSのIPアドレス's password: さっき作ったdeployアカウントのパスワード
Last login: Mon Mar 9 22:25:20 2020 from あなたのLocalマシンのFQDN
-bash: warning: setlocale: LC_CTYPE: cannot change locale (UTF-8): No such file or directory
[deploy@vultr ~]$ ログインできました。
3. SSHの基本設定
いちいちパスワードを入れるのは面倒だし、Capistranoでパスワード入力をスキップできるようにsshd構成を変更します。
(1)ローカルマシンからSSHログイン
$ ssh -i ~/.ssh/vultr deploy@あなたのVPSのIPアドレス
(2)VPSにログイン後の作業
$ sudo vi /etc/ssh/sshd_config
> 以下を変更
PermitRootLogin no # rootのリモートログインを不許可
PasswordAuthentication no # パスワード無しでSSHログイン
ClientAliveInterval 10 # SSHがタイムアウトしないように10秒毎にAlive確認
ClientAliveCountMax 6 # 上記を最大6回(つまり60秒)繰り返す
> 変更を反映
$ sudo systemctl reload sshd
(3)ローカルマシンからパスワード無しでSSHログイン
$ ssh -i ~/.ssh/vultr deploy@あなたのVPSのIPアドレス
もし、間違ってリモートからSSHできなくなってしまった時はView Console
アイコンをクリックしてコンソールを出してrootでログインし、復旧させる。
4. sudoの設定
deployユーザーにパスワードなしでsudoコマンドを実行できるように設定しました。お好みで設定しても、しなくても良いと思います。
(1)visudoコマンドでsudo権限を付与します。
$ sudo visudo
## Allow root to run any commands anywhere
root ALL=(ALL) ALL
deploy ALL=(ALL) ALL <=この行を追加
## Same thing without a password
# %wheel ALL=(ALL) NOPASSWD: ALL
%deploy ALL=(ALL) NOPASSWD: ALL <=この行を追加
deployグループのユーザーはパスワード無しでsudoできます。
[deploy@vultr ~]$ sudo whoami
root
パスワードを聞かれずにwhoami
できました。
5. Firewallの設定
$ sudo yum remove -y firewalld
$ sudo yum install -y iptables-services
$ sudo systemctl start iptables
$ sudo systemctl enable iptables
$ sudo /usr/libexec/iptables/iptables.init save
$ sudo vi /etc/sysconfig/iptables
> Web用に80と433をあける。
# Generated by iptables-save v1.4.21 on Tue Mar 10 01:44:41 2020
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [17:1954]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT <=この行を追加
-A INPUT -p tcp -m state --state NEW -m tcp --dport 443 -j ACCEPT <=この行を追加
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT
# Completed on Tue Mar 10 01:44:41 2020
> 上記の変更を反映させます。
$ sudo systemctl reload iptables
6. Swap領域の設定
今回作成したインスタンスはメモリが0.5GBと少なく、メモリを多く必要とするRailsではメモリ不足になる可能性が高いので、Swap領域を設定します。ページングが多発するとパフォーマンスが悪くなりますが、その際はVultrのプランをUpgradeすれば良いです。(ただし、一度UpgradeするとDowngradeはできません。) 今回は4GBと多めにSwap領域を確保します。
[deploy@vultr ~]$ su
Password:
[root@vultr deploy]# dd if=/dev/zero of=/swapfile bs=1M count=4096
4096+0 records in
4096+0 records out
4294967296 bytes (4.3 GB) copied, 8.98244 s, 478 MB/s
[root@vultr deploy]# mkswap /swapfile
Setting up swapspace version 1, size = 4194300 KiB
no label, UUID=5b48c0e8-9f76-4cb1-8826-1063a95e51eb
[root@vultr deploy]# swapon /swapfile
swapon: /swapfile: insecure permissions 0644, 0600 suggested.
# vi /etc/fstab
> 以下を一番下に追加
/swapfile swap swap defaults 0 0
> /etc/fstabの変更を保存したら、自動マウントされるか試すためにサーバを再起動する。
[root@vultr deploy]# reboot
再起動後、top
コマンドでSwap領域を確認。
[deploy@vultr ~]$ top
top - 01:55:14 up 0 min, 1 user, load average: 0.00, 0.00, 0.00
Tasks: 68 total, 2 running, 66 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.3 us, 0.0 sy, 0.0 ni, 99.7 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 498648 total, 351784 free, 59388 used, 87476 buff/cache
KiB Swap: 4194300 total, 4194300 free, 0 used. 417552 avail Mem
7. MySQLインストールと構成
DBはお好きなものを使えば良いと思いますが、私のローカルMacはMySQL5.7が入っているので同じバージョンを入れました。MySQL8が2倍速いという話もあり、試したのですがRails6だとmysqlクライアントを動かすのが素直に行かず、面倒臭いので5.7にしました。
(1)MySQLインストール
DefaultでMariaDBが入っているのでアンインストールしてからMySQLをインストールします。
# yum -y remove mariadb-libs
# rm -rf /var/lib/mysql/
# yum -y localinstall http://dev.mysql.com/get/mysql57-community-release-el7-8.noarch.rpm
> バージョンを確認
# yum info mysql-community-server
Failed to set locale, defaulting to C
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
* base: centos.mirror.constant.com
* extras: centos.mirror.constant.com
* updates: centos.mirror.constant.com
mysql-connectors-community | 2.5 kB 00:00:00
mysql-tools-community | 2.5 kB 00:00:00
mysql57-community | 2.5 kB 00:00:00
(1/3): mysql-connectors-community/x86_64/primary_db | 53 kB 00:00:00
(2/3): mysql57-community/x86_64/primary_db | 198 kB 00:00:00
(3/3): mysql-tools-community/x86_64/primary_db | 69 kB 00:00:00
Available Packages
Name : mysql-community-server
Arch : x86_64
Version : 5.7.29 <=5.7の現時点での最新版
Release : 1.el7
Size : 175 M
Repo : mysql57-community/x86_64
Summary : A very fast and reliable SQL database server
URL : http://www.mysql.com/
> インストールしてmysqldの起動と自動起動有効化
# yum -y install mysql-community-server mysql-devel
# systemctl enable mysqld.service
# systemctl start mysqld.service
(2)MySQL構成
# cat /var/log/mysqld.log | grep "A temporary password"
> 表示されるパスワードをメモ
> 上記のMySQL rootのパスワードを使ってインストール。いろいろ聞かれるが、基本的に全部YesでOK。
# mysql_secure_installation
# vi /etc/my.cnf
> 以下追記
character-set-server = utf8
default_password_lifetime = 0
(3)MySQLユーザー作成
Railsで使うDBを作り、DBユーザーを作成してGrantします。
# mysql -u root -p
mysql> CREATE DATABASE あなたのアプリ名_production;
mysql> CREATE USER 'DBユーザ名'@'localhost' IDENTIFIED BY 'パスワード';
mysql> GRANT ALL PRIVILEGES ON あなたのアプリ名_production.* TO 'DBユーザ名'@'localhost';
mysql> FLUSH PRIVILEGES;
mysql> exit;
8. Rubyインストールと基本構成
Rubyもいろいろバージョンがあるが、新し過ぎるバージョンはRails6側の各種Gemが未対応だったりとバージョン依存関係が面倒臭くなるので、Mac上のRailsアプリで動作が確認できている2.5.3を使うことにした。もちろん、rbenvも使う。
Rubyのインストール(rbenv install 2.5.3
)のところは安いプランだとパフォーマンスが悪いので結構時間がかかる。インストールには時間の余裕を持ってやった方が良い。また、途中でSSHがタイムアウトしないように前述のタイムアウトの設定を確認してからやること。
(1)Rubyのインストール
# yum -y install git gcc-c++ glibc-headers openssl-devel readline libyaml-devel readline-devel zlib zlib-devel bzip2
# cd /usr/local
# git clone git://github.com/sstephenson/rbenv.git rbenv
# git clone git://github.com/sstephenson/ruby-build.git rbenv/plugins/ruby-build
# vi /etc/profile.d/rbenv.sh
> 以下を記述してパスを通しておく。
export RBENV_ROOT="/usr/local/rbenv"
export PATH="${RBENV_ROOT}/bin:${PATH}"
eval "$(rbenv init --no-rehash -)"
# source /etc/profile.d/rbenv.sh
# rbenv install 2.5.3 <=これが時間がかかる。
# rbenv global 2.5.3
# rbenv rehash
(2)bundlerのインストール
ローカルのbundlerと同じバージョンをインストールする。
ローカルのbundlerのバージョン確認。私の環境は2.1.2であった。
$ gem list bundler
*** LOCAL GEMS ***
bundler (2.1.2, default: 1.17.3)
capistrano-bundler (1.6.0)
bundlerインストール
# gem install bundler -v 2.1.2
Railsで必要となるNodejsをインストールしておく。
# vi /etc/environment
> 次の2行を追加
LANG=en_US.utf-8
LC_ALL=en_US.utf-8
> EPELリポジトリからNode.jsをインストール
# yum install epel-release
# yum install nodejs npm
# npm install -g n
# n stable #=> 安定版インストール
installing : node-v12.16.1
mkdir : /usr/local/n/versions/node/12.16.1
fetch : https://nodejs.org/dist/v12.16.1/node-v12.16.1-linux-x64.tar.xz
installed : v12.16.1 to /usr/local/bin/node
active : v6.17.1 at /bin/node
> nodejsのバージョン確認
# node -v
v6.17.1
Yarnもインストールしておく。
# npm install -g yarn
/usr/bin/yarn -> /usr/lib/node_modules/yarn/bin/yarn.js
/usr/bin/yarnpkg -> /usr/lib/node_modules/yarn/bin/yarn.js
/usr/lib
└── yarn@1.22.4
9. Nginxのインストール
> リポジトリの準備
# vi /etc/yum.repos.d/nginx.repo
> nginx.repoは空のはずなので、以下を追加。
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/mainline/centos/7/$basearch/
gpgcheck=0
enabled=1
> インストール実行
# yum -y update
# yum -y install nginx
# systemctl start nginx
# systemctl enable nginx
プロセス確認
# ps aux|grep nginx
root 16535 0.0 0.1 46456 972 ? Ss 02:48 0:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
nginx 16536 0.0 0.3 46848 1664 ? S 02:48 0:00 nginx: worker process
動作確認のため、ブラウザでVultr VPSのIPアドレスにアクセス。以下の画面が出ればNginxのインストールとFirewallの変更は成功している。
10. 新しくRailsアプリをRubyMineで生成
今回Vultrで動かすアプリをローカルのMac側で新規に生成して準備しておく。説明は不要と思うが、作ったアプリは以下の画面の通り。
Rails 6.0.2.1
Ruby 2.5.3
(1) rails new
(2) bundle install
Rails 6にしてから依存関係は微妙に面倒臭くなった。Rails newしたらGemをクリーンインストールできるか確認してからアプリを作った方がいいね。Gemのインストール時は明示的にPathを指定した方が良い。
$ bundle clean --force
$ bundle install --path vendor/bundle
An error occurred while installing mysql2 (0.5.3), and Bundler cannot continue.
Make sure that `gem install mysql2 -v '0.5.3' --source 'https://rubygems.org/'` succeeds before bundling.
In Gemfile:
mysql2
macOS Catalina V10.15.3 ではお馴染みのエラー。対処方法は次の通り。
$ brew info openssl@1.1
openssl@1.1: stable 1.1.1d (bottled) [keg-only]
...
For compilers to find openssl@1.1 you may need to set:
export LDFLAGS="-L/usr/local/opt/openssl@1.1/lib"
export CPPFLAGS="-I/usr/local/opt/openssl@1.1/include"
...
上記ののpathをbundle config
で設定してからbundle install
を再実行。
$ bundle config --local build.mysql2 "--with-cppflags=-I/usr/local/opt/openssl@1.1/include"
$ bundle config --local build.mysql2 "--with-ldflags=-L/usr/local/opt/openssl@1.1/lib"
$ bundle install --path vendor/bundle
(3) database.ymlを修正
ローカルのMacのMySQLに接続するようdatabase.ymlを修正。
default: &default
adapter: mysql2
encoding: utf8mb4
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: <%= ENV.fetch('DATABASE_USER', '') %>
password: <%= ENV.fetch('DATABASE_PASSWORD', '') %>
host: <%= ENV.fetch('DATABASE_HOST', '') %>
development:
<<: *default
database: Capistrano3ToVultr_development
test:
<<: *default
database: Capistrano3ToVultr_test
production:
<<: *default
database: Capistrano3ToVultr_production
username: Capistrano3ToVultr
password: <%= ENV['CAPISTRANO3TOVULTR_DATABASE_PASSWORD'] %>
(4) msgpackをインストール
rakeを使う前にmsgpackをインストール
$ gem install msgpack
(5) db:create & migration
DB作成してマイグレーション
$ rake db:create
Created database 'Capistrano3ToVultr_development'
Created database 'Capistrano3ToVultr_test'
$ rake db:migrate
(6) webpackerをインストール
$ rails webpacker:install
✨ Done in 10.47s.
Webpacker successfully installed 🎉 🍰
(7) Railsアプリを起動してブラウザで確認。
11. RailsアプリをGitHubにPush
(1) GitHubに新規にリポジトリを作成
リポジトリを作成すると次のような画面になる。
(2) RailsアプリのディレクトリでGitを初期化
上記の画面のcreate a new repository on the command line
に従って初期化する。
$ cd アプリのroot directory
$ git init
Reinitialized existing Git repository in /Users/あなたのRailsディレクトリ/Capistrano3ToVultr/.git/
(3) .gitignore
にGitHubにPushしたくないファイルを指定
# See https://help.github.com/articles/ignoring-files for more about ignoring files.
#
# If you find yourself ignoring temporary files generated by your text editor
# or operating system, you probably want to add a global ignore instead:
# git config --global core.excludesfile '~/.gitignore_global'
# Ignore bundler config.
/.bundle
/vendor/bundler/
# Ignore all logfiles and tempfiles.
/log/*
/tmp/*
!/log/.keep
!/tmp/.keep
# Ignore uploaded files in development.
/storage/*
!/storage/.keep
/public/assets
.byebug_history
# Ignore master key for decrypting credentials and more.
/config/master.key
/config/settings.local.yml
/config/settings/*.local.yml
/config/environments/*.local.yml
/public/packs
/public/packs-test
/node_modules
/yarn-error.log
yarn-debug.log*
.yarn-integrity
.pryrc
.DS_Store
(4) Git Commit & Push to GitHub
GitHubにpushして入れる。
$ cd アプリのroot directory
$ git add .
$ git commit -m "first commit" <=好きなコメントでOK
$ git remote add origin git@github.com:あなたのリポジトリ名.git
$ git push -u origin master
Push後、GitHubの該当リポジトリに以下のようにファイルが入っていればOK。
(5) GitHubにデプロイ用ユーザーのSSH公開鍵を登録
Setting
> Deploy keys
> Add deploy keys
の順にクリック。
以下の画面になったら、ローカルMacの/Users/あなた/.ssh/vultr.pub
の中身を入れてAdd key
する。
12. Capistrano3を構成する
上記で新規に作ったRailsアプリのConfigを次のように変更。
(1) Capistrano関連Gemのインストール
> 以下を追加
# Use Capistrano for deployment
group :development do
gem 'capistrano'
gem 'ed25519' <=参考記事4には無いが、SSH鍵でed25519を使ったので指定。
gem 'bcrypt_pbkdf'
gem 'capistrano-rbenv'
gem 'capistrano-bundler'
gem 'capistrano-rails'
gem 'capistrano3-puma'
end
$ bundle install --path vendor/bundle
...
Bundle complete! 21 Gemfile dependencies, 77 gems now installed.
Bundled gems are installed into `./vendor/bundle`
Post-install message from capistrano3-puma:
All plugins need to be explicitly installed with install_plugin.
Please see README.md
(2) Capistranoの構成ファイルの生成
前のステップでbundle install
したらcap install
を実行してCapfileを生成する。VultrにはProduction環境だけ入れるので、Productionの分しか作らない。
$ bundle exec cap install STAGES=production
mkdir -p config/deploy
create config/deploy.rb
create config/deploy/production.rb
mkdir -p lib/capistrano/tasks
create Capfile
Capified
ここで、{Rails root}/Capfile
とconfig/deploy.rb
が生成されている事を確認する。
(3) Capistranoの構成
上記で生成されたCapfile
とdeploy.rb
を編集する。
# Load DSL and set up stages
require "capistrano/setup"
# Include default deployment tasks
require "capistrano/deploy"
# Load the SCM plugin appropriate to your project:
#
# require "capistrano/scm/hg"
# install_plugin Capistrano::SCM::Hg
# or
# require "capistrano/scm/svn"
# install_plugin Capistrano::SCM::Svn
# or
require "capistrano/scm/git"
install_plugin Capistrano::SCM::Git
# Include tasks from other gems included in your Gemfile
#
# For documentation on these, see for example:
#
# https://github.com/capistrano/rvm
# https://github.com/capistrano/rbenv
# https://github.com/capistrano/chruby
# https://github.com/capistrano/bundler
# https://github.com/capistrano/rails
# https://github.com/capistrano/passenger
#
# require "capistrano/rvm"
require "capistrano/rbenv"
# require "capistrano/chruby"
require "capistrano/bundler"
require "capistrano/rails/assets"
require "capistrano/rails/migrations"
# require "capistrano/passenger"
require 'capistrano/puma'
install_plugin Capistrano::Puma
install_plugin Capistrano::Puma::Nginx
# Load custom tasks from `lib/capistrano/tasks` if you have any defined
Dir.glob("lib/capistrano/tasks/*.rake").each { |r| import r }
server 'VultrサーバーのIPアドレス', user: "deploy", roles: %w{app db web}
# config valid for current version and patch releases of Capistrano
lock "~> 3.12.0"
server 'VultrサーバーのIPアドレス', port: 22, roles: [:app, :web, :db], primary: true
set :application, "あなたのアプリ名"
set :repo_url, "git@github.com:あなたのGitHubリポジトリ名.git"
set :user, 'deploy'
set :ssh_options, {
forward_agent: true,
user: fetch(:user),
keys: %w(~/.ssh/vultr)
}
# Default branch is :master
# ask :branch, `git rev-parse --abbrev-ref HEAD`.chomp
# Default deploy_to directory is /var/www/my_app_name
set :deploy_to, "/var/www/#{fetch(:application)}"
# Default value for :format is :airbrussh.
# set :format, :airbrussh
# You can configure the Airbrussh format using :format_options.
# These are the defaults.
# set :format_options, command_output: true, log_file: "log/capistrano.log", color: :auto, truncate: :auto
# Default value for :pty is false
# set :pty, true
# Default value for :linked_files is []
# append :linked_files, "config/database.yml"
# Default value for linked_dirs is []
# append :linked_dirs, "log", "tmp/pids", "tmp/cache", "tmp/sockets", "public/system"
# Default value for default_env is {}
# set :default_env, { path: "/opt/ruby/bin:$PATH" }
# Default value for local_user is ENV['USER']
# set :local_user, -> { `git config user.name`.chomp }
# Default value for keep_releases is 5
# set :keep_releases, 5
# Uncomment the following to require manually verifying the host key before first deploy.
# set :ssh_options, verify_host_key: :secure
# rbenv
set :rbenv_type, :system
set :rbenv_ruby, File.read('.ruby-version').strip
set :rbenv_prefix, "RBENV_ROOT=#{fetch(:rbenv_path)} #{fetch(:rbenv_path)}/bin/rbenv exec"
# bundler
append :linked_dirs, '.bundle'
set :bundle_jobs, 2 <=一番低いスペックのVultrプランなので2にした。Defaultは4。
append :linked_files, "config/master.key"
append :linked_dirs, "log", "tmp/pids", "tmp/cache", "tmp/sockets"
Capistranoはdeployユーザー権限で実行するので、Vultrに作ったVPSの/home/deploy/.bash_profile
を編集しておく。
# .bash_profile
# Get the aliases and functions
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
# User specific environment and startup programs
PATH=$PATH:$HOME/.local/bin:$HOME/bin
export PATH
export EDITOR=vi
export DATABASE_USER="上記で作ったDBユーザー名"
export DATABASE_PASSWORD="上記で作ったDBユーザーのパスワード"
(4) Vultr VPSにアプリのデプロイ先ディレクトリを準備
deploy.rb
でデプロイ先をset :deploy_to, "/var/www/#{fetch(:application)}"
としているので、VPSに/var/www/Capistrano3ToVultr
ディレクトリを作成する。
$ ssh -i ~/.ssh/vultr deploy@Vultr VPSのIPアドレス
以下はVultr側
$ sudo su
# mkdir /var/www
# mkdir /var/www/Capistrano3ToVultr
# mkdir /var/www/Capistrano3ToVultr/shared
# mkdir /var/www/Capistrano3ToVultr/shared/config
# chown -R deploy.deploy /var/www
(5) Vultr VPSにSharedディレクトリに入れるファイルをコピーしておく。
以下でrailsがリリース間で共有するリソースを定義しており、でデプロイ時に自動的に作られるが、ファイルは作られない。config/master.key
は予めサーバのshared以下にコピーしておく。
append :linked_files, "config/master.key"
append :linked_dirs, "log", "tmp/pids", "tmp/cache", "tmp/sockets"
$ scp -i ~/.ssh/vultr config/master.key deploy@VPSのIPアドレス:/var/www/Capistrano3ToVultr/shared/config/
master.key 100% 32 2.7KB/s 00:00
参考記事4に明確には書いてないけど必要だった事
- deployユーザーはパスワード無しでSSHできる事が必要。そうでないと
bundle exec cap production puma:nginx_config
でコケる。 - SSH鍵を複数のGitHubリポジトリで使い回しはできない。
(4) Capistranoでデプロイ実行
cap production deploy
でデプロイを実行するとGitHubからファイルを取ってきて指定した/var/www/アプリ名
ディレクトリにデプロイされる。デプロイ前にGitHubにPushしておくこと。
$ bundle exec cap production deploy
00:00 git:wrapper
01 mkdir -p /tmp
途中省略
デプロイが成功すればreleasesディレクトリにタイムスタンプがディレクトリ名になり、その下にファイルがデプロイされ、/var/www/Capistrano3ToVultr/currentにリンクされる。
[deploy@vultr releases]$ pwd
/var/www/Capistrano3ToVultr/releases
[deploy@vultr releases]$ ls -l
total 4
drwxrwxr-x 12 deploy deploy 4096 Mar 15 00:15 20200315001550
12. Nginx と Puma の連携
分かってしまえばどうと言うことはないのだが、ここでハマった。CapistranoもNginxも正常動作しているように見えた(エラーは何も出なかった)のだが、Railsの画面が出ず、Nginxの初期画面しか出なかった。原因はディレクトリやファイルのパーミッション設定とNginxとPumaの各プロセスの実行ユーザーの指定だった。これに気づくまで時間を要してしまったので、細かく書こうと思う。
(1) Config
以下は動作している各Configである。Defaultと変えたところだけコメントを付けた。ディレクトリやファイルのパーミッション、ユーザー、グループに注意。
drwxr-xr-x 3 deploy deploy 4096 Mar 7 22:09 www
drwxr-xr-x 5 deploy deploy 4096 Mar 8 04:55 Capistrano3
#!/usr/bin/env puma
directory '/var/www/Capistrano3/current'
rackup "/var/www/Capistrano3/current/config.ru"
environment 'production'
tag ''
pidfile "/var/www/Capistrano3/shared/tmp/pids/puma.pid"
state_path "/var/www/Capistrano3/shared/tmp/pids/puma.state"
stdout_redirect '/var/www/Capistrano3/shared/log/puma_access.log', '/var/www/Capistrano3/shared/log/puma_error.log', true
threads 0,16
bind 'unix:///var/www/Capistrano3/shared/tmp/sockets/puma.sock'
workers 0
restart_command 'bundle exec puma'
prune_bundler
on_restart do
puts 'Refreshing Gemfile'
ENV["BUNDLE_GEMFILE"] = ""
end
#user nginx;
user deploy; <=重要。NginxとPumaは同じユーザーでプロセスを起動する。
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*; <=RailsアプリのConfigをここでインクルードしている。
}
drwxr-xr-x 2 root root 4096 Mar 8 16:58 sites-available
drwxr-xr-x 2 root root 4096 Mar 8 16:58 sites-enabled
[deploy@vultr sites-available]$ pwd
/etc/nginx/sites-available
[deploy@vultr sites-available]$ ls -l
total 4
-rw-r--r-- 1 deploy deploy 1614 Mar 8 17:18 Capistrano3_production
[deploy@vultr sites-enabled]$ pwd
/etc/nginx/sites-enabled
[deploy@vultr sites-enabled]$ ls -l
total 0
lrwxrwxrwx 1 root root 49 Mar 8 03:39 Capistrano3_production -> /etc/nginx/sites-available/Capistrano3_production <=リンクを貼っただけ
upstream puma_Capistrano3_production {
server unix:/var/www/Capistrano3/shared/tmp/sockets/puma.sock fail_timeout=0;
}
server {
listen 80;
server_name あなたのVultrサーバーのIPアドレス;
root /var/www/Capistrano3/current/public;
try_files $uri/index.html $uri @puma_Capistrano3_production;
client_max_body_size 4G;
keepalive_timeout 10;
error_page 500 502 504 /500.html;
error_page 503 @503;
location @puma_Capistrano3_production {
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header X-Forwarded-Proto http;
proxy_pass http://puma_Capistrano3_production;
# limit_req zone=one;
access_log /var/www/Capistrano3/shared/log/nginx.access.log;
error_log /var/www/Capistrano3/shared/log/nginx.error.log;
# Basic認証
auth_basic "Restricted"; <=テスト用のサーバーなのでBasic認証を付けた
auth_basic_user_file /etc/nginx/sites-available/.htpasswd; <=テスト用のサーバーなのでBasic認証を付けた
}
location ^~ /assets/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
location = /50x.html {
root html;
}
location = /404.html {
root html;
}
location @503 {
error_page 405 = /system/maintenance.html;
if (-f $document_root/system/maintenance.html) {
rewrite ^(.*)$ /system/maintenance.html break;
}
rewrite ^(.*)$ /503.html break;
}
if ($request_method !~ ^(GET|HEAD|PUT|PATCH|POST|DELETE|OPTIONS)$ ){
return 405;
}
if (-f $document_root/system/maintenance.html) {
return 503;
}
}
(2) Railsアプリの動作確認
Puma起動
$ bundle exec cap production puma:status
00:00 puma:status
WARN Puma not running
$ bundle exec cap production puma:start
00:00 puma:start
using conf file /var/www/Capistrano3/shared/puma.rb
01 RBENV_ROOT=/usr/local/rbenv /usr/local/rbenv/bin/rbenv exec bundle exec puma -C /var/www/Capistrano3/shared/puma.rb --daemon
01 Puma starting in single mode...
01 * Version 4.3.3 (ruby 2.5.3-p105), codename: Mysterious Traveller
01 * Min threads: 0, max threads: 16
01 * Environment: production
01 * Daemonizing...
✔ 01 deploy@あなたのサーバーIPアドレス 0.940s
$ bundle exec cap production puma:status
00:00 puma:status
01 RBENV_ROOT=/usr/local/rbenv /usr/local/rbenv/bin/rbenv exec bundle exec pumactl -S /var/www/Capistrano3/shared/tmp/pids/puma.state -F /var/www/Capistrano3/shared/puma.rb status
01 Puma is started
✔ 01 deploy@あなたのサーバーIPアドレス 0.576s
Railsアプリ画面確認
終わりに
今後、本番のRailsアプリをデプロイする時にはサーバーを二重化してVultrのロードバランサを使って耐障害性を高めるなどやりたいと思う。MySQLの二重化とか、TokyoサーバーとNew Yorkサーバーでのクラスタリングとか遅延がある中でどこまで実運用に耐えられるのか試したい。一定規模のユーザーが増えて、収益が十分確保できればAWSに移行するだろうが、それまでは月々のRunning Costをいかに安く抑えるかが重要なのでVultrは強い味方と言えると思う。ただし、インフラ関係のスキルは必要だが。
今後やりたいこと
- SMTPの構成
- バックアップ&リストア検証
- ロードバランサーで二重化
- MySQLクラスタリング