配置 unicorn 和 nginx 运行 Redmine

Redmine 支持多种服务器配置, Web 服务器可选择 nginxapache, Ruby 应用服务器可选择 unicorn, passenger, pumathin

Easy Redmine官方安装文档推荐使用 nginx + unicorn 运行 Easy Redmine 并给出了详细的安装配置手册。本文记录配置 unicorn 和 nginx 运行 Redmine 的过程,包括常见问题和简单的问题排查方法。

环境

以下是配置前的环境:

  • 阿里云 1 核 2G 云服务器
  • Ubuntu 16.04.5 LTS (GNU/Linux 4.4.0-117-generic x86_64)
  • nginx 1.10.3-0ubuntu0.16.04.3
  • rvm 1.29.4
  • ruby 2.4.4p296 (2018-03-28 revision 63013) [x86_64-linux]
  • Rails 4.2.8
  • Redmine 3.4.6
  • Redmine 运行用户: redmine
  • Redmine 工作目录: /data/redmine/redmine

配置 unicorn

安装 unicorn

unicorn 可以作为一个 gem 单独安装,如:

gem install unicorn

也可以只安装在当前 Redmine 环境中

cat >> /data/redmine/redmine/Gemfile.local << EOF
gem 'unicorn'
EOF
cd /data/redmine/redmine
bundle install --without development test

生成 unicorn 配置文件

执行以下命令生成 unicorn 配置文件,文件名为 /data/redmine/redmine/config/unicorn.rb。

需要注意的是:

  • worker_processes 建议设置为与CPU核数一致
  • Web 服务器运行用户 (www-data 或 nginx) 和 Redmine 运行用户 ( 本文中为 redmine) 应具有 redmine_unicorn.sock 的读写权限
cat > /data/redmine/redmine/config/unicorn.rb << EOF
app_home="/data/redmine/redmine"

worker_processes 2
timeout 3600
preload_app true

listen "/tmp/redmine_unicorn.sock", :backlog => 64
pid "/tmp/redmine_unicorn.pid"

stdout_path "#{app_home}/log/unicorn.log"
stderr_path "#{app_home}/log/unicorn.err"

before_fork do |server, worker|
  # Close all open connections
  if defined?(ActiveRecord::Base)
    ActiveRecord::Base.connection.disconnect!
  end

  old_pid = "#{server.config[:pid]}.oldbin"
  if old_pid != server.pid
    begin
      sig = (worker.nr + 1) >= server.worker_processes ? :QUIT : :TTOU
      Process.kill(sig, File.read(old_pid).to_i)
    rescue Errno::ENOENT, Errno::ESRCH
    end
  end
end

after_fork do |server, worker|
  # Reopen all connections
  if defined?(ActiveRecord::Base)
    ActiveRecord::Base.establish_connection
  end
end
EOF

生成服务脚本并配置为开机启动

以 root 权限执行以下命令生成服务脚本,需要注意修改脚本中的以下变量为实际值:

  • User
  • WorkingDirectory
  • PIDFile
  • ExecStart 中的命令字符串,尤其是其中的 unicorn 配置文件路径
cat > /etc/systemd/system/redmine.service << EOF
[Unit]
Description=Redmine server system service

[Service]
Restart=on-failure
Type=simple
User=redmine
WorkingDirectory=/data/redmine/redmine
Environment=RAILS_ENV=production
PIDFile=/tmp/redmine_unicorn.pid
ExecStart=/bin/bash -lc 'rvm default do unicorn -D -c /data/redmine/redmine/config/unicorn.rb -E production'

[Install]
WantedBy=multi-user.target

EOF

其中 ExecStart 中的命令字符串应根据 unicorn 的安装方式进行调整,上面的例子针对 unicorn 作为一个独立安装的 gem 的情况。而如果 unicorn 写入在 Gemfile.local 中,并执行了 bundle install, ExecStart 中的命令字符串应改为:

bundle exec unicorn -D -c /data/redmine/redmine/config/unicorn.rb -E production

可按照 redmine.service 中的 User 和 WorkingDirectory 执行 ExecStart 中的命令字符串,验证命令能执行成功。

如果测试没有问题,以 root 权限执行以下命令启动服务并检查服务状态:

systemctl daemon-reload
systemctl start redmine.service
systemctl enable redmine.service
systemctl status redmine.service

如果一起正常,可以看到服务状态为正在运行,执行以下命令可以看到系统中多了若干 ruby 进程,进程数目与 unicorn 配置文件中的 worker_processes 数量相关。

ps -e | grep ruby

如果出现问题,可以查看 unicorn 配置文件中的指定的日志文件。

配置 nginx

以 root 权限新建文件 /etc/nginx/conf.d/redmine.conf, 文件内容可参考如下:

upstream unicorn {
  # for UNIX domain socket setups:
  server unix:/tmp/redmine_unicorn.sock fail_timeout=0;
}

server {
  listen        80;
  # the aplication will listen on all server names  
  server_name   _;
  error_log /var/log/nginx/redmine_error.log;
  access_log /var/log/nginx/redmine_access.log;

  root                          /data/redmine/redmine/public;
  try_files                     $uri @app;
  error_page                    500 502 503 504 /500.html;

  location @app {
    proxy_pass                  http://unicorn;
    proxy_set_header            Host $http_host;
    proxy_set_header            X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header            X-Forwarded-Proto $scheme;
    proxy_connect_timeout       600;
    proxy_send_timeout          600;
    proxy_read_timeout          600;
    send_timeout                600;
  }
}

其中:

  • sock 文件需要与 unicorn 配置文件一致
  • 主机名和监听端口号应与实际匹配

详细配置可参见 nginx 官网上的 ngx_http_upstream_module

以 root 权限重新加载 nginx 并查看启动状态:

service nginx reload
service nginx status

此时即可以通过浏览器访问 Redmine。

常见问题及处理

如果出现配置错误,有可能出现各种问题,此时应查看日志文件中描述的错误原因,有针对性的进行解决。

redmine.service 状态异常

问题原因有可能是:

  • Redmine 本身配置
  • unicorn 配置文件中有错误
  • redmine.service 中有错误

具体原因可查看 unicorn 配置文件指定的日志文件,或者逐步排查,如通过运行 redmine.service 中的启动命令排查问题:

su - redmine
cd ~/redmine
bundle exec unicorn -D -c /data/redmine/redmine/config/unicorn.rb -E production

连接 upstream 错误

在 nginx 日志文件中,出现以下错误:

2018/12/12 11:58:09 [crit] 1927#1927: *1 connect() to unix:/tmp/redmine_unicorn.sock failed (13: Permission denied) while connecting to upstream, client: 192.168.1.51, server: www.eaglesoftware.cn, request: "GET / HTTP/1.1", upstream: "http://unix:/tmp/redmine_unicorn.sock:/", host: www.eaglesoftware.cn, referrer: "https://www.eaglesoftware.cn/"

此时说明 Web 服务器运行用户没有 /data/redmine/redmine/redmine_unicorn.sock 文件的读写权限,可使用类似以下命令测试用户对文件的访问权限。

sudo -u www-data stat /data/redmine/redmine/redmine_unicorn.sock

Web 服务器运行用户可通过查看配置文件获取,如对 nginx, 可查看 /etc/nginx/nginx.conf 文件。

cat /etc/nginx/nginx.conf | grep user

注意 Web 服务器运行用户需要首先对存放 redmine_unicorn.sock 的目录具有执行权限,才可能访问该文件。一般通过以下方式可修复此错误:

  • 改动 redmine_unicorn.sock 的存储位置
  • 将 Web 服务器运行用户加入 redmine_unicorn.sock 文件所属的用户组
  • 运行 chmod 更改组或其它用户对该文件的访问权限
  • 运行 chmod 增加组或其它用户对 redmine_unicorn.sock 所在目录的执行权限
上一篇:简述Xml.Serialization如何序列化对象到XML文件


下一篇:python: 序列化/反序列化及对象的深拷贝/浅拷贝