Nic Lin's Blog

喜歡在地上滾的工程師

一鍵將 Rails App 佈署(Deploy)到 VPS 上

部屬前碎念

我有一個專案是抓subdomin在判斷群組,就像Logdown一樣依照次級網域來引導到不同使用者的部落格一樣,礙於某些因素將其專案從機器上搬出來,原本打算搬到Heroku,但發現naked domain實在是很難搞定,最後決定是搬到Amazon Ec2上面,因為過程其實做過很多次,常常健忘就把這些記錄下來。

網域申請我本身是使用Godaddy,他裡面的CNAME指向不能在heroku上面玩次級網址,因為heroku沒有Public IP給你使用,所以用EC2的彈性會好很多,畢竟服務不一樣。

Heroku是屬於PaaS 類型(Platform as a Service),支援特定語言或框架,幫你把很多細節處理好,一鍵部屬也不必多作設定。 Amazon EC2則是屬於IaaS 類型(Infrastructure as a Service),可以完整獲取Root權限,並進去機器裡面做設定,像是擁有一台電腦一樣。

實作部分

Amazon EC2如何申請是用這邊不多贅述,本篇只講部屬細節,這邊建議在選機器的時候,Oregon選擇離自家較近的東京機房,速度會好一些,機器的OS我個人建議選ubuntu,因為有被aws的linux稍微雷過XD。

登入VPS

參照ec2上面的connect方式,應該會如下,請用自己的pem跟vps ip進行連線,以下為範例

ssh -i "yourpem.pem" ubuntu@ec2-111-222-333-444.ap-northeast-1.compute.amazonaws.com

進入機器後,先創建部屬用的帳號,這邊盡量不要用root權限去做部屬比較妥當。

sudo adduser deploy
sudo adduser deploy sudo
su deploy

中間有設定密碼的部分請自行設定,有填資料的部分可以直接Enter過去。

然後為了方便我們登入deploy不需輸入密碼,我們先做ssh認證的部分。

ssh-keygen

中間一路enter過去採用default即可

cd
cd .ssh/
vi authorized_keys

然後將你電腦本地的.ssh/id_rsa.pub裡面的內容複製進去,並且存檔:wq

這樣你在進行登入的時候就不需輸入密碼,可以嘗試重新以deploy帳號登入aws ec2

ssh deploy@111.222.333.444

如果不用密碼就直接進去表示成功

安裝Ruby

這裡我是裝2.3.1,如果有不同版本再請自行修改

sudo apt-get update
sudo apt-get install git-core curl zlib1g-dev build-essential libssl-dev libreadline-dev libyaml-dev libsqlite3-dev sqlite3 libxml2-dev libxslt1-dev libcurl4-openssl-dev python-software-properties libffi-dev

再來安裝rbenv

cd
git clone https://github.com/rbenv/rbenv.git ~/.rbenv
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(rbenv init -)"' >> ~/.bashrc
exec $SHELL

git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
echo 'export PATH="$HOME/.rbenv/plugins/ruby-build/bin:$PATH"' >> ~/.bashrc
exec $SHELL

rbenv install 2.3.1
rbenv global 2.3.1
ruby -v

最後一步是安裝bundle工具,不然你的rails會沒辦法bundle install

gem install bundler

安裝Nginx + Passenger

sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 561F9B9CAC40B2F7
sudo apt-get install -y apt-transport-https ca-certificates

# Add Passenger APT repository
sudo sh -c 'echo deb https://oss-binaries.phusionpassenger.com/apt/passenger trusty main > /etc/apt/sources.list.d/passenger.list'
sudo apt-get update

# Install Passenger & Nginx
sudo apt-get install -y nginx-extras passenger

安裝完啟動Nginx

sudo service nginx start

因為我們的EC2需要將http prot打開才能看到網站,所以別忘記去設定 設定位置在SecurityGroup > 你的instance所使用的group > 下方的inbound選擇edit > 加入http並且save

由於我們的nginx已經啟動,也將http prot80打開,這時候我們將ec2給我們的public ip直接輸入網址,如果設定都正確就可以直接看到nginx為我們預設的首頁。

螢幕快照 2016-09-15 下午5.43.27.png

接著我們編輯nginx設定檔

sudo vim /etc/nginx/nginx.conf

在http的block裡面加入

passenger_root /usr/lib/ruby/vendor_ruby/phusion_passenger/locations.ini;

passenger_ruby /home/deploy/.rbenv/shims/ruby;

並且重新啟動nginx,如果有跳fail就要檢查一下語法是否錯誤。

sudo service nginx restart

創建你的Database

MySQL

sudo apt-get install mysql-server mysql-client libmysqlclient-dev

PostgreSQL

sudo apt-get install postgresql postgresql-contrib libpq-dev

基礎設定

sudo su - postgres
createuser --pwprompt
exit

關閉nginx預設的歡迎頁

sudo vi /etc/nginx/sites-available/default

將以下兩行用#註解掉

listen 80 default_server;
listen [::]:80 default_server ipv6only=on;

建立部屬所需的資料夾

我們預期將專案放在 /var/www/rails 裡面

cd
cd /var/
mkdir www
cd /var/www/
mkdir rails
sudo chown rails/

請將awesome_project替換成自己的專案名稱

sudo vi /etc/nginx/sites-available/awesome_project

並且輸入以下內容後:wq存檔離開

server {
  listen 80 default_server;
  server_name www.mydomain.com;
  passenger_enabled on;
  passenger_app_env production;
  root /var/www/rails/current/public;
}

注意的地方是

server_name 的地方,如果你沒有申請域名(例如www.domain.com),這行可以省略。

root 代表你的code放在哪,記得務必指向你rails資料夾當中的public資料夾。這邊的資料夾結構說明:

/var/www 是server預設的資料夾

/rails 是我們剛才的所設定的資料夾名稱,建議這邊的名稱和前面的資料夾名稱相同

/current 是capistrano佈署時所產生的資料夾,如果你沒打算用capistrano佈署,可以不用管這層的資料夾

/public 是rails當中的public資料夾,nginx這邊的設定必須指向一個public資料夾

將網站設定啟用

sudo ln -s /etc/nginx/sites-available/rails /etc/nginx/sites-enabled/rails
sudo nginx -s reload

本機安裝Capistrano

group :development do
  gem 'capistrano'
  gem 'capistrano-bundler', '~> 1.1.2'
  gem 'capistrano-rails'
  gem 'capistrano-passenger'
  gem 'capistrano-rbenv', github: "capistrano/rbenv"
 end
 
 #使用mysql可以加入這行
 
 gem 'mysql2', '0.3.18'

執行bundle install之後

安裝capistrtano

cap install

將會產生所需的設定檔。

設定Capistrano

接著進行設定,進入config/deploy.rb,改成你想要的設定:

set :application, "rails"
set :repo_url, "git@bitbucket.org:motionex/rails.git"

使用capistrano會搭配使用git,如果你的專案是private的,建議放到Bitbucket,就不會變成public專案。否則放在github即可。

回到設定檔中,以下是原本註解掉或不存在的設定,請刪除註解或補上:

set :linked_files, fetch(:linked_files, []).push('config/database.yml', 'config/secrets.yml')
set :linked_dirs, fetch(:linked_dirs, []).push('log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'vendor/bundle', 'public/system')

role :web, %w{deploy@111.222.333.444} #這裡輸入你的EC2 IP

設定好之後我們可以用capistrano來進行檢查

cap production deploy:check

由於capistrano是使用ssh登入vps主機,所以前面如果沒設定錯誤,在這個步驟並不會叫你輸入密碼。

設定database.yml及secrets.yml

因為github上面的專案會有安全性的問題,畢竟沒付費的public專案是誰想看就能看得到的,所以良好的撰寫習慣會將這兩隻檔案加入.gitignore,也因為這樣在部屬的時候會少這兩隻檔案,所以我們必須在vps裡面先設定好這兩隻檔案,當capistrano上傳專案時,直接用替換方式做覆蓋。

cd /var/www/rails
mkdir shared
mkdir shared/config
touch shared/config/database.yml
touch shared/config/secrets.yml

並且將database以及secrets的設定訊息填入。

參考如下

production:
  adapter: mysql2
  encoding: utf8
  database: your_database_name
  pool: 25
  host: 127.0.0.1
  encoding: utf8
  username: your_username
  password: your_password
  port: 3306
production:
  secret_key_base: 一堆亂碼

都設定好就可以執行

cap production deploy

Rails設定

接下來請連線到VPS進行Rails的設定,如果剛剛的mysql還沒有創建Database 請輸入

mysql -u root -p
#然後輸入密碼
CRETAE DATABASE 資料庫名稱;

接下來

cd /var/www/rails/current
RAILS_ENV=production rake db:create
RAILS_ENV=production rake db:migrate
sudo service nginx restart

這時打開瀏覽器,應該可以看到Rails成功部屬了。

備註: 1. 如果部屬空專案會出現404,請自行設定root route讓網頁能正常導向。 2. 如果重開機以後瀏覽器顯示Incomplete response received from application,代表secrets的hash有問題,可用以下步驟解決: * 執行$rake secret * 複製產生的一長串hash * 到/var/www/rails/shared/config/secrets.yml檔案當中,將原本production底下的secretkeybase換成新的hash即可。

參考連結: * 將Rails佈署(Deploy)到VPS上 * Deploy Ruby On Rails on Ubuntu 14.04 Trusty Tahr * Ruby on Rails實戰聖經之網站佈署

comments powered by Disqus