【2023年版】PassengerなんもわからんけどNginx+Passenger+PostgreSQL on Ubuntu 22.04でRedmine5.0.xを動かしてみた

# 変更履歴
それは、すまんの_(.__.)_の記録……
|項番|版|変更日|変更内容|
|:-:|:-:|:-:|:--|
|1|v1.0.0|2023-06-07|初版作成|
|2|v1.0.1|2023-06-10|nginxのpassenger設定を修正<br>シンボリックリンクのコマンドを修正|


# ITSが欲しい!!切実に
皆さんの会社は課題管理システム使ってますか?
私は
  * 自分のタスクの総量が把握できなくなる
  * どれから手を付けるか悩むときがある
  * 締め切りをしばしばプッチする
  * 炎上具合がわからない
というマネジメントダメダメマンなので「難しいことは全部システムに任せた!!」と今までやってきました。
この度、プロジェクト運営を考えていくうえで、上のようなお悩み点が噴出してしまい「もうやだ……Redmine入れよ……」と久しぶりに(5年ぶり4回目くらい) Ubuntu Server 22.04上にRedmineを構築してみました。
私史上初の試みで「ApacheもいいけれどNginxもよくない?」とちょっと調べてみたところ、NginxだとApacheでやっていた「httpの80番で受け取ったリクエストをRubyの3001番に回す」みたいなのをしないでNginxがAPサーバーみたいなことをしてくれるらしいので、その方向で構築してみました。

## 前提条件と環境
* 仮想環境: Hyper-V
* ホストOS: Windows10 (21H2)
* ゲストOS: Ubuntu 22.04 Jammy Jerryfish
* Nginx: 1.18.0
* Passenger: 6.0.17
* PostgreSQL: 14+238

## 作業手順

### 1. インストール用のisoのダウンロードと仮想マシンの作成
何はなくとも[公式からisoデータをダウンロード](https://ubuntu.com/download/server)してきます。
記事作成時点(2023年06月03日ですとUbuntu 23.04も公開されていますが、今回は以前触ってた(そしてGitLab運用してた)という理由でUbuntu 22.04を選択しました。
続いて、Hyper-Vマネージャーを開いて(Hyper-Vマネージャーの有効化については[こちら(Microsoft Learn)](https://learn.microsoft.com/ja-jp/virtualization/hyper-v-on-windows/quick-start/enable-hyper-v)を参照)第2世代で仮想マシンを作成していきます。
![世代の選択](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352775/096cc419-3c9e-7a5d-0018-1d5c95db981b.png)
![インストールメディアでisoファイルを設定](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352775/352469a7-4d8c-6d2c-378e-bf2deb003b3a.png)
久しぶりでハマったのが「トラステッド プラットフォーム モジュールを有効にする」にしないと上手いこと接続して画面が表示できなかったことでしょうか。
ウィザード作成後に「設定」を開いてここの設定。
![暗号化のサポートでTPMを有効にする](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352775/df610b39-3fc2-bcd5-0622-0bae141a7a99.png)


### 2. Ubuntuの起動と初期設定
Hyper-Vの仮想マシンが作成出来たら、さっそく起動していきます。
初期設定は普通で(参考サイトを[参考文献](#参考文献)に入れました)。途中で固定IPアドレス設定だけはしておきました。
更新をかけながらインストールすることもできますが、今回は「後でaptで更新しよう」という方針でインストールを優先。

### 3. 環境固有の設定
ここからはRedmine.JPさんのblog記事を参考に作業していきます。

#### 3.1 ロケールの設定
PostgreSQLで日本語を取り扱うための設定だそうです(latin1問題……苦しんだなぁ)
```bash:ロケールにja_JP.UTF-8を追加＆確認
$ sudo locale-gen ja_JP.UTF-8
$ locale -a
# こんな感じで"ja_JP.utf8が含まれる
C
C.UTF-8
POSIX
en_US.utf8
ja_JP.utf8
```
#### 3.2 タイムゾーンの設定
標準だと日本になっていないみたいなので、timedatectlで設定します。
```bash:タイムゾーンをAsia/Tokyoに設定
$ timedatectl set-timezone Asia/Tokyo
```

#### 3.3 パッケージの更新
パッケージは全部aptで導入します。システムの更新もありますので、一度```apt full-upgrade```をかけてから必要なパッケージを導入します。
```bash:パッケージの更新と導入
$ sudo apt update
$ sudo apt -y full-upgrade
# ここでゴリっとシステム関係の更新が入ると思うので、更新が終わったら一度再起動して再ログインします。
$ sudo reboot now
# --------
# さ　い　き　ど　う
# --------
# ここから再起動後。パッケージリポジトリの内容は変わらないと思うけれどもおまじない的に更新
$ sudo apt update
# RubyとPassengerのビルドに必要なものを導入
$ sudo apt install -y build-essential zlib1g-dev libssl-dev libreadline-dev libyaml-dev libcurl4-openssl-dev libffi-dev
# PostgrerSQLとヘッダファイルの導入
$ sudo apt install -y postgresql libpq-dev
# 日本語フォントの導入
$ sudo apt install -y imagemagick fonts-takao-pgothic
# バージョン管理システム(SubversionとGitの導入∵Redmineをリポジトリから引っ張ってくるのでsvnを入れます)
$ sudo apt install -y subversion git
```
#### 3.4 Rubyをビルドしてインストール
私が「ルビーわからんおじさん」なので「aptで入らんのですか??」と思いつつ、ソースコードからビルドしてインストールします。
尚、Redmine のtrunk版ではRuby 3.2系が使えるらしいですが([Redmineの使用推奨環境](https://redmine.org/projects/redmine/wiki/RedmineInstall))安定板では3.1系までだそうなので、[公式](https://www.ruby-lang.org/ja/downloads/)の安定版である3.1.4を使用します。
```bash:Rubyのソースコードをダウンロードしてインストールするまで
# ホームディレクトリで作業することを想定
$ pwd
/home/fattoton/
# curlコマンドでソースコードをダウンロードします
$ curl -O https://cache.ruby-lang.org/pub/ruby/3.1/ruby-3.1.4.tar.gz
# tarコマンドで解凍(gzだけれどもxvfでいけた)
$ tar xvf ruby-3.1.4.tar.gz
# 解凍したフォルダーに移動
$ cd ./ruby-3.1.4

# ソースコードのビルドとインストール
# ----  ここから  ----
$ ./configure --disable-install-doc
$ make
$ sudo make install
# ----  ここまで  ----

# インストール完了後にRubyのバージョンを確認
$ ruby -v
ruby 3.1.4p223 (2023-03-30 revision 957bb7cb81) [x86_64-linux]
```

#### 3.5 NginxとPassengerの導入
Passengerは```install gem passenger```で導入することもできますが、提供元であるPhusionのマニュアルによれば「aptにリポジトリを追加してそっから突っ込んでね!!(意訳)」ということらしいので英語を見ながらぽちぽちやっていきます。
ここで結構悩んだんですが(よくよく考えれば当たり前な話)NginxとPassengerそれぞれを導入するだけではダメで、それらの間をつないでやるライブラリが必要です。
図にするとこんな感じ
```mermaid
flowchart LR
    Nginx-->libnginx-mod-http-passenger
    libnginx-mod-http-passenger-->Passenger
    Passenger-->libnginx-mod-http-passenger
    libnginx-mod-http-passenger-->Nginx
```

あとは古い情報だと、キーチェーンを使わないでPGP暗号鍵をストアする方法も出てくるんですが、それだと「もうそのやり方やめてって言ったでしょ～💢」とUbuntuに怒られたので、公式ででてる今っぽい(?)やり方で導入してます。
```bash:Nginxとpassengerの導入
# PGP暗号鍵の復号とhttps経由でのダウンロードをするために必要なモジュールの導入
$ sudo apt install -y dirmngr gnupg apt-transport-https ca-certificates curl
# 暗号鍵のダウンロードとキーチェーンへの登録
# (最後出力を/dev/nullに突っ込んでるのはバイナリファイルの内容をコンソールに表示させないため)
$ curl https://oss-binaries.phusionpassenger.com/auto-software-signing-gpg-key.txt | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/phusion.gpg >/dev/null
# aptにリポジトリを追加
$ sudo sh -c 'echo deb https://oss-binaries.phusionpassenger.com/apt/passenger jammy main > /etc/apt/sources.list.d/passenger.list'
# aptの情報を更新
$ sudo apt update

# (1)Nginx, (2)Passenger, (3)Passenger+Nginxのライブラリの順で導入
$ sudo apt install -y nginx
$ sudo apt install -y passenger
$ sudo apt install -y libnginx-mod-http-passenger

# libnginx-mod-http-passengerの設定ファイルがあるか確認の上シンボリックリンクをうまい具合につくってくれる
$ if [ ! -f /etc/nginx/modules-enabled/50-mod-http-passenger.conf ]; then sudo ln -s /usr/share/nginx/modules-available/mod-http-passenger.load /etc/nginx/modules-enabled/50-mod-http-passenger.conf ; fi
$ sudo ls /etc/nginx/conf.d/mod-http-passenger.conf
```
ここで公式によると「もしも```/etc/nginx/conf.d/mod-http-passenger.conf```がなかったら自分で作ってね!!」だそうで

```conf:mod-http-passenger.conf
passenger_root /usr/lib/ruby/vendor_ruby/phusion_passenger/locations.ini;
passenger_ruby /usr/bin/passenger_free_ruby;
```
というのが要ることが稀にあるらしい。私は遭遇しなかったので無視して問題ないとは思います。
以上でNginx, Passenger, libnginx-mod-http-passengerが導入できたので、systemdでサービスを再起動してやります。
```bash:Nginxのサービスを再起動して状態を確認
# サービス再起動
$ sudo systemctl restart nginx
# サービスのステータス確認
$ sudo systemctl status nginx
# Passengerの動作状態確認
$ sudo passenger-memory-stats
```
こんな感じの表示が出てきます(Apache動いてないって言ってるけれどもこれはどうすればいいんでしょうね??)
![Passengerのメモリ使用量](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352775/dc7d2741-afda-d9bb-8990-dbead319d52d.png)

#### 3.6 データベースの設定
PostgreSQLにRedmineが使用するユーザーを作成したあと、Redmine用のデータベースを作成します。
```bash:PostgreSQLにRedmine用の設定を実施
# PostgreSQLにユーザーredmineを追加
$ sudo -i -u postgres createuser -P redmine
# パスワードを設定するように求められます
Enter pasword for new role:   # PostgreSQLにユーザー名redmineでアクセスする際のパスワードを入力
Enter it again:               # パスワードを再入力

# PostgreSQLにデータベースを作成
# ここで一番最初にやった"ja_JP.UTF-8"を使う
$ sudo -i -u postgres createdb -E UTF-8 -l ja_JP.UTF-8 -O redmine -T template0 redmine
```

#### 3.7 Redmineのダウンロード
Redmineのセットアップの流れを一応おさらい的に書いておくと、
* すごーく昔のRedmine
    * 手作業でGemを一つずつ流し込むんで超めんどい<br> & Gem間で依存パッケージの管理ができてなくて(プラグインで)時々詰む
* bundlerが導入されてからのRedmine
    * Gem.lockの中にバージョン指定が書いてあるからあとはbundlerが良きに計らってくれるよ!!<br>何なら特定の場所にGemを配置して複数のRubyの環境が同居できるようになるよ!!
   
という感じなので、どのみちRedmineをダウンロードしたらあとは勝手に動くわけではないのです。わけのわからないエラーで苦しまなくなったのでだいぶ楽になったけどね。
なのでRedmineを特定のフォルダーにダウンロードして、設定ファイルをいじってからGemをbundlerで導入します。
今回はRedmine.JPさんの記事と同じ```/var/lib/redmine```にファイルを配置します[^1]。
[^1]:個人的には以前は/opt/redmine/とかに置いてたけれども、どこに置くのが正解なんですかね??
```bash:RedmineをRedmine.orgからチェックアウト
sudo mkdir /var/lib/redmine
sudo chown www-data /var/lib/redmine
# redmine.orgからver.5.0の安定版を/var/lib/redmine/以下にダウンロード
sudo -u www-data svn co https://svn.redmine.org/redmine/branches/5.0-stable /var/lib/redmine
```
#### 3.8 database.ymlとconfiguration.ymlの設定
RubyからPostgreSQLへ接続するための接続情報と、メール配信や添付ファイルの保存領域などの設定をそれぞれファイルに記載します。
それぞれ
```/var/lib/redmine/config/database.yml.example```
```/var/lib/redmine/config/configuration.yml.example```
というお手本のファイルがあるのでコピーして拡張子の.exampleを取って使うと楽です。
```bash:設定ファイルをコピーして作成
#作業ディレクトリの確認
$ pwd
/var/lib/redmine/config/
# /var/lib/redmine以下の所有者がwww-dataなので、sudoにユーザーを指定して実行
$ sudo -u www-data cp ./database.yml.example ./database.yml
$ sudo -u www-data cp ./configuration.yml.example ./configuration.yml
```

```yaml:database.yml
production:
  adapter: postgresql
  database: redmine
  host: localhost
  username: redmine
  password: "********" # 3.6で設定したPostgreSQLにアクセスするためのパスワード
  encoding: utf8
```
```yaml:confiugration.yml
default:
  # 今回はメール送信は設定しなかったので割愛
  # email_delivery:
  #   delivery_method: :smtp
  #   smtp_settings:
  #     address: "localhost"
  #     port: 25
  #     domain: "example.com"
  # 添付ファイルの保存フォルダーを設定
  attachements_storage_path: /var/lib/redmine/files
  # バージョン管理システム(使用するもののみ)のコマンドを設定
  scm_git_command: git
  # 日本語用フォントを設定
  rmagick_font_path: /usr/share/fonts/truetype/takao-gothic/TakaoPGothic.ttf
```

#### 3.9 Redmineで使用するRuby Gemの導入
bundlerを使ってGemを導入します。
```bash:bundlerでGemを導入
$ cd /var/lib/redmine
# オプションの--without development testをつけることでProduction版以外の環境の作成を抑止する
$ sudo bundle install --without development test
```

#### 3.10 Redmineを起動させるための設定
セッション改ざん防止用秘密鍵とデータを保存するためのテーブルを作成します。
```bash:秘密鍵とテーブルの作成
# 【重要】必ずRedmineのルートディレクトリで実施すること
$ pwd
/var/lib/redmine/
# セッション改ざん防止用秘密鍵の作成
$ sudo -u www-data bin/rake generate_secret_token
# PostgreSQLのデータベースにテーブルを作成
$ sudo -u www-data RAILS_ENV=production bin/rake db:migrate
```

#### 3.11 Nginxの設定
Nginxで公開するサイトの設定をします。
にわか知識の理解で書くと
1. Nginxの設定ファイルの大元は```/etc/nginx/nginx.conf```
1. ```nginx.conf```の中でプラグインの設定は```/etc/nginx/conf.d/*.conf```から、Virtual Hostの設定は```/etc/nginx/sites-enabled/*```からそれぞれ参照して読み込む
1. ```/etc/nginx/sites-enabled/```以下には```/etc/nginx/sites-available/```以下にある.confファイルへのシンボリックリンクを配置することで、サイトを簡単に挿げ替えできるようになっている(シンボリックリンクの向きを変えるだけで良い。
ということらしいです。
図にするとこんな感じ。
```mermaid
%%{init: {"flowchart": {"defaultRenderer": "elk", "curve": "monotoneY"}} }%%
flowchart LR
    dir1["/etc/nginx/"]
    dir2["conf.d/"]
    dir3["sites-enabled/"]
    dir4["sites-availabe/"]
    file1["nginx.conf"]
    file2["mod-http-passenger.conf"]
    file3["redmine"]
    file4["redmine_server.conf"]
    dir1---dir2
    dir1---dir3
    dir1---dir4
    dir1---file1
    subgraph plugin_config["プラグイン設定"]
    dir2---file2
    end
    subgraph enabled["公開対象"]
    dir3---file3
    end
    subgraph available["実際の設定ファイル"]
    dir4---file4
    end
    file1-. 参照 .->dir2
    file1-. 参照 .->dir3
    file3-. シンボリックリンク .->file4
```
ただ、最初は当然redmineというシンボリックリンクはなく、defaultという名前のファイルがあるだけなので
1. defaultを削除
1. redmine_server.confを作る
1. シンボリックリンクをredmineという名前で作る
をやってやります。
```bash:nginxの設定
# 作業フォルダーは/etc/nginx/
$ pwd
/etc/nginx/
# 先にnginxのサービスを止める
$ sudo systemctl stop nginx
# シンボリックリンクの削除(rmでもできるけれどもunlinkで)
$ unlink ./sites-enabled/default
# sites-availableにあるdefaultの設定を名前を変えてコピーしてやる
$ cp ./sites-available/default ./sites-available/redmine.conf
# シンボリックリンクの作成(フルパスで指定してね(^o^)/)
$ ln -s /etc/nginx/sites-available/redmine.conf /etc/nginx/sites-enabled/redmine
```
あとはdefaultをコピーして作ったredmine.confの中身を修正してやります。
```conf:redmine.confでServerの設定
server {
    listen 80;
    server_name redmine;
    # passeengerを有効に設定
    passenger_enabled on;
    # passengerに指定するrubyのインストールパス
    passenger_ruby /usr/local/bin/ruby;
    # Redmineを実行するためのルートディレクトリの設定
    root /var/lib/redmine/public;
}
```
修正が完了したらnginxを起動する前に必ず文法チェックを通しましょう(通さないでnginxが起動せず苦しんだ)。
```bash:Nginxで設定ファイルの文法チェック
$ sudo nginx -t
# 問題なければ以下のように表示される
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
```
ここまで来たらnginxのサービスを起動してブラウザーでページにアクセスしてログイン画面が出れば完了です。
```bash:nginxのサービス起動とステータス確認
sudo systemctl start nginx
sudo systemctl status nginx
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352775/9f7152da-e6cb-fd2b-bd11-604f795c474c.png)

## 感想
Nginxの設定が思った以上にあっさり行ったのは驚きでした。
逆にハマったポイントとしては
1. よく訳が分かっていない状態で```sudo apt install passenger```と```sudo gem install passenger```を両方やって見事にぶつかった。何なら途中でpassengerに「なんか2つ入ってるんですけど?💢」と怒られた
1. NginxとPassengerとlibnginx-mod-http-passengerの関係がよくわからず3回くらい入れたり消したりして、途中で/etc/以下の設定ファイルを手で消したらもうどうしようもなくなってサーバーをつぶしてもう1回作り直した(aptって --purgeしても設定ファイルから作り直ししてくれないの……)
1. 勇み足でRuby 3.2.2を入れたらbundlerに冷たく「つかえねーっつーの」と怒られた
という所でしょうか?
兎にも角にもこれで手順が固まったのでまたあちこちにRedmine(に限らず課題管理システム)を布教していきたいなぁと思う所です。

## 参考文献

https://www.server-world.info/query?os=Ubuntu_22.04&p=install

https://blog.redmine.jp/articles/5_0/install/ubuntu/

https://qiita.com/ytojima/items/5c5daf68af501ef8c62a

https://qiita.com/NaokiIshimura/items/24e0b911ca411421205a

https://qiita.com/kazuo_y/items/78e24d187807abfb0072

https://zenn.dev/spiegel/articles/20220508-apt-key-is-deprecated

https://libproc.com/nginx-conf-validation/

https://www.phusionpassenger.com/docs/tutorials/what_is_passenger/

https://www.phusionpassenger.com/docs/advanced_guides/install_and_upgrade/nginx/install/oss/jammy.html