Railsのリポジトリがある前提です
バージョン
centos
7.6
mysql
8.0.17
$ ruby -v
2.6.3
$ rails -v
6.0.0.rc1
$ node -v
v12.8.0
大まかな手順
1. conohaにVPS登録
2. vpsサーバの各種設定
3. Rubyインストール
4. mysqlインストール・設定
5. nginxインストール・設定
6. CapistranoとUnicornのインストール・設定
7.
8.
1. conohaに登録
↓ こちらから登録すると1000円分のクーポンがもらえるらしいです
https://www.conoha.jp/referral/?token=IWGrST5H2QhYV.qMLTsPTHRLvaa1fDkrP7CpxS7_2efeNKRbFC8-O6O
私はCentos7.6でメモリ2GB1750円のvpsプランを選択しました。
=>⚠️ # はroot権限という意味です
2. サーバーの設定
ログイン
$ ssh root@123.43.567.89
# yum update
localeを変更する
# localectl set-locale LANG=ja_JP.utf8
# localectl
# cat /etc/locale.conf
# source /etc/locale.conf #反映
作業ユーザー登録
# useradd username
# passwd username
# usermod -G wheel username
# visudo
↓ファイルが立ち上がる
## Allows people in group wheel to run all commands
%wheel ALL=(ALL) ALL
上の行の先頭のコメントを外して保存
一旦、サーバーから抜けて作成したユーザーでログインできるか確認
$ ssh hogehuga@123.45.678.000
ログイン成功!!
鍵認証の設定
Mac側で鍵のペアを生成(秘密鍵と公開鍵)
VPS側で公開鍵をMac側で秘密鍵を使ってマッチさせる仕組み
鍵を生成前にまずはVPS側で公開鍵の保管場所を作成する
$ mkdir ~/.ssh # ディレクトリ作成
$ chmod 700 ~/.ssh #パーミッション設定
MAC側(localhost)で作業
$ ssh-keygen -y rsa -v # 鍵が作成される(id_rsaとid_rsa.pub)
$ chmod 600 ~/.ssh/id_rsa.pub # パーミッション付与
公開鍵をVPSに転送
$ scp ~/.ssh/id_rsa.pub hogehuga@123.45.678.000:~/.ssh/authorized_keys
vpsに入って確認する
$ ls -la .ssh
=> authorized_keysが入っていれば良い
セキュリティを高めるsshの設定
# vim /etc/ssh/sshd_config
で以下のように変更
PubkeyAuthentication yes
Port変更
Port 55555
rootユーザーでのログインを禁止。
PermitRootLogin no
パスワードログインを禁止。yesからnoへ変更
PasswordAuthentication no
公開鍵の場所を設定
AuthorizedKeysFile .ssh/authorized_keys
sshdを再起動。編集を反映させる
# service sshd restart
iptablesをインストール
# yum install iptables-services
# vim /etc/sysconfig/iptables
下を削除
# -A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT
下を追加
-A INPUT -m state --state NEW -m tcp -p tcp --dport 55555 -j ACCEPT
iptablesの設定を反映させる再起動
# service iptables restart
configファイルも作っておく
# vi ~/.ssh/config
Host conoha_deploy_app
HostName 123.45.67.89 # ip_adress
User hogehuga
Port 55555
IdentityFile ~/.ssh/id_rsa # deployの時にも使います
ssh-agentを登録しておく
$ eval `ssh-agent`
$ ssh-add ~/.ssh/id_rsa
ローカルから接続できているか試す
$ ssh conoha_deploy_app
3. Ruby インストール
サーバーでの作業が続きます
まずはgitをインストール!
なるべく新しいのが良いと思ったので2.7.4です。
少し手間ですが、以下のコマンドを実行しました。
参考
https://ex1.m-yabe.com/archives/3546
# yum install curl-devel expat-devel gettext-devel openssl-devel zlib-devel perl-ExtUtils-MakeMaker
# cd /usr/local/src
# wget https://www.kernel.org/pub/software/scm/git/git-2.7.4.tar.gz
# tar zxvf git-2.7.4.tar.gz
# cd git-2.7.4
# ./configure --prefix=/usr/local/
# rpm -qa|grep gcc
# yum -y install gcc
# ./configure --prefix=/usr/local/
# make prefix=/usr/local all
# make prefix=/usr/local install
# git version
=> git version 2.7.4
rbenvインストール
rbenvはrubyのバージョン管理ツールです
$ git clone https://github.com/sstephenson/rbenv.git ~/.rbenv
ruby-buildインストール
ruby-burildはrbenv installを実行するためのrbenvのプラグインです。
rbenvとセットでインストール
$ git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
依存パッケージのインストール
rubyをインストールするための関連するパッケージです。これがないと、rbenv installの際にコケます。
$ sudo yum -y install bzip2 gcc openssl-devel readline-devel zlib-devel
rbenv読み込み設定
$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
# rbenvの初期化
$ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
# bashの再読込
$ source ~/.bash_profile
# バージョン確認 バージョンが出ればOK
$ rbenv -v
Rubyインストール
$ rbenv install 2.6.3
$ rbenv global 2.6.3
$ rbenv rehash
# バージョン確認
$ ruby -v
2.6.3
bundlerインストール
$ gem install bundle
node.jsインストール
railsでnode.jsが必要
$ sudo yum install nodejs npm --enablerepo=epel
yarnもインストール
$ sudo npm install -g yarn
4. MySQL8のインストール
sudo rpm -Uvh https://dev.mysql.com/get/mysql80-community-release-el7-3.noarch.rpm
sudo yum install --enablerepo=mysql80-community mysql-community-server
sudo yum clean all
mysqld --version
systemctl enable mysqld.service 自動起動設定
systemctl start mysqld.service 起動
sudo grep 'temporary password' /var/log/mysqld.log => 最初のログインで使用する初期設定用のパスワードが表示されます
mysql -u root -p
mysql_secure_installation =>passwordを変更する
Mysql 8のmy.cnf設定
デフォルトでも構いません
https://qiita.com/nanorkyo/items/94a80683c6753f61316a
リモートで
sudo vim /etc/my.cnf
自分はこんな感じです↓
[mysqld]
default-authentication-plugin=mysql_native_password
default-password-lifetime = 0
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_bin
open-files-limit = 65536
max-connections = 10000
table-open-cache = 2000
[client]
default-character-set = utf8mb4
リスタートして
sudo systemctl restart mysqld.service
ログインする
Mysqlログイン
mysql -u root -p
> create user 'username'@'123.4.56.78' identified by 'password';
> grant all privileges on *.* to 'hogehuga'@'123.4.56.78' with grant option;
> flush privileges;
$ mysql -u hogehuga -h 123.4.56.78 -p
> create database app_production;
> exit;
5. nginx(webサーバー)の設定
デプロイするアプリの置き場所をVPSに用意する
$ sudo mkdir -p /var/www/アプリケーション名
nginxをインストールするための準備
# cd /etc/yum.repos.d
# touch nginx.repo
ファイルの中身を書き加えましょう。
管理者権限になっていることに注意
# vi nginx.repo
nginx.repoファイルの書き方は以下のような感じ(サンプル)
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/7/$basearch/
gpgcheck=0
enabled=1
nginxをインストール
インストールされるリポジトリ情報を確認
# yum info nginx
インストール
# yum install nginx
設定ファイルをバックアップ
# sudo cp /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/local.conf
# mv /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf.bk
# 各種ログのディレクトリ設定
error_log /var/www/app_name/current/log/nginx.error.log;
access_log /var/www/app_name/current/log/nginx.access.log;
# 処理を受け取る最大許容量
client_max_body_size 2G;
upstream unicorn {
server unix:/var/www/deploy_app/shared/tmp/sockets/unicorn.sock; ### 変更箇所 ちょー大事、後ほど登場するユニコーンと紐づく
}
server {
listen 80; # ポート番号
server_name 123.654.87.9;
# 次のリクエストが来るまでの待ち時間(秒
keepalive_timeout 5;
location / {
root /var/www/app_name/current/public;
}
#キャッシュのディレクトリ
try_files $uri/index.html $uri.html $uri @app;
location @unicorn {
# HTTP headers
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://unicorn;
}
error_page 500 502 503 504 /500.html;
location = /500.html {
root /var/www/app_name/current/public;
}
}
設定ファイルを編集
$ sudo vi /etc/sysconfig/iptables
-A INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT
を追記
# sample configuration for iptables service
# you can edit this manually or use system-config-firewall
# please do not ask us to add additional ports/services to this default configuration
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-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 12345 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT
みたいな感じになってます
再起動。
$ sudo service iptables restart
開放されてるか確認
$ sudo iptables -nL
こんな感じで表示されます
ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:80
サーバー再起動の際にもNginxが自動的に起動するよう設定
chkconfig nginx on
Nginxの設定が完了
6. CapistranoとUnicornの設定
Gemfileにインストール作業で使用する物を記述
ruby '2.6.3'
gem 'mysql2'
・・・・その他中略・・・
group :development do
# Access an IRB console on exception pages or by using <%= console %> anywhere in the code.
gem 'web-console', '>= 3.3.0'
gem 'listen', '>= 3.0.5', '< 3.2'
# Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
gem 'spring'
gem 'spring-watcher-listen', '~> 2.0.0'
# 以下追記
gem 'capistrano'
gem 'capistrano-bundler'
gem 'capistrano-rails'
gem 'capistrano-rbenv'
gem 'capistrano-nvm', require: false
gem 'capistrano-yarn'
gem 'capistrano3/unicorn'
end
group :production, :staging do
# 以下追記
gem 'unicorn'
end
$ bundle install
Capistranoを設定していく
ファイルを生成するコマンド
$ cap install
capistranoの設定ファイルを編集
# capistranoの基本動作を設定
require "capistrano/setup"
require "capistrano/deploy"
require "capistrano/scm/git"
install_plugin Capistrano::SCM::Git
require "capistrano/rails"
require "capistrano/rails/assets"
require "capistrano/rails/migrations"
# rbenvの設定
require "capistrano/rbenv" #ok
require "capistrano/bundler"
require "pry" # 全然必要ないけどデバッグで便利でした...
require 'capistrano/yarn'
require 'capistrano3/unicorn'
Dir.glob("lib/capistrano/tasks/*.rake").each { |r| import r }
リモートのサーバー情報書いていく
set :stage, :production
set :branch, 'master' ## 必要があれば変更
server '21.43.65.7', user: 'hoge', roles: %w{app db web}, port: 12345
set :ssh_options, {
port: 12345, #### 変更
keys: [File.expand_path('~/.ssh/id_rsa')], # リモートサーバー用秘密鍵があるところを指定
forward_agent: true,
auth_methods: %w(publickey)
アプリケーション名や
gitのリポジトリなど書いていきます
# config valid for current version and patch releases of Capistrano
lock "~> 3.11.0"
set :application, "deploy_app"
set :repo_url, "git@github.com:user_name/deploy_app.git" デプロイするgitリポジトリURL
set :deploy_to, '/var/www/deploy_app' # デプロイ先
set :rbenv_type, :user # rbenvをシステムにインストールした or ユーザーローカルにインストールした
set :rbenv_ruby, '2.6.3' # サーバで利用するrubyのバージョンを指定
set :rbenv_path, '/home/username/.rbenv'
set :rbenv_prefix, "RBENV_ROOT=#{fetch(:rbenv_path)} RBENV_VERSION=#{fetch(:rbenv_ruby)} #{fetch(:rbenv_path)}/bin/rbenv exec"
# リリースフォルダをいくつまで保持するか?
set :keep_releases, 5
set :deploy_via, :remote_cache
set :log_level, :debug # capistranoの出力ログの制御
set :pty, true # sudoを使用するのに必要
set :yarn_flags, "--ignore-engines --prefer-offline --production --no-progress"
set :yarn_roles, :all
set :yarn_env_variables, {}
# Shared に入るものを指定
set :linked_files, %w{config/database.yml config/secrets.yml} # シンボリックリンクを貼るファイル
set :linked_dirs, %w{log tmp/pids tmp/sockets tmp/cache vender/bundle } # sharedにシンボリックリンクを張るディレクトリ指定
after 'deploy:publishing', 'deploy:restart'
namespace :deploy do
desc 'Restart application'
# アプリ再起動を行うタスク
task :restart do
on roles(:app), in: :sequence, wait: 5 do
execute :mkdir, '-p', release_path.join('tmp')
execute :touch, release_path.join('tmp/restart.txt')
end
end
# linked_files で使用するファイルをアップロードするタスク
# deployが行われる前にコマンドにて実行する
desc 'upload important files'
task :upload do
on roles(:app) do |host|
execute :mkdir, '-p', "#{shared_path}/config"
upload!('config/database.yml',"#{shared_path}/config/database.yml")
upload!('config/secrets.yml',"#{shared_path}/config/secrets.yml")
end
end
# webサーバー再起動時にキャッシュを削除する
after :restart, :clear_cache do
on roles(:web), in: :groups, limit: 3, wait: 10 do
#Here we can do anything such as:
within release_path do
execute :rm, '-rf', release_path.join('tmp/cache')
end
end
end
# Flow の before, after のタイミングで上記タスクを実行
before :started, 'deploy:upload'
after :finishing, 'deploy:cleanup'
#unicorn 再起動タスク
desc 'Restart application'
task :restart do
invoke 'unicorn:restart' # lib/capustrano/tasks/unicorn.rake 内処理を呼び出す
end
end
認証で使うsecrets.ymlを生成します
ローカルで以下のコマンドを実施
$ rails secret | pbcopy
ファイルに貼り付ける
production:
secret_key_base: #####ここに貼り付けてください
リモートサーバにて
必要なディレクトリを作成しておく
$ sudo mkdir -p /var/www/deploy_app/shared/config
$ sudo chown -R 作業ユーザー名 www
Uniconの設定をします
ローカルで
vim lib/capistrano/tasks/unicorn.cap
コピペでいいです
namespace :unicorn do
task :environment do
set :unicorn_pid, "#{current_path}/tmp/pids/unicorn.pid" # config/unicorn/production.rbないのpidと同じ
set :unicorn_config, "#{current_path}/config/unicorn/production.rb"
end
def start_unicorn
# フォルダが存在した場合のみ実行する
within current_path do
execute :bundle, :exec, :unicorn, "-c #{fetch(:unicorn_config)} -E #{fetch(:rails_env)} -D"
end
end
# unicorn停止
def stop_unicorn
execute :kill, "-s QUIT $(< #{fetch(:unicorn_pid)})"
end
# unicorn再起動
def reload_unicorn
execute :kill, "-s USR2 $(< #{fetch(:unicorn_pid)})"
end
# unicorn 強制終了
def force_stop_unicorn
execute :kill, "$(< #{fetch(:unicorn_pid)})"
end
# unicorn をスタートさせる
desc "Start unicorn server"
task :start => :environment do
on roles(:app) do
start_unicorn
end
end
# unicorn停止させる
desc "Stop unicorn server gracefully"
task :stop => :environment do
on roles(:app) do
stop_unicorn
end
end
#
desc "Restart unicorn server gracefully"
task :restart => :environment do # TODO
on roles(:app) do
if test("[ -f #{fetch(:unicorn_pid)} ]")
reload_unicorn
else
start_unicorn
end
end
end
# unicornを強制終了させるTask
desc "Stop unicorn server immediately"
task :force_stop => :environment do # TODO
on roles(:app) do
force_stop_unicorn
end
end
end
unicornの設定ファイルを書いていく
ここがうまく紐づかないとリリース後にrailsが動かなかったりします
気をつけてください
# -*- coding: utf-8 -*-
worker_processes Integer(ENV["WEB_CONCURRENCY"] || 3)
timeout 30
# ホットデプロイをするか?
preload_app true # 更新時ダウンタイム無し
current_path = '/var/www/deploy_app/shared'
app_path = '/var/www/deploy_app/current'
working_directory "#{app_path}"
# nginxと連携するための設定
# リクエストを受け取る ポート番号を指定
listen "/var/www/deploy_app/shared/tmp/sockets/unicorn.sock" # nginxと同じ
# PIDの管理ディレクトリ
pid "#{current_path}/tmp/pids/unicorn.pid"
stdout_path "#{app_path}/log/unicorn.log"
stderr_path "#{app_path}/log/unicorn.log"
# ログの出力パス
stderr_path File.expand_path('log/unicorn.log', ENV['RAILS_ROOT'])
stdout_path File.expand_path('log/unicorn.log', ENV['RAILS_ROOT'])
puts "カレントパス#{ current_path }"
puts ""
# フォーク前に行うことを定義
before_fork do |server, worker|
Signal.trap 'TERM' do
puts 'Unicorn master intercepting TERM and sending myself QUIT instead'
Process.kill 'QUIT', Process.pid
end
defined?(ActiveRecord::Base) and
ActiveRecord::Base.connection.disconnect!
end
# フォーク後に行うことを定義
after_fork do |server, worker|
Signal.trap 'TERM' do
puts 'Unicorn worker intercepting TERM and doing nothing. Wait for master to send QUIT'
end
defined?(ActiveRecord::Base) and
ActiveRecord::Base.establish_connection
end
database.ymlの設定
default: &default
adapter: mysql2
encoding: utf8mb4
charset: utf8mb4
collation: utf8mb4_unicode_ci
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: root
password:
host: localhost
socket: /tmp/mysql.sock
development:
<<: *default
database: deploy_app_development
test:
<<: *default
database: deploy_app_test
production:
<<: *default
adapter: mysql2
database: deploy_app_production
username: username
password: PassWord
host: 12.34.765.89
7 リモートとgithubの連携
ローカルとサーバーの鍵認証は先にしておりますが、
リモートサーバーとgithubを連携するための
鍵認証の設定です
リモートサーバーで作業すること
$ cd ~/.ssh
$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/hogehuga/.ssh/id_rsa): Enter
Enter passphrase (empty for no passphrase): Enter
Enter same passphrase again: Eneter
$ cat id_rsa.pub
# 出力をコピーして、以下のgithubのコンソールリンクより公開鍵を登録
-> https://github.com/settings/keys
# 設定ファイルを作成
$ sudo vi ~/.ssh/config
# 以下を記述
Host github
Hostname github.com
User git
IdentityFile ~/.ssh/id_rsa
ssh-agentの設定(これやらないとpermission error出ます)
$ eval `ssh-agent`
$ ssh-add ~/.ssh/id_rsa
$ ssh -vT github で確認 # vはデバッグオプションで便利
# 以下のような文章が出力されればOK
Hi Hogehuga! You've successfully authenticated, but GitHub does not provide shell access.
gitにプッシュする
$ git add .
$ git commit -m "deploy"
$ git git push origin master
長かったですが、デプロイしてみましょう
ローカルから
$ bundle exec cap production deploy:upload # database.yml、secrets.ymlをアップロードする
$ bundle exec cap production deploy:check # deploy可能かのチェック
$ bundle exec cap production deploy
すんなりいくとは思いませんが、
エラーが起きた場合にはnginxのログやunicornのログなどを頼りにしつつ、問題を切り分けてコツコツ進んでいくのが良いと思います。
ファイルの権限/設定のパスの整合性/各種システムの起動し忘れ/などなどです
雑なメモ
nginx基本コマンド
起動
$ sudo systemctl start nginx
停止
$ sudo systemctl stop nginx
再起動
$ sudo systemctl restart nginx
再起動しても設定ファイルが反映されない場合など
$ sudo nginx -s reload
状態の確認
$ sudo systemctl status nginx
Mysqlコマンド
ログイン
mysql -u username -h 123.45.67.89 -p
・起動
sudo service mysqld start
・停止
sudo service mysqld stop
・再起動
sudo service mysqld restart
Iptablesコマンド
systemctl start iptables
systemctl enable iptables
systemctl status iptables
sshdコマンド
systemctl restart sshd
systemctl status sshd
Unicornコマンド