如何在 Ubuntu 14.04 上使用 Puma 和 Nginx 部署 Rails 应用程序
介绍
当您准备好部署 Ruby on Rails 应用程序时,需要考虑许多有效的设置。本教程将帮助您部署 Ruby on Rails 应用程序的生产环境,以 PostgreSQL 作为数据库,在 Ubuntu 14.04 上使用 Puma 和 Nginx。
Puma 是一个应用程序服务器,就像 Unicorn 一样,它使您的 Rails 应用程序能够并发处理请求。由于 Puma 并非设计为供用户直接访问,我们将使用 Nginx 作为反向代理来缓冲用户与 Rails 应用程序之间的请求和响应。
先决条件
本教程假设您在将部署应用程序的用户上安装了 Ubuntu 14.04 服务器并安装了以下软件:
- Ruby on Rails,使用 rbenv
- 带 Rails 的 PostgreSQL
如果您还没有设置,请按照上面链接的教程进行操作。我们假设您的用户名为 deploy。
此外,本教程不包括如何设置您的开发或测试环境。如果您需要这方面的帮助,请按照 PostgreSQL with Rails 教程中的示例进行操作。
创建 Rails 应用程序
理想情况下,您已经有一个要部署的 Rails 应用程序。如果是这种情况,您可以跳过此部分,并在继续操作时进行适当的替换。如果没有,第一步是创建一个使用 PostgreSQL 作为其数据库的新 Rails 应用程序。
此命令将创建一个名为 \appname 的新 Rails 应用程序,它将使用 PostgreSQL 作为数据库。请随意将突出显示的 \appname 替换为其他内容:
rails new appname -d postgresql
然后切换到应用程序目录:
cd appname
让我们花点时间创建将由 Rails 应用程序的生产环境使用的 PostgreSQL 用户。
创建生产数据库用户
为了简单起见,让我们将生产数据库用户命名为与您的应用程序名称相同的名称。例如,如果您的应用程序名为 \appname,您应该像这样创建一个 PostgreSQL 用户:
sudo -u postgres createuser -s appname
我们要设置数据库用户的密码,所以进入PostgreSQL控制台是这样的:
sudo -u postgres psql
然后为数据库用户设置密码,示例中的\appname,如下所示:
\password appname
输入您想要的密码并确认。
使用以下命令退出 PostgreSQL 控制台:
\q
现在我们已准备好使用正确的数据库连接信息配置您的应用程序。
配置数据库连接
确保您位于应用程序的根目录中 (cd ~/appname
)。
在您喜欢的文本编辑器中打开应用程序的数据库配置文件。我们将使用 vi:
vi config/database.yml
更新 production
部分,使其看起来像这样:
production:
<<: *default
host: localhost
adapter: postgresql
encoding: utf8
database: appname_production
pool: 5
username: <%= ENV['APPNAME_DATABASE_USER'] %>
password: <%= ENV['APPNAME_DATABASE_PASSWORD'] %>
请注意,数据库用户名和密码配置为由环境变量APPNAME_DATABASE_USER
和APPNAME_DATABASE_PASSWORD
读取。将生产密码和秘密保存在应用程序代码库之外被认为是最佳实践,因为如果您使用 Git 等分布式版本控制系统,它们很容易暴露。接下来我们将讨论如何使用环境变量设置数据库身份验证。
保存并退出。
安装 rbenv-vars 插件
在部署生产 Rails 应用程序之前,您应该使用环境变量设置生产密钥和数据库密码。管理环境变量的一种简单方法是使用 rbenv-vars 插件,我们可以使用它在运行时将密码和机密加载到我们的应用程序中。
要安装 rbenv-vars 插件,只需切换到 .rbenv/plugins
目录并从 GitHub 克隆它。例如,如果 rbenv 安装在您的主目录中,请运行以下命令:
cd ~/.rbenv/plugins
git clone https://github.com/sstephenson/rbenv-vars.git
设置环境变量
现在安装了 rbenv-vars 插件,让我们设置所需的环境变量。
首先,生成密钥,用于验证签名 cookie 的完整性:
cd ~/appname
rake secret
复制生成的密钥,然后使用您喜欢的编辑器打开 .rbenv-vars
文件。我们将使用 vi:
vi .rbenv-vars
Rails 应用程序可以读取您在此处设置的任何环境变量。
首先,像这样设置 SECRET_KEY_BASE
变量(用您刚刚生成和复制的密码替换突出显示的文本):
SECRET_KEY_BASE=your_generated_secret
接下来,像这样设置 APPNAME_DATABASE_USER
变量(将突出显示的 \APPNAME 替换为您的应用程序名称,将 \appname 替换为您的生产数据库用户名):
APPNAME_DATABASE_USER=appname
最后,像这样设置 APPNAME_DATABASE_PASSWORD
变量(将突出显示的 \APPNAME 替换为您的应用程序名称,将 \prod_db_pass 替换为您的生产数据库用户密码):
APPNAME_DATABASE_PASSWORD=prod_db_pass
保存并退出。
您可以通过运行以下命令查看使用 rbenv-vars 插件为您的应用程序设置了哪些环境变量:
rbenv vars
如果您更改密码或数据库密码,请更新您的 .rbenv-vars
文件。请注意将此文件保密,不要将其包含在任何公共代码存储库中。
创建生产数据库
现在您的应用程序已配置为与您的 PostgreSQL 数据库通信,让我们创建生产数据库:
RAILS_ENV=production rake db:create
生成控制器
如果您按照示例进行操作,我们将生成一个脚手架控制器,以便我们的应用程序可以查看:
rails generate scaffold Task title:string note:text
现在运行此命令来更新生产数据库:
RAILS_ENV=production rake db:migrate
您还应该预编译资产:
RAILS_ENV=production rake assets:precompile
要测试您的应用程序是否工作,您可以运行生产环境,并将其绑定到您服务器的公共 IP 地址(替换您服务器的公共 IP 地址):
RAILS_ENV=production rails server --binding=server_public_IP
现在在 Web 浏览器中访问此 URL:
http://server_public_IP:3000/tasks
如果它工作正常,你应该看到这个页面:

返回您的 Rails 服务器,然后按 Ctrl-c
停止应用程序。
安装 Puma
现在我们准备安装 Puma。
一个简单的方法是将它添加到应用程序的 Gemfile
中。在您喜欢的编辑器中打开 Gemfile(确保您在应用程序的根目录中):
vi Gemfile
在文件末尾,使用以下行添加 Puma gem:
gem 'puma'
保存并退出。
要安装 Puma 和任何未完成的依赖项,请运行 Bundler:
bundle
Puma 现已安装,但我们需要对其进行配置。
配置 Puma
在配置 Puma 之前,您应该查看您的服务器拥有的 CPU 内核数。您可以使用此命令轻松地做到这一点:
grep -c processor /proc/cpuinfo
现在,让我们将 Puma 配置添加到 config/puma.rb
。在文本编辑器中打开文件:
vi config/puma.rb
将此配置复制并粘贴到文件中:
# Change to match your CPU core count
workers 2
# Min and Max threads per worker
threads 1, 6
app_dir = File.expand_path("../..", __FILE__)
shared_dir = "#{app_dir}/shared"
# Default to production
rails_env = ENV['RAILS_ENV'] || "production"
environment rails_env
# Set up socket location
bind "unix://#{shared_dir}/sockets/puma.sock"
# Logging
stdout_redirect "#{shared_dir}/log/puma.stdout.log", "#{shared_dir}/log/puma.stderr.log", true
# Set master PID and state locations
pidfile "#{shared_dir}/pids/puma.pid"
state_path "#{shared_dir}/pids/puma.state"
activate_control_app
on_worker_boot do
require "active_record"
ActiveRecord::Base.connection.disconnect! rescue ActiveRecord::ConnectionNotEstablished
ActiveRecord::Base.establish_connection(YAML.load_file("#{app_dir}/config/database.yml")[rails_env])
end
将 worker
的数量更改为服务器的 CPU 内核数量。
保存并退出。这会使用您的应用程序的位置及其套接字、日志和 PID 的位置来配置 Puma。随意修改文件,或添加您需要的任何其他选项。
现在创建配置文件中引用的目录:
mkdir -p shared/pids shared/sockets shared/log
创建 Puma Upstart 脚本
让我们创建一个 Upstart 初始化脚本,这样我们就可以轻松地启动和停止 Puma,并确保它会在启动时启动。
从 Puma GitHub 存储库将 Jungle Upstart 工具下载到您的主目录:
cd ~
wget https://raw.githubusercontent.com/puma/puma/master/tools/jungle/upstart/puma-manager.conf
wget https://raw.githubusercontent.com/puma/puma/master/tools/jungle/upstart/puma.conf
现在打开提供的 puma.conf
文件,这样我们就可以配置 Puma 部署用户了:
vi puma.conf
查找指定 setuid
和 setgid
的两行,并将 \apps 替换为您的部署用户和组的名称。例如,如果您的部署用户名为\deploy,这些行应该是这样的:
setuid deploy
setgid deploy
保存并退出。
现在将脚本复制到 Upstart 服务目录:
sudo cp puma.conf puma-manager.conf /etc/init
puma-manager.conf
脚本引用 /etc/puma.conf
它应该管理的应用程序。让我们现在创建和编辑该清单文件:
sudo vi /etc/puma.conf
此文件中的每一行都应该是您希望 puma-manager
管理的应用程序的路径。现在将路径添加到您的应用程序。例如:
/home/deploy/appname
保存并退出。
现在您的应用程序已配置为在引导时通过 Upstart 启动。这意味着即使在您的服务器重新启动后,您的应用程序也会启动。
手动启动 Puma 应用程序
要立即启动所有托管的 Puma 应用程序,请运行以下命令:
sudo start puma-manager
您还可以使用 puma
Upstart 脚本启动单个 Puma 应用程序,如下所示:
sudo start puma app=/home/deploy/appname
您还可以使用 stop
和 restart
来控制应用程序,如下所示:
sudo stop puma-manager
sudo restart puma-manager
现在,您的 Rails 应用程序的生产环境正在 Puma 下运行,并且正在监听 shared/sockets/puma.sock
套接字。在外部用户可以访问您的应用程序之前,您必须设置 Nginx 反向代理。
安装和配置 Nginx
使用 apt-get 安装 Nginx:
sudo apt-get install nginx
现在用文本编辑器打开默认服务器块:
sudo vi /etc/nginx/sites-available/default
用以下代码块替换文件的内容。请务必将突出显示的部分替换为适当的用户名和应用程序名称(两个位置):
upstream app {
# Path to Puma SOCK file, as defined previously
server unix:/home/deploy/appname/shared/sockets/puma.sock fail_timeout=0;
}
server {
listen 80;
server_name localhost;
root /home/deploy/appname/public;
try_files $uri/index.html $uri @app;
location @app {
proxy_pass http://app;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
}
error_page 500 502 503 504 /500.html;
client_max_body_size 4G;
keepalive_timeout 10;
}
保存并退出。这将 Nginx 配置为反向代理,因此 HTTP 请求通过 Unix 套接字转发到 Puma 应用服务器。随意进行任何您认为合适的更改。
重启 Nginx 使更改生效:
sudo service nginx restart
现在可以通过服务器的公共 IP 地址或 FQDN 访问 Rails 应用程序的生产环境。要访问我们之前创建的任务控制器,请在 Web 浏览器中访问您的应用程序服务器:
http://server_public_IP/tasks
您应该会看到与第一次测试您的应用程序时看到的相同页面,但现在它是通过 Nginx 和 Puma 提供服务的。
结论
恭喜!您已经使用 Nginx 和 Puma 部署了 Ruby on Rails 应用程序的生产环境。
如果您希望改进生产 Rails 应用程序部署,您应该查看我们关于如何使用 Capistrano 自动化部署的教程系列。该系列基于 CentOS,但它仍然有助于自动化部署。