Software engineering notes

Rails Installation And Deployment

Installation

(最後更新: 2016-04-14)

[1] Update & Upgrade

sudo apt-get update
sudo apt-get upgrade -y

[2] Install RVM (Ruby Version Manager)

Install curl (MacOS doesn’t need to execute this)

sudo apt-get install curl

Install RVM

\curl -sSL https://get.rvm.io | bash -s stable

讀取 rvm

source ~/.rvm/scripts/rvm

安裝 rvm 自己相依的東西

rvm requirements

[3] Install Ruby

rvm install ruby
rvm use ruby --default

[4] Install RubyGems

rvm rubygems current

[5] Install rails

gem install rails

安裝 rails 的 doc 很久, 可以加上 -no-rdoc --no-ri 忽略 doc

[6] 安裝 node.js

sudo apt-get install nodejs

or mac

brew install node

[7] Test

cd /tmp
rails new rails_test
cd rails_test
rails s

預設 port 是 3000

Upgrade 己存在專案的 Rails 版本

安裝最新版本的 Rails

gem install rails

修改 Gemfile, 改成指定版本

gem 'rails', '4.2.3'

Update 專案引入的套件

bundle update

Deployment

(最後更新: 2016-04-14)

[1] 安裝 Passenger + Nginx

安裝 passenger

sudo apt-get install libcurl4-openssl-dev       # passenger 需要
gem install passenger

安裝 nginx

rvmsudo passenger-install-nginx-module          # 用 passenger 安裝 nginx

如果安裝 passenger-install-nginx-module 發生錯誤

/home/web-admin/.rvm/rubies/ruby-2.3.0/lib/ruby/2.3.0/rubygems/specification.rb:2158:in `method_missing': undefined method `this' for #<Gem::Specification:0xdf627c passenger-5.0.27> (NoMethodError)
from /home/web-admin/.rvm/rubies/ruby-2.3.0/lib/ruby/2.3.0/rubygems/specification.rb:1057:in `find_active_stub_by_path'
from /home/web-admin/.rvm/rubies/ruby-2.3.0/lib/ruby/2.3.0/rubygems/core_ext/kernel_require.rb:64:in `require'
from /home/web-admin/.rvm/gems/ruby-2.3.0/gems/passenger-5.0.27/bin/passenger-install-nginx-module:33:in `<top (required)>'
from /home/web-admin/.rvm/gems/ruby-2.3.0/bin/passenger-install-nginx-module:23:in `load'
from /home/web-admin/.rvm/gems/ruby-2.3.0/bin/passenger-install-nginx-module:23:in `<main>'
from /home/web-admin/.rvm/gems/ruby-2.3.0/bin/ruby_executable_hooks:15:in `eval'
from /home/web-admin/.rvm/gems/ruby-2.3.0/bin/ruby_executable_hooks:15:in `<main>'

看起來可能是我預設用 ruby-2.3 發生問題,所以先降回 ruby-2.2

rvm install ruby-2.2.4
rvm use ruby-2.2 --default

再安裝一次就成功了!

[2] 安裝成功後設定根目錄

建立 /var/www 目錄

設定 /opt/nginx/conf/nginx.conf, 將 location / { 範圍內註解掉, 並在 http { 內加上 :

error_log /var/www/rails_app/log/nginx_error.log;
access_log /var/www/rails_app/log/nginx_access.log;
server {
    listen 80;
    server_name 106.185.47.26;  # or domain name
    root /var/www/rails_app/public;
    passenger_enabled on;
}

[3] 安裝 nginx 指令

如果有開 tmux 記得關掉再執行 :

cd /tmp
wget -O init-deb.sh https://www.linode.com/docs/assets/660-init-deb.sh
sudo mv init-deb.sh /etc/init.d/nginx
sudo chmod +x /etc/init.d/nginx
sudo /usr/sbin/update-rc.d -f nginx defaults

start

sudo /etc/init.d/nginx start
or
sudo service nginx start

[4] 把 code 放到 /var/www

bundle install

如果顯示 bundle 沒安裝,執行:gem install bundle

[5] 環境

development :

rake db:migrate RAILS_ENV=development

production :

  1. 產生 Key

    rake secret # 產生key

  2. 設定 secret, 有兩種方式, 擇一就好

第一種

config/secrets.yml
    production:
      secret_key_base: cf2d4472039660a31a002b21cd3ded0cf7cc2c5a0d82f24dcdf5097b79c1900241f97eb85542f8e4a349f32fac37b618bc663b21f16de2706bb897885d6cc3f0

第二種

1) nginx.conf :
    passenger_env_var SECRET_KEY_BASE "cf2d4472039660a31a002b21cd3ded0cf7cc2c5a0d82f24dcdf5097b79c1900241f97eb85542f8e4a349f32fac37b618bc663b21f16de2706bb897885d6cc3f0";

2) config/secrets.yml
    production:
      secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
  1. DB migrate + Assets precompile

First time :

RAILS_ENV=production rake db:create
RAILS_ENV=production rake db:migrate

Update code :

RAILS_ENV=production bundle exec rake assets:precompile
  1. Restart web server

    sudo service nginx restart

Troubleshootings

出現錯誤 500 We're sorry, but something went wrong.

  1. 判斷是 nginx 的 500 還是 Rails 的 500 (看頁面的 html 及 css 可以判斷)

  2. 500 的話先看, 目錄權限有沒有問題, www.example.com/robots.txt 讀取 public/robots.txt 看通不通

注意, 如果放在 /root 下, 因為 /root 的權限還是 root 的, 即使網站 foler 改成 www-data 也沒用, 建議放在 /var/www 下, /var/www 權限記得要給 www-data

nginx 預設 user 是 nobody, 建議改成 www-data, 並且確定網站根目錄的權限也是 www-data

  1. 當 nginx 及 rails log 都沒有異樣, 執行 RAILS_ENV=production rails c 看有沒有錯誤, 如果有錯誤會導致 nginx 的 500

  2. 檢查在 development 環境是否正常 rails s -b 0.0.0.0

  3. 檢查 production 是否正常 RAILS_ENV=production rails s -b 0.0.0.0

確定有做 assets precompile, 如果 public/assets 有檔案但 404

environments/production.rb, 改成 true :

config.assets.compile = true

確定網頁都沒有 404 等等之類的問題

  1. 再回去看 log/production.log 有沒有異常

很有可能會發生內建的 http server : WEBrick 執行的權限是夠的, 但 nginx 執行權限不夠導致錯誤

I18n 導致錯誤

I, [2015-08-22T06:53:22.272463 #7927]  INFO -- : Completed 500 Internal Server Error in 490ms (ActiveRecord: 0.0ms)
F, [2015-08-22T06:53:22.273759 #7927] FATAL -- :
I18n::InvalidLocaleData (can not load translations from /usr/local/rvm/gems/ruby-2.2.1/gems/devise-i18n-views-0.3.4/lib/../locales/pt-PT.yml: #<Errno::EACCES: Permission denied @ rb_sysopen - /usr/local/rvm/gems/ruby-2.2.1/gems/devise-i18n-views-0.3.4/lib/../locales/pt-PT.yml>):
  app/controllers/application_controller.rb:18:in `set_locale'

調整權限

chmod -R 777 /usr/local/rvm/gems/ruby-2.2.1/gems

沒有 permission 問題後, 網頁就能 work 了

403 Forbidden

以下有幾個方向可以找出問題在哪裡 :

完整的 nginx.conf

/opt/nginx/conf/nginx.conf :

user web-admin;
worker_processes  1;

events {
    worker_connections  1024;
}


http {
    passenger_root /usr/local/rvm/gems/ruby-2.2.1/gems/passenger-5.0.15;
    passenger_ruby /usr/local/rvm/gems/ruby-2.2.1/wrappers/ruby;

    include       mime.types;
    default_type  application/octet-stream;

    sendfile        on;

    keepalive_timeout  65;

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

    server {
        listen 443 ssl;
        ssl_certificate /opt/nginx/ssl/example_combined.crt;
        ssl_certificate_key /opt/nginx/ssl/example.key;

        client_max_body_size       50M;

        listen       80;
        server_name  example.com;

        # non-www redirect to www
        if ($host = $server_name) {
            return 301 https://www.$server_name$request_uri;
        }

        # 將 http 導到 https
        if ($scheme = http) {
            return 301 https://www.$server_name$request_uri;
        }

        # 注意 owner 可能引發 500
        root /var/www/example/public;
        passenger_enabled on;
        rails_env production;

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }

    server {
        listen 3000;
        server_name dev.example.com;

        client_max_body_size       50M;

        # 注意 owner 可能引發 500
        root /var/www/example/public;
        passenger_enabled on;
        rails_env development;
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}

其他

關閉 Development 環境的錯誤訊息

config/environments/development.rb

config.consider_all_requests_local       = false

重啟 Rails app

在網站根目錄下新增

touch tmp/restart.txt

Reload 頁面就會觸發重新啟動

Once Passenger has noticed that the file’s timestamp has changed, it will restart the application.