Deploy rails 5.2 app lên server amazon EC2
Bài đăng này đã không được cập nhật trong 5 năm
1. Tạo 1 user để deploy
sudo adduser deploy
cấp quyền cho user
sudo nano /etc/sudoers
%deploy ALL=(ALL) ALL
chuyển sang làm việc với user deploy
sudo su - deploy
2. Add ssh key authentication
Để lấy code từ github thông qua ssh
ssh-keygen -t rsa -b 4096 -C "YOUR EMAIL"
và enter liên tục thôi.
Dùng lệnh cat ~/.ssh/id_rsa.pub
để hiển thị ssh-key, copy rồi paste vào setting SSH and GPG key của bạn rồi tạo mới SHH key
Tiếp theo lập ssh authentication để kết nối được với server ở local không phải cần password hay thông qua user ubuntu
mkdir .ssh
sudo chmod 700 .ssh
touch ~/.ssh/authorized_keys
sudo chmod 600 ~/.ssh/authorized_keys
Ta lấy ssh-key dùng ở trên để rồi copy paste vào file authorized_keys
là được
Giờ các bạn có thể nhanh chóng vào server ở local thông qua lệnh
shh deploy@<ip_server_aws>
<ip_server_aws>
là IPv4 public ip, các bạn có thể thấy ở trang Instance
3. Cài đặt Rails
gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
curl -sSL https://get.rvm.io | bash -s stable
source ~/.rvm/scripts/rvm
rvm requirements
rvm install 2.5.1
rvm use ruby-2.5.1 --default
gem install rails 5.2.1 --no-ri --no-rdoc
gem install bundler --no-ri --no-rdoc
rails -v
sudo apt-get install mysql-server mysql-client libmysqlclient-dev
4. Cài đặt Nginx
sudo apt-get update
sudo apt-get install curl git-core nginx -y
TIếp theo là cấu hình cho việc lưu log nginx. Thay đổi user default trong file sudo nano /etc/nginx/nginx.conf
thành deploy
5. Cài đặt Capistrano
Thêm gem Capistrano vào Gemfile
gem 'capistrano', '~> 3.11.0', require: false
gem 'capistrano-rvm', '~> 0.1.2', require: false
gem 'capistrano-rails', '~> 1.4.0', require: false
gem 'capistrano-bundler', '~> 1.3.0', require: false
gem 'capistrano3-puma', '~> 3.1.1', require: false
cài đặt thư viện
bundle
Khởi tạo Capistrano
cap install
Capfile
require 'capistrano/setup'
require 'capistrano/deploy'
require 'capistrano/rails'
require 'capistrano/bundler'
require 'capistrano/rvm'
require 'capistrano/puma'
install_plugin Capistrano::Puma # Default puma tasks
require "capistrano/scm/git"
install_plugin Capistrano::SCM::Git
Dir.glob('lib/capistrano/tasks/*.rake').eachmport r }
config/deploy/production.rb
# Change these
# By default your port will be 22
server "YOUR_SERVER_IP", port: YOUR_PORT, roles: %w(web app db), primary: true
set :repo_url, "YOUR_GIT_URL"
set :application, "YOUR_APP_NAME_production"
set :user, "ubuntu"
set :puma_threads, [4, 16]
set :puma_workers, 0
# Don"t change these unless you know what you"re doing
set :pty, true
set :use_sudo, false
set :stage, :production
set :deploy_via, :remote_cache
set :deploy_to, "/home/#{fetch(:user)}/apps/#{fetch(:application)}"
set :puma_bind, "unix://#{shared_path}/tmp/sockets/#{fetch(:application)}-puma.sock"
set :puma_state, "#{shared_path}/tmp/pids/puma.state"
set :puma_pid, "#{shared_path}/tmp/pids/puma.pid"
set :puma_access_log, "#{release_path}/log/puma.access.log"
set :puma_error_log, "#{release_path}/log/puma.error.log"
set :ssh_options, { forward_agent: true, user: fetch(:user), keys: %w(~/.ssh/id_rsa.pub) }
set :puma_preload_app, true
set :puma_worker_timeout, nil
set :puma_init_active_record, true # Change to false when not using ActiveRecord
## Defaults:
# set :scm, :git
# set :branch, :master
# set :format, :pretty
# set :log_level, :debug
# set :keep_releases, 5
## Linked Files & Directories (Default None):
# set :linked_files, %w{config/database.yml}
# set :linked_dirs, %w{bin log tmp/pids tmp/cache tmp/sockets vendor/bundle public/system}
namespace :puma do
desc "Create Directories for Puma Pids and Socket"
task :make_dirs do
on roles(:app) do
execute "mkdir #{shared_path}/tmp/sockets -p"
execute "mkdir #{shared_path}/tmp/pids -p"
end
end
before :start, :make_dirs
end
namespace :deploy do
desc "Make sure local git is in sync with remote."
task :check_revision do
on roles(:app) do
unless `git rev-parse HEAD` == `git rev-parse origin/master`
puts "WARNING: HEAD is not the same as origin/master"
puts "Run `git push` to sync changes."
exit
end
end
end
desc "Initial Deploy"
task :initial do
on roles(:app) do
invoke "deploy"
end
end
before :starting, :check_revision
after :finishing, :compile_assets
after :finishing, :cleanup
after :finishing, :restart
end
# ps aux | grep puma # Get puma pid
# kill -s SIGUSR2 pid # Restart puma
# kill -s SIGTERM pid # Stop puma
config/deploy/staging.rb
# By default your port will be 22
server 'YOUR_SERVER_IP', port: YOUR_PORT, roles: [:web, :app, :db], primary: true
set :repo_url, 'YOUR_GIT_URL'
set :application, 'YOUR_APP_NAME_staging'
set :user, 'ubuntu'
set :puma_threads, [4, 16]
set :puma_workers, 0
set :branch, :staging
set :port, 3000
# Don't change these unless you know what you're doing
set :pty, true
set :use_sudo, false
set :stage, :production
set :deploy_via, :remote_cache
set :deploy_to, "/home/#{fetch(:user)}/apps/#{fetch(:application)}"
set :puma_bind, "unix://#{shared_path}/tmp/sockets/#{fetch(:application)}-puma.sock"
set :puma_state, "#{shared_path}/tmp/pids/puma.state"
set :puma_pid, "#{shared_path}/tmp/pids/puma.pid"
set :puma_access_log, "#{release_path}/log/puma.access.log"
set :puma_error_log, "#{release_path}/log/puma.error.log"
set :ssh_options, { forward_agent: true, user: fetch(:user), keys: %w(~/.ssh/id_rsa.pub) }
set :puma_preload_app, true
set :puma_worker_timeout, nil
set :puma_init_active_record, true # Change to false when not using ActiveRecord
## Defaults:
# set :scm, :git
# set :format, :pretty
# set :log_level, :debug
# set :keep_releases, 5
## Linked Files & Directories (Default None):
# set :linked_files, %w{config/database.yml}
# set :linked_dirs, %w{bin log tmp/pids tmp/cache tmp/sockets vendor/bundle public/system}
namespace :puma do
desc 'Create Directories for Puma Pids and Socket'
task :make_dirs do
on roles(:app) do
execute "mkdir #{shared_path}/tmp/sockets -p"
execute "mkdir #{shared_path}/tmp/pids -p"
end
end
before :start, :make_dirs
end
namespace :deploy do
desc "Make sure local git is in sync with remote."
task :check_revision do
on roles(:app) do
unless `git rev-parse HEAD` == `git rev-parse origin/master`
puts "WARNING: HEAD is not the same as origin/master"
puts "Run `git push` to sync changes."
exit
end
end
end
desc 'Initial Deploy'
task :initial do
on roles(:app) do
invoke 'deploy'
end
end
before :starting, :check_revision
after :finishing, :compile_assets
after :finishing, :cleanup
after :finishing, :restart
end
# ps aux | grep puma # Get puma pid
# kill -s SIGUSR2 pid # Restart puma
# kill -s SIGTERM pid # Stop puma
tạo file config/nginx
# config/nginx/nginx_production.conf
upstream puma {
server unix:///home/deploy/apps/YOUR_APP_NAME_production/shared/tmp/sockets/YOUR_APP_NAME_production-puma.sock;
}
server {
listen 80 default_server deferred;
# server_name example.com;
root /home/deploy/apps/YOUR_APP_NAME_production/current/public;
access_log /home/deploy/apps/YOUR_APP_NAME_production/current/log/nginx.access.log;
error_log /home/deploy/apps/YOUR_APP_NAME_production/current/log/nginx.error.log info;
location ^~ /assets/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
try_files $uri/index.html $uri @puma;
location @puma {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://puma;
}
error_page 500 502 503 504 /500.html;
client_max_body_size 10M;
keepalive_timeout 10;
}
config/nginx/nginx_production.conf
# config/nginx/nginx_production.conf
upstream puma {
server unix:///home/deploy/apps/YOUR_APP_NAME_production/shared/tmp/sockets/YOUR_APP_NAME_production-puma.sock;
}
server {
listen 80 default_server deferred;
# server_name example.com;
root /home/deploy/apps/YOUR_APP_NAME_production/current/public;
access_log /home/deploy/apps/YOUR_APP_NAME_production/current/log/nginx.access.log;
error_log /home/deploy/apps/YOUR_APP_NAME_production/current/log/nginx.error.log info;
location ^~ /assets/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
try_files $uri/index.html $uri @puma;
location @puma {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://puma;
}
error_page 500 502 503 504 /500.html;
client_max_body_size 10M;
keepalive_timeout 10;
}
config/nginx/nginx_staging.conf
# config/nginx/nginx_staging.conf
upstream staging {
server unix:///home/ubuntu/apps/YOUR_RAILS_APP_staging/shared/tmp/sockets/cap-rails-staging-puma.sock;
}
server {
listen 3000 default_server deferred;
# server_name example.com;
root /home/ubuntu/apps/YOUR_RAILS_APP_staging/current/public;
access_log /home/ubuntu/apps/YOUR_RAILS_APP_staging/current/log/nginx.access.log;
error_log /home/ubuntu/apps/YOUR_RAILS_APP_staging/current/log/nginx.error.log info;
location ^~ /assets/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
try_files $uri/index.html $uri @staging;
location @staging {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://staging;
}
error_page 500 502 503 504 /500.html;
client_max_body_size 10M;
keepalive_timeout 10;
}
cap production deploy:initial
cap staging deploy:initial
scp /config/master.key YOUR_REMOTE_USER@YOUR_REMOTE_IP:/home/YOUR_REMOTE_USER/apps/YOUR_APP_NAME_production/shared/config/
scp /config/master.key YOUR_REMOTE_USER@YOUR_REMOTE_IP:/home/YOUR_REMOTE_USER/apps/YOUR_APP_NAME_staging/shared/config/
/etc/nginx/sites-enabled
# the default remote config, you can backup it first
sudo rm /etc/nginx/sites-enabled/default
# symlink new configuration file
sudo ln -nfs "/home/deploy/apps/YOUR_APP_NAME_production/current/config/nginx/nginx_production.conf" "/etc/nginx/sites-enabled/YOUR_APP_NAME_production"
sudo ln -nfs "/home/deploy/apps/YOUR_APP_NAME_production/current/config/nginx/nginx_staging.conf" "/etc/nginx/sites-enabled/YOUR_APP_NAME_staging"
sudo service nginx restart
cap production deploy
cap staging deploy
cap production / staging puma:status
cap production / staging puma:start
cap production / staging puma:stop
cap production / staging puma:restart
tài liệu tham khảo: capistranorb nginx how-to-deploy-ruby-on-rails-apps-on-aws-ec2
All rights reserved