[CentOS]: Redmine を nginx + unicorn で サブディレクトリ運用するメモ

# 要約
Redmine 4.1.x を CentOS8.1 上で動く httpdサーバ nginx とアプリケーションサーバ unicorn を使ってサブディレクトリ (/redmine) で動かすためのシンプルなメモ書き

## 注意
- メモ程度のため、nginx, ruby などの環境のインストール手順は割愛
- あくまでもサブディレクトリで動かすために若干いじった部分のみを備忘録として記載
- 下記前提と異なる場合は、本メモでも動かない可能性がある（環境依存性あり）

## 前提

||バージョンなど|
|:-----|:-----|
| OS |CentOS 8.1|
| HTTPサーバ | nginx mainline (1.17.10)|
| ruby | ruby 2.6.6p146 |
| redmine | 4.1.1 |
| redmine install directory | /var/lib/redmine |
| redmine URI | https://(YOURSITE)/redmine |

# インストールメモ
## unicorn インストールと設定
redmine のディレクトリに Gem.local ファイルを作り、unicorn を bundler 経由でいれる

```shell
# pwd
/var/lib/redmine

# vi Gemfile.local
gem "unicorn"

# bundler update
```

config ディレクトリの下にunicorn用ファイル unicorn.rb を作成する。概ね、後述のリンクサイトを参考にコピペ。ユーザーID, グループIDなどは各自環境で修正する。

ソケット名は、nginx の設定でも使うので合わせる。

```ruby:config/unicron.rb
# -*- coding: utf-8 -*-
# Unicorn設定ファイル
# 次のURLのサンプルをベースにしている。
# http://unicorn.bogomips.org/examples/unicorn.conf.rb

# 専用サーバーであればコアにつき1個以上を指定する。
worker_processes 2

# リクエスト待ち受け口、TCPとUNIXドメインとが指定可能。
listen "/var/lib/redmine/tmp/sockets/unicorn.sock", :backlog => 32
# listen 8282, :tcp_nopush => true

# タイムアウト秒数
timeout 30

# 稼働中のプロセスのPIDを書いておくファイル。
pid "/var/lib/redmine/tmp/pids/unicorn.pid"

# デーモンで起動すると標準出力／標準エラー出力が/dev/nullになるので、
# それぞれログファイルに出力する。
# /var/logで一元管理する場合はフルパスで記載、その場合は/var/log配下にunicornディレクトリを作っておく。
# stderr_path '/var/log/unicorn/unicorn.stderr.log'
# stdout_path '/var/log/unicorn/unicorn.stdout.log'
stderr_path 'log/unicorn.stderr.log'
stdout_path 'log/unicorn.stdout.log'

# マスタープロセス起動時にアプリケーションをロードする(true時)。
# ワーカープロセス側でロードをしないのでメモリ消費、応答性良好になる。
# ただし、ソケットはfork後に開きなおす必要あり。
# HUPシグナルでアプリケーションはロードされない。
preload_app true

# unicornと同一ホスト上のクライアントとのコネクション限定で、維持されているかを
# アプリケーションを呼ぶ前にチェックする。
check_client_connection false

before_fork do |server, worker|
  # Railsでpreload_appをtrueにしているときは強く推奨
  defined?(ActiveRecord::Base) and
    ActiveRecord::Base.connection.disconnect!
end

after_fork do |server, worker|
  # Railsでpreload_appをtrueにしているときは必須
  defined?(ActiveRecord::Base) and
    ActiveRecord::Base.establish_connection

  begin
    uid, gid = Process.euid, Process.egid
    user, group = "redmine", "redmine"
    ENV["HOME"] = "/home/redmine"
    target_uid = Etc.getpwnam(user).uid
    target_gid = Etc.getgrnam(group).gid
    worker.tmp.chown(target_uid, target_gid)
    if uid != target_uid or gid != target.gid
      Process.initgroups(user, target_gid)
      Process::GID.change_privilege(target_gid)
      Process::UID.change_privilege(target_uid)
    end
  rescue
    if RAILS_ENV = "development"
      STDERR.puts "could not change user, oh well"
    else
      STDERR.puts "could not change user, oh well"
      raise e
    end
  end
end
```

## unicorn のサービス化
unicorn は MariaDB 稼働後に動かす必要があるので、After の行にいれておく（mysqldな人は修正）。

サブディレクトリで運用する場合には、**ExecStartの行、bundle で動かす指定の --path=/redmine を付け忘れないように**！

`#  vi /usr/lib/systemd/system/unicorn.service`

```
[Unit]
Description=Redmine Unicorn Server
After=mariadb.service

[Service]
WorkingDirectory=/var/lib/redmine
Environment=RAILS_ENV=production
SyslogIdentifier=redmine
PIDFile=/var/lib/redmine/tmp/pids/unicorn.pid

ExecStart= /usr/local/rbenv/shims/bundle exec "unicorn_rails -c config/unicorn.rb -E production --path=/redmine"
ExecStop=/usr/bin/kill -QUIT $MAINPID
ExecReload=/bin/kill -USR2 $MAINPID

[Install]
WantedBy=multi-user.target
```
実際に動かして動作確認。問題ないようならサービスに登録する。

```
# systemctl start unicorn
# systemctl status unicorn
● unicorn.service - Redmine Unicorn Server
   Loaded: loaded (/usr/lib/systemd/system/unicorn.service; disabled; vendor preset: disabled)
   Active: active (running) since Fri 2020-05-15 17:59:16 JST; 1min 33s ago
 Main PID: 5873 (ruby)
    Tasks: 7 (limit: 25029)
   Memory: 116.9M
   CGroup: /system.slice/unicorn.service
           ├─5873 unicorn_rails master -c config/unicorn.rb -E production
           ├─5908 unicorn_rails worker[0] -c config/unicorn.rb -E production
           └─5910 unicorn_rails worker[1] -c config/unicorn.rb -E production

 5月 15 17:59:16 magi systemd[1]: Started Redmine Unicorn Server.

正しくうごいているようならサービスとして登録する

# sudo systemctl enable unicorn.service
Created symlink /etc/systemd/system/multi-user.target.wants/unicorn.service → /usr/lib/systemd/system/unicorn.service.
```

## nginx 側の設定
configファイルに redmine + unicorn 用の設定を追加する。https://(SITE)/redmine でアクセスするため、ssl (port:443) の server {...} 内に下記を追加する。

```
server {
    listen      443 ssl;
    server_name (YOUR-SITE-NAME);
    root        /var/www/html;
    (中略)

    #
    # for redmine + unicorn
    #
    location /redmine {
        alias /var/lib/redmine/public;
        try_files $uri/index.html $uri.html $uri @redmine;
    }

    location @redmine {
        proxy_redirect off;
	proxy_set_header X-Real-IP $remote_addr;
	proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
	proxy_set_header Host $http_host;
	proxy_connect_timeout 60;
	proxy_read_timeout 60;
	proxy_send_timeout 600;
	proxy_pass http://redmine;
    }
```

また、unicorn のソケット経由で受け渡すための指示も config に書く。こちらは、http {...} の中に記載する。

```
http {
    ##
    ## Ruby Application server Unicorn
    ##
    upstream redmine {
        server unix:/var/lib/redmine/tmp/sockets/unicorn.sock;
    }

    server {
       (中略)
```

あとは、nginx と unicorn を再起動して https://(YOUR-SITE)/redmine にアクセスできるか確認すればOK。

記載していないが、redmine のディレクトリの owner/group を redmine にしておくなど忘れずにしておく。

# 総評
ngnix + unicorn で動かすこと自体は難しくないが、サブディレクトリが絡むとどこになにを追加するかを間違えると、internal error や gateway error に悩まされ続けることになる。

ポイントは、
- unicorn 起動時にパスを指定する (--path=/redmine)
- nginx の configuration で location /redmine として書く
この2点をミスしなければ動く（はず）

はまりポイントとして、
- ソケット名の不一致
- redmine 動作のための User/Group 及びディレクトリの所有権
- 設定ファイル修正後の unicorn 再起動忘れ
あたり。時間あれば nginx, ruby あたりからのインストールメモも追加予定。

# Links

- [Centos7にNginx + UnicornでRedmine3.3構築方法](https://qiita.com/0ta2/items/d20e81b9395a654f6e55)
- [RedmineをCentOS 7上で動かすーUnicornとNginx編¶](https://www.torutk.com/projects/swe/wiki/RedmineをCentOS_7上で動かすーUnicornとNginx編)
- [CentOS7にRedmine3.2を入れ、nginx、unicornで動かす。](https://qiita.com/bikun_bikun/items/30951573fc900d78d0c9)