Jex’s Note

Deploy Rails

(最後更新: 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
  • 安裝在預設路徑 /opt/nginx, 千萬不要改, 免得 nginx 指令會無效
  • 如果有出現 export rvmsudo_secure_path=1 執行它
  • 記憶體太少可能會導致安裝失敗, 如果顯示要你增加 swap 可參考此篇

如果安裝 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;
}
  • nginx 執行時的 user 可以不用特別指定, 預設是
  • 如果要跑 development 環境則加上 rails_env development;

[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"] %>

3) 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

4) Restart web server

sudo service nginx restart

網頁不通

出現錯誤 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

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

4) 檢查在 development 環境是否正常 rails s -b 0.0.0.0

5) 檢查 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 等等之類的問題

6) 再回去看 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 看看有沒有出現什麼異常的訊息,有可能 passenger_root 路徑設定錯導致找不到檔
  • 確定網站根目錄的權限是 nginx 可以執行的
  • 去 nginx 的 error log 看看有沒有線索

完整的 nginx.conf

  • 區分 dev (3000 port) / production 環境 / ssl
  • passenger_root : 可用 passenger-config --root 得知
  • passenger_ruby : 可用 passenger-config --ruby-command 得知

/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.

Comments