將Rails佈署(Deploy)到VPS上
一般來說,Rails佈署是非常麻煩的事情,尤其整個技術的變遷實在太過快速,很多網路上的資料都舊了。自己最近在研究佈署,發現很多資料都已經過期,在這邊彙整自己將Rails佈署到VPS上的心得。以下示範的是非常精簡的版本,沒有效能調教、沒有安全措施,基本上就只是個能動、稍微對Ruby增加一點彈性的佈署結果。如果有需要更深入的佈署,網路上有非常多關於主機調教的教材。
本機環境:Mac OSX 10.9
Capistrano版本:3.4.0
VPS主機:Digital Ocean
遠端主機作業系統:Ubuntu 14.04
遠端Ruby版本:2.2.0
遠端Rails版本:4.1.2
遠端資料庫:mysql
Web Server:nginx
App Server:passenger
0.登入VPS
首先,在Digital Ocean開啟一個新的droplet,這在任何VPS應該都相同,接著利用terminal的ssh登入該主機。
$ssh [email protected]
請將111.222.333.444
換成你的主機ip。
1.切換至新的user
所有事情用root來做,事後都會有權限的問題需要解決,因此登入後第一件事情就是開另一個user來用。
$adduser motionex
(新增user需要輸入密碼)
$sudo usermod -aG sudo motionex
$su motionex
請將motionex
換成你想要的使用者名稱,第二步是給予該user root權限。
2.安裝必要套件
利用Ubuntu標準動作apt-get安裝必須要用的套件,內容繁多這邊就直接列表。
$sudo apt-get update
$sudo apt-get -y install build-essential libssl-dev libyaml-dev libreadline-dev openssl curl git-core zlib1g-dev bison libxml2-dev libxslt1-dev libcurl4-openssl-dev libsqlite3-dev sqlite3 mysql-common mysql-client libmysqlclient-dev mysql-server
沒有意外的話會下載及安裝許多套件,另外安裝mysql時他會向我們詢問密碼,同樣輸入即可。
3.安裝nginx
一般來說也可以用apt-get安裝,但可能會安裝到過期的版本,這邊是用Railscast上另外新增repo的安裝方式。
$ sudo add-apt-repository ppa:nginx/stable
$ sudo apt-get -y update
$ sudo apt-get -y install nginx
如果安裝完成正確無誤,可執行:
$ sudo service nginx start
並打開瀏覽器,輸入主機的ip位置,就會出現Welcome to nginx的頁面。
4.安裝node.js
如同我們一般在Rails教學上所學到的,要執行Ruby,也要先安裝Node.js
$ sudo add-apt-repository ppa:chris-lea/node.js
$ sudo apt-get -y update
$ sudo apt-get -y install nodejs
安裝完成以後輸入:
$node -v
只要有出現版本號,就代表安裝成功。
5.安裝rbenv
許多教學為了避免安裝過多其他套件,導致離題,因此都是直接從Ruby官網提供的版本,利用make指令來安裝Ruby。但這未來會有一個比較麻煩的問題是如果要更新Ruby會比較麻煩。這邊安裝rbenv,要切換版本比較方便,且安裝過程也不麻煩。執行Railscast建議的rbenv-installer:
$ curl -fsSL https://github.com/rbenv/rbenv-installer/raw/master/bin/rbenv-installer | bash
正確的指令請參考rbenv-installer官方repo。如果指令有改,請以repo當中的為主。安裝完成以後請繼續執行:
$ nano ~/.bashrc
在這個檔案中,我們要在最前面加上一段rbenv指定要加上的code:
export RBENV_ROOT="${HOME}/.rbenv"
if [ -d "${RBENV_ROOT}" ]; then
export PATH="${RBENV_ROOT}/bin:${PATH}"
eval "$(rbenv init -)"
fi
加上以後,按ctrl + x
離開,並按大寫Y
儲存,再按一下Enter
確定儲存離開。這邊用的是nano編輯器,你也可以用自己喜歡的編輯器貼上code。接著執行:
$ source ~/.bashrc
$ rbenv --version
正確的話會出現版本號,代表安裝成功。接著安裝最新穩定版本的Ruby,目前是2.3.1:
$ rbenv install 2.3.1
$ rbenv rehash
$ rbenv global 2.3.1
$ ruby -v
正確無誤的話會看到Ruby版本顯示出來。
另外,ihower有說明直接安裝Ruby的方法,若不想安裝rbenv,也可參考他的內容,但本人依照他的教學一直安裝失敗,可能本人機器狀況不佳,人品也不好。
6.安裝passenger
雖然Ruby自己有提供passenger的gem,但passenger需要sudo權限,必須要在sudo底下再安裝一個ruby,比較麻煩,權限也很容易混淆,因此我們改用apt-get來安裝。
$ sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 561F9B9CAC40B2F7
$ sudo nano /etc/apt/sources.list.d/passenger.list
打開檔案以後,加入以下這行:
deb https://oss-binaries.phusionpassenger.com/apt/passenger trusty main
接著用同樣方式離開nano編輯器,使用ls
檢查該檔案的所屬人是誰,如果是你新開的帳號而非root,則我們要將該檔案的所有者改為root:
$ sudo chown root:root /etc/apt/sources.list.d/passenger.list
$ sudo chmod 600 /etc/apt/sources.list.d/passenger.list
接著從nginx外掛當中安裝passenger:
$ sudo apt-get update
$ sudo apt-get install nginx-extras passenger
7.確認Ruby路徑是否正確
安裝完成以後,有可能會將Ruby的連結打亂,因此檢查一下Ruby的路徑:
$ which ruby
正確的結果:/home/motionex/.rbenv/shims/ruby
錯誤的結果:/usr/bin/ruby
motionex
這個user名稱是我們在步驟1新增的,你電腦上顯示的會是你新增的名稱。
如果很不幸的路徑錯了,代表rbenv並沒有正常運作,請回到步驟5重新安裝一次rbenv。
8.將passenger掛到nginx上
打開nginx文件。
$ sudo nano /etc/nginx/passenger.conf
會看到以下兩行:
passenger_root /usr/lib/ruby/vendor_ruby/phusion_passenger/locations.ini;
passenger_ruby /usr/bin/ruby;
將第二行修改為rbenv的路徑,讓整個檔案變成:
passenger_root /usr/lib/ruby/vendor_ruby/phusion_passenger/locations.ini;
passenger_ruby /home/motionex/.rbenv/shims/ruby;
motionex
請改為你的帳號名稱。另外打開原本nginx的設定檔:
$ sudo nano /etc/nginx/nginx.conf
找到以下這行:
# include /etc/nginx/passenger.conf;
移除註解符號,讓他使用我們剛調整的passenger設定。
9.將原本的伺服器port關閉
這個步驟要做的事情是將原本我們在瀏覽器打開的welcome to nginx
頁面關閉。在terminal中輸入:
$sudo nano /etc/nginx/sites-available/default
找到以下兩行:
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
將這兩行的前面加上#
符號,註解掉,儲存以後伺服器就不會接收從預設的80 port進來的http request,再打開一次瀏覽器,應該會出現「無法顯示網頁」。
10.建立我們要佈署的rails資料夾
接下來我們要用同樣方式寫一個設定檔案,用來取代原本的設定檔。輸入:
$ sudo nano /etc/nginx/sites-available/rails
這個指令當中的rails
可以是任何名字,只要記得即可。打開以後在裡面填入:
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資料夾
11.將網站設定啟用
將剛剛的設定檔,設定一個link到nginx啟用網站的資料夾:
$ sudo ln -s /etc/nginx/sites-available/rails /etc/nginx/sites-enabled/rails
$ sudo nginx -s reload
重啟之後,這邊的設定就算完成了,接著要設定本機的rails app。
12.本機安裝capistrano
這邊回到本機,假設已經有一個準備好要佈署的專案(空專案也行),安裝 gem capistrano:
group :development do
gem 'capistrano-rails'
gem 'capistrano-passenger'
end
# 並加上稍後會使用的資料庫gem
gem 'mysql2'
並且
$ bundle
完成之後,在專案的根目錄底下產生capistrano設定檔:
$ cap install
會產生一些設定檔。
注意:capistrano可能因為版本的更新而造成指令不同,請在官方repo頁面確認正確的指令。
13.設定capistrano
接著進行設定,進入config/deploy.rb
,以下兩行原本就存在,請改成你想要的設定:
set :application, "rails"
set :repo_url, "[email protected]:my_accoung/rails.git"
使用capistrano會搭配使用git,如果你的專案是不開放的,建議放到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{[email protected]}
motionex
及後方的ip請換成自己的設定及VPS ip。
$ cap production deploy:check
capistrano會開始幫你檢查及調整VPS上的設定,可能會需要你輸入密碼。
首先會碰到的問題是你可能需要將本機的ssh key加到github或bitbucket上,才有可能進行佈署。 Bitbucket ssh文件說明Github ssh文件說明
如果你接下來看到一個錯誤訊息:
mkdir:
cannot create directory '/var/www/rails'
: Permission denied
恭喜你,前面的部份都過關了,接下來請進入下一個步驟來解決這個問題。
14.設定database.yml及secrets.yml
這段有點囉嗦,如果你真的很不在乎安全性,那可以跳過這段。但基本上把db密碼和網站的hash直接存放到git是很怪的事情,容易受到有心人的攻擊,所以我們要直接在VPS上建立設定檔,而不從本機佈署上去。
如果你的
config/database.yml
及config/secrets.yml
兩個已經push上去到repo過了,請加到.gitignore
中,並且用git rm --cache
指令來從repo當中刪除。
前一個步驟最後所產生的錯誤,是因為/var/www
底下需要有sudo權限才能編修檔案。我們需要先在VPS上把幾個必須的結構建立起來,capistrano才能幫我們完成剩下的工作。
請在回到VPS上,如果你的連線已經不見了,可重新用你的新帳號ssh連線回去,記得不要用root帳號。接著輸入:
$ cd /var/www
$ sudo mkdir rails
$ sudo chown motionex:motionex rails
最後一個指令是修改我們新開的資料夾權限為自己可以修改,以免佈署時權限不足,記得將motionex
改為自己的使用者帳號。
只要有權限問題,記得用
ls -l
指令檢查權限,並用chown
指令修改權限。
接著:
$ cd /var/www
$ mkdir rails/releases
$ mkdir rails/shared
$ mkdir rails/shared/config
$ touch rails/shared/config/database.yml
$ touch rails/shared/config/secrets.yml
打開你在本機的config/secrets.yml檔案,整個複製起來,並且回到VPS上我們剛剛建立的secrets.yml檔案當中,整個貼上。
而database.yml比較麻煩一點,因為我們要使用的是mysql資料庫,因此請在剛剛建立的database.yml當中寫入以下內容:
default: &default
adapter: mysql2
encoding: utf8
username: root
password: my_password
host: 127.0.0.1
port: 3306
development:
<<: *default
database: rails_development
test:
<<: *default
database: rails_test
production:
<<: *default
database: rails_production
其中的my_password
請設定為你剛剛安裝mysql時所設定的密碼,而三個資料庫名稱,也可以隨意取。
以上這個步驟是要把我們繞過git的檔案手動增加上伺服器上。
兩個檔案都增加完成以後,再回到本機執行:
$cap production deploy:check
正確無誤的話會看到完成檢查的訊息,此時可以正式執行:
$cap production deploy
就會快樂的看到他把檔案丟上去了,但目前連還不算佈署完成,本機依然需要一些Rails的相關設定。
15.Rails設定
接下來的步驟大家就應該都很熟悉了,請連線到VPS並進入rails資料夾:
$ cd /var/www/rails/current
$ gem install bundler
$ bundle
$ rake db:create
$ rake db:migrate
$ sudo service nginx restart
這時再打開瀏覽器,就會看到熟悉的rails首頁啦!
問題:如果你是佈署空專案的話,會出現404頁面,請加上一個首頁,用以確認佈署成功
問題:如果有遇到db無法create的問題,請確定'mysql'和'mysql2'兩個gem都有安裝在VPS上,執行
$gem install 'mysql'
即可
問題:如果重開機以後瀏覽器顯示
Incomplete response received from application
,代表secrets的hash有問題,可用以下步驟解決:
執行
$rake secret
複製產生的一長串hash
到
/var/www/rails/shared/config/secrets.yml
檔案當中,將原本production底下的secretkeybase換成新的hash即可。
如果有任何可以再精簡的地方或改善的地方,歡迎指正!
後續操作
參考資料
圖片來源
CC授權:WikiMedia