Skip to content

how to deploy rails to ubuntu1404 with rails template

yafei lee edited this page Aug 25, 2022 · 38 revisions

使用 rails template 布署到你的 Ubuntu 14.04 或者 Ubuntu 16.04 服务器

rails-template 是一套全栈式的解决方案, 基于它的布署是非常快速, 安全的.

Ubuntu14.04 / 16.04 LTS 是目前最稳定且常见的发布版本, 推荐使用.

下文基于 rails-template 来说明它的最佳布署实践.

表达惯例

# 开头代表该命令使用 root 权限执行.

$ 开头代表该命令使用 ruby 用户权限执行.

从 root 切换至 ruby 用户, 使用 su - ruby, - 的作用可以确保 ruby 用户的环境变量的正确加载.

如果命令中有 xxx, 请自行替换为自己的项目名称.

基本

获取 root 用户

本地执行

(本地命令)
$ ssh root@yourserverip

输入密码确保登录成功.

准备工作

更新源, 并安装必需的用户.

# apt-get update
# apt-get install -y 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 imagemagick libmagickwand-dev

创建新用户 ruby

# adduser ruby ( 不要使用 useradd )

随便输入一个复杂密码即可, 因为后续我们只使用 ruby 用户的 sshkey 登录方式.

在 ruby 用户下安装 rbenv + ruby 环境

# su - ruby

第一步, 安装 rbenv ( https://github.com/rbenv/rbenv )

以下是关键安装步骤

$ git clone https://github.com/rbenv/rbenv.git ~/.rbenv
$ git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
$ git clone https://github.com/andorchen/rbenv-china-mirror.git ~/.rbenv/plugins/rbenv-china-mirror( 可选, 将下载切换至 ruby.taobao.org 速度会超快 )

$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
$ echo 'eval "$(rbenv init -)"' >> ~/.bashrc
$ echo 'source ~/.bashrc' >> ~/.bash_profile
$ source ~/.bash_profile

$ rbenv install 2.5.3
$ rbenv global 2.5.3
$ rbenv rehash

第二步,安装 rails 依赖 gembundler

$ gem sources --add https://gems.ruby-china.com/ --remove https://rubygems.org/ ( 可选 )
$ echo "gem: --no-document" > ~/.gemrc ( 可选 )
$ gem update --system
$ gem install bundler
$ bundle config mirror.https://rubygems.org https://gems.ruby-china.com ( 可选 )

mina & setup

准备发布目录

# mkdir -p /data/www/
# chown ruby:ruby /data/www

准备无密码登录

$ ssh-keygen
$ vi ~/.ssh/authorized_keys ( 然后复制本机的 id_rsa.pub 内容写入. )

新打开本地终端, 测试是否ok:

(本地命令)
$ ssh ruby@yourserverip

无须密码即可登录, 说明已经配置成功.

准备github clone 权限

$ cat ~/.ssh/id_rsa.pub

将输出复制到 github 仓库的 deploy key 里, 保证发布环境主机能 clone 仓库.

测试方法:

$ git clone xx.git

确保能够克隆代码

准备 postgresql

# apt-get install -y postgresql libpq-dev

postgresql user 设置

( 最简单的一种方式是 将 /etc/postgresql/9.3/main/pg_hba.conf 里面的 md5 与 peer 统一改为 trust )

然后重启 postgresql

# service postgresql restart

安装 redis

# apt-get install redis-server

安装 nodejs ( 用来编译 assets 使用 )

# curl -sL https://deb.nodesource.com/setup_14.x | sudo -E bash -
# apt-get install -y nodejs

安装 yarn ( 用来编译 webpacker 使用 )

# curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
# echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
# apt-get update
# apt-get install -y yarn
$ yarn config set registry https://registry.npm.taobao.org ( 可选, 切换到 ruby 用户目录执行 )

在本地的主机执行: $ mina setup

根据提示, 到服务器修改对应的配置 application.ymldatabase.yml, 可以分别参考 application.yml.exampledatabase.yml.example

$ vi /data/www/xxx/shared/config/application.yml
$ vi /data/www/xxx/shared/config/database.yml

开始发布

调整 config/deploy/production.rb 的配置后, 可以开始第一次发布了.

发布任务往往第一次会失败, 为了方便调试和追踪, 可以先进行一次冒烟

(本地)$ mina first_deploy

如果一切顺利, 进入正式发布流程.

(本地)$ mina deploy

发布成功后, 开始配置 nginx

为了确保 action cable 可以正确工作, 需要 nginx 版本不低于 1.9

nginx 安装与配置

# add-apt-repository ppa:nginx/stable
# apt-get update
# apt-get install nginx
# nginx -v ( > 1.9 )
# cp /data/www/xxx/current/config/nginx.conf.example /etc/nginx/conf.d/xxx.conf

调整里面的 server_name 指向自己的域名

# nginx -s reload

在本地浏览器打开 http://yourserverdomain 来检查是否发布成功.

其他最佳实践

服务器安全

我们采用 ufw 来作为防火墙, 简单而不失安全.

ufw 配置, 打开 22, 80, 443 端口

# ufw allow 22/tcp
# ufw allow 80/tcp
# ufw allow 443/tcp
# ufw enable

这样, 可以防止大部分的入侵了.

cdn 配置

CDN 可以大大加速应用的访问速度, 使用一个 CDN 服务后( 例如又拍云或七牛云 ), 拿到回源后的CDN地址.

在线上 application.yml 配置如下:

CDN: ''

添加以下代码到: config/environments/production.rb

if ENV['CDN'].present?
  config.action_controller.asset_host = ENV['CDN']
end

重新编译 assets

$ cd /data/www/xxx/current
$ RAILS_ENV=production bundle exec rake assets:precompile

刷新页面, 检查静态资源是否正确显示, 即可.

monit 监控

# apt-get install monit
# cp /data/www/xxx/current/config/monit.conf.example /etc/monit/conf.d/xxx.conf

(可选, 集成 slack 通知)

logrotate 日志分割

rails-template 默认集成了日志分割工具, 确保在长期运行过程中日志不会无限增加. 默认的配置逻辑是每天切一份, 保留最近七天的日志.

# cp /data/www/xxx/current/config/logrotate.conf.example /etc/logrotate.d/xxx

测试一下

# logrotate -f /etc/logrotate.d/xxx

如果有安全问题, 请在配置中添加 su ruby ruby, 然后重试.

连接数限制

如果你的应用使用了 actioncable, 必须确保连接数支持限制打开. 使用

$ ulimit -Sn
$ ulimit -Hn

来检查. 输出值都应该设置为 65535. 如果不是, 请修改 limits.conf 配置.

# vi /etc/security/limits.conf

添加以下内容

root soft nofile 65535
root hard nofile 65535
* soft nofile 65535
* hard nofile 65535

然后使用上述命令再次检查输出结果, 确保成功.

异常通知

推荐使用 exception_notification + slack 做异常监控.

参考代码如下:

Gemfile 添加:

gem 'exception_notification'
gem 'slack-notifier'

执行: bundle install

application.yml.example 添加:

# exception notification
EXCEPTION_SLACK_WEBHOOK: ''
EXCEPTION_USERNAME: ''

config/environments/production.rb 中添加:

  if ENV['EXCEPTION_SLACK_WEBHOOK'].present?
    config.middleware.use ExceptionNotification::Rack,
      :slack => {
        :webhook_url => ENV['EXCEPTION_SLACK_WEBHOOK'],
        :channel => "#exceptions",
        :username => ENV['EXCEPTION_USERNAME'].presence || 'webhook',
        :additional_parameters => {
          :mrkdwn => true,
        }
      }
  end

发布之前, 别忘了在线上的 shared/config/application.yml 中添加 EXCEPTION_SLACK_WEBHOOK 的配置信息. 之后就可以了.

HTTPS SSL 支持

我们推荐使用 let's encrypt 来生成 ssl 证书, 用 acme.sh 命令来具体操作.

开始之前, 需要确保你的网站应用已经正常可以访问: http://yourdomain.com , 这在生成证书时需要校验.

安装:

# curl https://get.acme.sh | sh
source ~/.bashrc

生成证书( 将示例域名和目录替换成实际项目的域名和目录 ):

# acme.sh --issue -d yourdomain.com -w /data/www/xxx/current/public
# mkdir /etc/nginx/sslkeys

安装到 nginx 目录中( 将示例域名替换成实际域名 )

# acme.sh --installcert -d yourdomain.com --keypath /etc/nginx/sslkeys/yourdomain.com.key  --fullchainpath /etc/nginx/sslkeys/yourdomain.com.key.pem --reloadcmd "service nginx force-reload"

准备 dhparam( 安全协议 ):

# openssl dhparam -out /etc/nginx/sslkeys/dhparam.pem 2048
# cp /data/www/xxx/current/config/nginx.ssl.conf.example /etc/nginx/conf.d/xxx.ssl.conf

更新配置 /etc/nginx/conf.d/xxx.ssl.conf:

server_name yourdomain.com;

ssl_certificate  /etc/nginx/sslkeys/yourdomain.com.key.pem;
ssl_certificate_key /etc/nginx/sslkeys/yourdomain.com.key;
ssl_dhparam  /etc/nginx/sslkeys/dhparam.pem;

移除非 ssl 的配置

# rm /etc/nginx/conf.d/xxx.conf

数据备份

推荐使用 backup gem 来做数据备份, rails-template 已经准备好一份 backup.rb 的示例. 操作如下:

$ gem install backup -v '5.0.0.beta2'
$ backup generate:model --trigger xxx --archives --storages='local' --compressor='gzip'
$ cp /data/www/xxx/current/config/backup.rb.example ~/Backup/models/xxx.rb
$ backup perform --trigger xxx

这样已经将数据库与配置文件备份到 /data/www/backups 中了.

在实际使用中, 我们需要设定自动备份, 以及云端备份( 建议使用 FTP 上传模式 ), 那么操作如下:

先注释 ~/Backup/models/xxx.rb 中的 local 字段,打开 FTP 字段,调整其中的配置参数,然后往下看。

安装 whenever 并设定配置:

$ gem install whenever

schedule.rb 配置如下:

env :PATH, ENV['PATH']

every 1.day, :at => '02:00' do
  command "backup perform -t xxx"
end
$ cd ~/Backup
$ mkdir config
$ cp schedule.rb config/schedule.rb

生成 crontab 配置

$ whenever --update-crontab

使用 backup perform -t xxx 来检查是否备份成功.