アカベコマイリ

HEAR NOTHING SEE NOTHING SAY NOTHING

Redmine 3.4 から 4.2 へ移行

2021/8 に Redmine/Git サーバーを刷新した際の覚書。半年以上も前の内容だが、メンテナンスなどで読み返すこともありそうなのでブログとして書いておくことにした。

非常に長いため Redmine 構築と Git (Gitolite) で記事をわける。

移行の動機

Redmine/Git サーバーの稼働している CentOS 6 がサポート終了したこと、その標準ミドルウェア群が古すぎて Redmine 4 系へ移行できない問題を踏まえ、移行を決定。移行元、先ともにサーバーはさくらの VPS 4GB プランとした。

OS は CentOS Stream 8 を選択。当初 CentOS 8 想定だったが CentOS の方針変更によりこのバージョンはサポート短縮、代わりに Stream という名前でローリング リリースしてゆくのだという。つまり OS やミドルウェアの破壊的なバージョン更新もありえる。そのため従来方針の代替になる Rocky Linux と迷ったが、移行の動機が環境の古さなので受け入れることにした。

しかし現在としては Rocky Linux のほうがよかったかも、と考えている。ローリング リリースで環境は新しくなるものの、バージョン系の移行は 3 年周期ぐらいで十分なので。今回の作業で 7 年物の古い Redmine/Git も刷新できたから、同じ RHEL 系であればサーバー乗り換えは楽になったはず。

バージョン更新で致命的な問題が起きたら、改めて Rocky Linux へ移行するかもしれない。

バックアップ

はじめに Redmine 関連をバックアップする。サーバーに SSH 接続して以下を実行。プラグインは利用していないため MySQL の DB ダンプ、Redmine の添付ファイルと設定だけを対象とした。これらをまとめて ZIP 保存。

$ cd
$ mkdir redmine-backup
$ mysqldump -u xxxx -p yyyy > redmine-backup/redmine.sql
$ cp -r /var/lib/redmine/files redmine-backup
$ cp -r /var/lib/redmine/config redmine-backup
$ zip -r redmine-backup.zip redmine-backup/

次に Git リポジトリーの保存。Gitolite の設定は git-admin というリポジトリーとして git clone 済みなので、新サーバーへこれを push すれば済む。よって管理化の各種リポジトリーの実体を保存して ZIP 保存。

$ cd
$ sudo su root
# cp -r /home/gituser/repositories .
# zip -r repositories.zip repositories/

Redmine/Git 両方のバックアップ ZIP ファイルをローカルにダウンロードして終了。

MySQL の文字エンコーディング変換

これまで MySQL の文字エンコーディングは utf8 を利用していた。しかし最近は様々な媒体で Unicode 絵文字が普及しており、これを MySQL で扱うためには文字エンコーディングを utf8mb4 へ移行しなければならない。そのためにバックアップした MySQL DB のダンプ ファイルを加工する。

ZIP を展開したディレクトリー上で以下を実行。単なる文字列の置換なのでテキスト エディターなどで処理してもよい。

$ sed -e "s/CHARSET=utf8/CHARSET=utf8mb4/g" ./redmine.sql > ./redmine_utf8mb4.sql

この方法は手軽だが雑である。より安全に変換したいなら MySQL 上で SQL を実行するほうがよい。

ALTER DATABASE redmine CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;

今回はダンプ内の検索で対象がテーブルの文字エンコーディング指定しか存在しないことを確認済みなので、お手軽なテキスト置換を採用。変換した redmine_utf8mb4.sql を含めてディレクトリーを再度 ZIP に固め、この作業は終了とする。

新サーバー構築

ここからは移行先となるサーバー環境を構築してゆく。前述のように

  • さくらのVPS 4GB プラン
  • CentOS Stream 8

を対象とする。

さくらのVPS コントロール パネルからサーバー マシンを起動。初期状態は root ユーザーへ VPS 作成時に入力しやパスワードが設定されている。そのため以下のような感じで SSH 接続可能なことを確認しておく。

$ ssh root@xxxx.vs.sakura.ne.jp -o PreferredAuthentications=password -o PubkeyAuthentication=no

本記事では新サーバーのドメイン名を xxxx.vs.sakura.ne.jp にしているので、参考にする場合は自身の環境へあわせて変更すること。

作業ユーザー追加と sudo 設定など

ユーザーを追加してパスワードを設定。本記事では akabeko としておく。

# useradd akabeko
# passwd akabeko
Changing password for user akabeko.
New password:
Retype new password:
passwd: all authentication tokens updated successfully.

sudo を設定。

# visudo

ユーザー akabekosudo を利用できるように設定を追加。この場所を探すには vi をコマンドモードにして /Allow と入力して検索すればよい。root の行を直下にコピペしてユーザー名を akabeko に書き換える。

## Next comes the main part: which users can run what software on
## which machines (the sudoers file can be shared between multiple
## systems).
## Syntax:
##
##      user    MACHINE=COMMANDS
##
## The COMMANDS section may have other options added to it.
##
## Allow root to run any commands anywhere
root    ALL=(ALL)       ALL
akabeko    ALL=(ALL)       ALL

:wq で保存してから sudo が通ることを確認。ユーザーを akabeko に変更してからシステム更新コマンド dnf を実行してみる。パスワードを聞かれて設定したものを入力確定、正常に sudo dnf が実行できた。

# su - akabeko
$ sudo dnf

We trust you have received the usual lecture from the local System
Administrator. It usually boils down to these three things:

    #1) Respect the privacy of others.
    #2) Think before you type.
    #3) With great power comes great responsibility.

[sudo] password for akabeko:
usage: dnf [options] COMMAND

...以下略

sudo 時のコマンド実行におけるパス通し、プロンプトの書式と色、ロケールなどを設定しておく。

$ cd
$ vi .bash_profile

設定内容は以下。

# User specific environment and startup programs
export PS1="\[\e[1;32m\][\u@\h \W]\\$\[\e[00m\] "

# locale
export LANG=en_US.UTF-8
export LC_ALL=$LANG

# sudo
PATH=$PATH:$HOME/bin
PATH=$PATH:/sbin
PATH=$PATH:/usr/sbin
PATH=$PATH:/usr/local/sbin

ファイルを保存したら設定を読み直す。

$ source .bash_profile

プロンプトが設定したとおり緑系の色になったので OK。

公開鍵認証

SSH のパスワード認証を禁止して公開鍵認証のみとする。

ローカルの macOS 上で鍵を作成。パスワードは未設定とした。これらのファイルは ~/.ssh 内に保存しておくこと。Windows の場合は C:¥Users¥ユーザー名¥.ssh とする。.ssh フォルダーがなければ作成しておく。

$ ssh-keygen -f xxxx.vs.sakura.ne.jp
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:

...以下略

サーバーに公開鍵を送信。コマンド末尾の : を忘れると空振りするので注意する。成功したら akabeko ユーザーのホーム ディレクトリーにファイルが転送されているはず。

$ scp -P 22 xxxx.vs.sakura.ne.jp.pub xxxx.vs.sakura.ne.jp:
xxxx.vs.sakura.ne.jp's password:
xxxx.vs.sakura.ne.jp.pub

akabeko でサーバーにログイン。

$ ssh akabeko@xxxx.vs.sakura.ne.jp

akabeko として先ほど転送された公開鍵ファイルを利用して認証を設定。その後にサーバーから抜ける。

$ cd
$ mkdir .ssh
$ chmod 700 .ssh
$ mv xxxx.vs.sakura.ne.jp.pub .ssh/authorized_keys
$ chmod 600 .ssh/authorized_keys
$ exit

秘密鍵ファイル xxxx.vs.sakura.ne.jp がローカルの ~/.ssh に配置されていることを確認。同ディレクトリーの config ファイルへ以下の設定を追加する。

HOST xxxx.vs.sakura.ne.jp
    HOSTNAME     xxxx.vs.sakura.ne.jp
    USER         akabeko
    PORT         22
    IDENTITYFILE ~/.ssh/xxxx.vs.sakura.ne.jp

これで ssh xxxx.vs.sakura.ne.jp に対する公開鍵認証 SSH が実行可能となった。以降のサーバー接続はこれで実行する。

公開鍵認証を設定したのでサーバに SSH 接続してから root ユーザーとパスワードによるログインを禁止する。

$ sudo vi /etc/ssh/sshd_config

以下のように編集。PasswordAuthentication のほうはコメントアウトされているので解除のうえ、yesno に書き換える。

PermitRootLogin no

... 中略 ....

PasswordAuthentication no

SSH デーモンを再起動。

$ sudo systemctl restart sshd

これで一通り OK。試しに公開鍵認証していない root で SSH 接続してみるとエラーになることが確認できるはず。成功した場合は sshd_config を見直すこと。

$ ssh root@xxxx.vs.sakura.ne.jp
root@xxxx.vs.sakura.ne.jp: Permission denied (publickey,gssapi-keyex,gssapi-with-mic).

FileZilla によるファイル送信

新サーバーとファイルをやりとりする際、GUI を利用できると便利だ。というわけで FileZilla を設定する。SCP で十分とか他のツールを使う場合、本項は読み飛ばして OK。

FileZilla をセットアップしたら接続先として以下を作成して保存。

項目
設定名 xxxx.vs.sakura.ne.jp
プロトコル SFTP
ホスト xxxx.vs.sakura.ne.jp
ポート
ログオン タイプ 鍵ファイル
ユーザー akabeko
鍵ファイル 公開鍵認証用に作成した秘密鍵ファイルのパス

古いバージョンの FileZilla は OpenSSH 形式の秘密鍵を Putty 形式の PPK ファイルに変換する必要があった。しかし現行版は OpenSSH 対応しているので ~/.ssh の秘密鍵をそのまま鍵ファイルに指定すればよい。

これで接続できることを確認したら akabeko のホーム ディレクトリーへ Redmine のバックアップ ZIP ファイルをアップロードしておくこと。

logwatch

サーバー上のログを監視するため logwatch を設定。インストールして動作確認してみる。

$ sudo dnf install logwatch
$ sudo logwatch --output stdout

問題なければ以下を実行して設定を更新。

$ sudo cp -p /usr/share/logwatch/default.conf/logwatch.conf /etc/logwatch/conf
$ sudo vi /etc/logwatch/conf/logwatch.conf

変更箇所を抜粋。

MailTo = レポート メール送信先アドレス
MailFrom = logwatch@xxxx.vs.sakura.ne.jp
Detail = High

これで保存して改めて動作確認。

$ sudo logwatch --output stdout

 ...ここにサーバーの状態が出力される

問題なければメール送信をテストしてみる。

$ sudo logwatch --output mail
Can't exec "/usr/sbin/sendmail": No such file or directory at /sbin/logwatch line 1146, <TESTFILE> line 1.
Can't execute /usr/sbin/sendmail -t: No such file or directory

しかしエラーになった。原因は CentOS 8 から sendmail が標準で提供されないから。なので手動追加する。

$ sudo dnf install sendmail
$ systemctl start sendmail
$ sudo systemctl enable sendmail
Created symlink /etc/systemd/system/multi-user.target.wants/sendmail.service → /usr/lib/systemd/system/sendmail.service.
Created symlink /etc/systemd/system/multi-user.target.wants/sm-client.service → /usr/lib/systemd/system/sm-client.service.

改めて実行したところエラーなし。

$ sudo logwatch --output mail

以降は logwatchcron に登録した時刻で毎日、レポート メールが届くはず。送信先が Gmail だと迷惑メールとしてフィルターされがちなので注意すること。

firewalld の起動と初期設定

ファイヤーウォール firewalld を利用する。まずは動作確認。

$ sudo firewall-cmd --state
not running

動作していないので起動する。

$ sudo systemctl start firewalld
$ sudo firewall-cmd --state
running

OS 起動時の実行を設定。

$ sudo systemctl enable firewalld.service
Created symlink /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service → /usr/lib/systemd/system/firewalld.service.
Created symlink /etc/systemd/system/multi-user.target.wants/firewalld.service → /usr/lib/systemd/system/firewalld.service.

HTTP/HTTPS のポートを許可。

$ sudo firewall-cmd --zone=public --add-service=http --permanent
$ sudo firewall-cmd --zone=public --add-service=https --permanent
$ sudo firewall-cmd --reload

この時点では IP 制限をしない。Apache を入れてから HTTP/HTTPS だけ制限する予定。

Apache

Apache のインストールと設定。

$ sudo dnf install httpd
$ sudo vi /etc/httpd/conf/httpd.conf

標準の Options から Indexes を削除。

<Directory "/var/www/html">
    #
    # Possible values for the Options directive are "None", "All",
    # or any combination of:
    #   Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews
    #
    # Note that "MultiViews" must be named *explicitly* --- "Options All"
    # doesn't give it to you.
    #
    # The Options directive is both complicated and important.  Please see
    # http://httpd.apache.org/docs/2.4/mod/core.html#options
    # for more information.
    #
    # Options Indexes FollowSymLinks
    Options FollowSymLinks

    #
    # AllowOverride controls what directives may be placed in .htaccess files.
    # It can be "All", "None", or any combination of the keywords:
    #   Options FileInfo AuthConfig Limit
    #
    AllowOverride None

    #
    # Controls who can get stuff from this server.
    #
    Require all granted
</Directory>

これが指定されていると index.html のないディレクトリーにアクセスされた際、自動的に内容リストを表示する。そのため隠しファイルなどがあると存在が露見し、攻撃するための情報を提供することになるので無効化した。

設定ファイルに構文エラーがないかを確認。

$ sudo apachectl configtest
Syntax OK

httpd を起動。ついでに自動起動も設定。

$ sudo systemctl start httpd
$ sudo systemctl enable httpd
Created symlink /etc/systemd/system/multi-user.target.wants/httpd.service → /usr/lib/systemd/system/httpd.service.

この状態で http://xxxx.vs.sakura.ne.jp/ を開くと Apache の情報が表示される。これを防ぐためにダミー ページを作成。

$ cd /var/www/html/
$ sudo touch index.html
$ sudo chown akabeko:akabeko index.html
$ vi index.html

内容は <h1>Welcome to xxxx.vs.sakura.ne.jp</h1> とだけ表示する簡素なもの。Redmine/Git サーバーなら基本的にここへアクセスする機会はないため、これでよい。

IP 制限

職場 Redmine を秘匿するために firewalld を利用して HTTP/HTTPS アクセスを IP 制限する。まずは現状の設定を表示。

$ sudo firewall-cmd --list-all
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: ens3
  sources:
  services: cockpit dhcpv6-client http https ssh
  ports:
  protocols:
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:

はじめに public ゾーンの httphttps を削除してアクセス不能とする。

$ sudo firewall-cmd --permanent --remove-service=http
$ sudo firewall-cmd --permanent --remove-service=https
$ sudo firewall-cmd --reload
$ sudo firewall-cmd --list-all
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: ens3
  sources:
  services: cockpit dhcpv6-client ssh
  ports:
  protocols:
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:

Web ブラウザーで http://xxxx.vs.sakura.ne.jp/ を開いてエラーになることを必ず確認しておくこと。

次に Web アクセスを制限するためのゾーンを追加。名前は myWeb としておく。アドレスは自社ネットワーク用の固定 IP を指定する。社内イントラネット、または相当となる VPN 接続した状態で Web ブラウザーから アクセス情報【使用中の IP アドレス確認】 を表示すれば簡単に確認できる。ここでは xxx.xxxx.xxx.xxx としておく。

$ sudo firewall-cmd --permanent --new-zone=myWeb
$ sudo firewall-cmd --permanent --zone=myWeb --set-target=ACCEPT
$ sudo firewall-cmd --permanent --zone=myWeb --add-source=xxx.xxxx.xxx.xxx
$ sudo firewall-cmd --permanent --zone=myWeb --add-service=http
$ sudo firewall-cmd --permanent --zone=myWeb --add-service=https
$ sudo firewall-cmd --reload
$ sudo firewall-cmd --list-all --zone=myWeb
myWeb (active)
  target: ACCEPT
  icmp-block-inversion: no
  interfaces:
  sources: xxx.xxxx.xxx.xxx
  services: http https
  ports:
  protocols:
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:
$ sudo firewall-cmd --get-active-zones
myWeb
  sources: xxx.xxxx.xxx.xxx
public
  interfaces: ens3

設定後、イントラネットまたは VPN 経由からなら http://xxxx.vs.sakura.ne.jp/ にアクセス可能なこと、なしならエラー表示されることを確認できた。IP 制限をやめる場合はゾーンを削除してから publichttphttps を再設定する。

$ sudo firewall-cmd --permanent --delete-zone=myWeb
$ sudo firewall-cmd --zone=public --add-service=http --permanent
$ sudo firewall-cmd --zone=public --add-service=https --permanent
$ sudo firewall-cmd --reload

Redmine 4.2 から 2 要素認証が利用可能となった。そのためユーザー全員がこれを設定済みならば IP 制限をやめてもよさそう。

MySQL

Redmine の DB を格納するために MySQL を構築。バージョンが CentOS 6 の 5 系から一気に 8 系へ更新されていた。

$ sudo dnf install mysql-server
$ mysql --version
mysql  Ver 8.0.21 for Linux on x86_64 (Source distribution)

設定ファイルをバックアップしてから書き換える。

$ cd
$ cp /etc/my.cnf ./
$ sudo vi /etc/my.cnf

CentOS 6 時代のデフォルトは以下だったが、

[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
user=mysql
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0

[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid

CentOS 8 だとこうなっている。

#
# This group is read both both by the client and the server
# use it for options that affect everything
#
[client-server]

#
# include all files from the config directory
#
!includedir /etc/my.cnf.d

以下の記事を読むと MySQL 8.0.1 以降の文字エンコーディングは標準で utf8mb4 とのこと。

インストールしたバージョンは Ver 8.0.21 なので設定ファイルは変更しないでおく。

MySQL の自動起動登録と起動。

$ sudo systemctl enable mysqld
Created symlink /etc/systemd/system/multi-user.target.wants/mysqld.service → /usr/lib/systemd/system/mysqld.service.

$ sudo systemctl restart mysqld

ルートにパスワードを設定。SSL で保護せよと警告されるが今回は同一サーバー内なのでよしとしておく。

$ sudo mysqladmin -u root password 'パスワード'
mysqladmin: [Warning] Using a password on the command line interface can be insecure.
Warning: Since password will be sent to server in plain text, use ssl connection to ensure password safety.

パスワードが設定されたことを確認。

$ mysql -u root -p
Enter password:

...中略

mysql> exit;
Bye

OK。不要なユーザーとデータベースを削除する。

$ mysql -u root -p mysql
mysql> SELECT user, password, host FROM user;
ERROR 1054 (42S22): Unknown column 'password' in 'field list'

昔はこの時で先程パスワードを設定したユーザーを識別できたのだがエラーになった。改めて実行。

mysql> SELECT user, host FROM user;
+------------------+-----------+
| user             | host      |
+------------------+-----------+
| mysql.infoschema | localhost |
| mysql.session    | localhost |
| mysql.sys        | localhost |
| root             | localhost |
+------------------+-----------+

現在は不要なユーザーと思えるものがない。次はデータベースの確認。

mysql> SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+

これも昔は test というのがあって不要だったのだけど現在は必要最小で構成されているようだ。

rbenv で Ruby 構築

rbenv 経由で Ruby をインストールする。

sudo 経由で rbenv を実行するための設定をおこなう。visudo で設定ファイルを新規作成。

$ sudo visudo -f /etc/sudoers.d/00_base

以下を記述して保存。

Defaults !secure_path
Defaults env_keep += "PATH RBENV_ROOT"

設定ファイルに記述した環境変数を追加。

$ export RBENV_ROOT=/usr/local/rbenv
$ export PATH=${RBENV_ROOT}/bin:${PATH}

この環境変数を利用して GitHub のリポジトリから rbenv と ruby-build を clone する。

$ sudo git clone https://github.com/rbenv/rbenv.git ${RBENV_ROOT}
$ sudo git clone https://github.com/rbenv/ruby-build.git ${RBENV_ROOT}/plugins/ruby-build

rbenv 初期化。コマンドを実行すると export された環境変数などが表示される。

$ sudo rbenv init -
export PATH="/usr/local/rbenv/shims:${PATH}"
export RBENV_SHELL=sudo
command rbenv rehash 2>/dev/null
rbenv() {
  local command
  command="${1:-}"
  if [ "$#" -gt 0 ]; then
    shift
  fi

  case "$command" in
  rehash|shell)
    eval "$(rbenv "sh-$command" "$@")";;
  *)
    command rbenv "$command" "$@";;
  esac
}

現在のユーザーで rbenv を利用するために .bash_profile へ設定を追加しておく。

$ vi .bash_profile

以下を追記して保存。

# rbenv
export RBENV_ROOT="/usr/local/rbenv"
export PATH="${RBENV_ROOT}/bin:${PATH}"
eval "$(rbenv init -)"

保存された設定を反映するため .bash_profile を読み直す。

$ source ~/.bash_profile

これで PATH が通ったはず。試しに rbenv コマンドをオプション指定なしで実行してみるとバージョンやオプションなどが表示される。

$ rbenv
rbenv 1.1.2-61-g585ed84
Usage: rbenv <command> [<args>]

Some useful rbenv commands are:
   commands    List all available rbenv commands
   local       Set or show the local application-specific Ruby version
   global      Set or show the global Ruby version
   shell       Set or show the shell-specific Ruby version
   install     Install a Ruby version using ruby-build
   uninstall   Uninstall a specific Ruby version
   rehash      Rehash rbenv shims (run this after installing executables)
   version     Show the current Ruby version and its origin
   versions    List installed Ruby versions
   which       Display the full path to an executable
   whence      List all Ruby versions that contain the given executable

See `rbenv help <command>' for information on a specific command.
For full documentation, see: https://github.com/rbenv/rbenv#readme

Ruby をインストールする。rbenv は Ruby のバージョンを自由に選択できる。

$ rbenv install -l
2.6.8
2.7.4
3.0.2
jruby-9.2.19.0
mruby-3.0.0
rbx-5.0
truffleruby-21.2.0
truffleruby+graalvm-21.2.0

Only latest stable releases for each Ruby implementation are shown.
Use 'rbenv install --list-all / -L' to show all local versions.

最新は 3.0.2 のようだ。しかし以下を見ると 3.x 系は掲載されていない。

不安になったので Twitter でつぶやいたら Redmine コミッターの前田さんから即レスあり。いわく

Redmine 4.2 はまだ Ruby 3.0 には対応していません。2.4 から 2.7 までです。Ruby 3.0 には Redmine 5.0 から対応します。

とのこと。よって今回は 2.7 系の最新となる 2.7.4 を選ぶ。

$ sudo rbenv install 2.7.4
Downloading ruby-2.7.4.tar.bz2...
-> https://cache.ruby-lang.org/pub/ruby/2.7/ruby-2.7.4.tar.bz2
Installing ruby-2.7.4...

BUILD FAILED (CentOS Stream 8 using ruby-build 20210726-3-g075ad3b)

Inspect or clean up the working tree at /tmp/ruby-build.20210801171024.23522.h79LiI
Results logged to /tmp/ruby-build.20210801171024.23522.log

Last 10 log lines:
	from ./tool/rbinstall.rb:846:in `block (2 levels) in install_default_gem'
	from ./tool/rbinstall.rb:279:in `open_for_install'
	from ./tool/rbinstall.rb:845:in `block in install_default_gem'
	from ./tool/rbinstall.rb:835:in `each'
	from ./tool/rbinstall.rb:835:in `install_default_gem'
	from ./tool/rbinstall.rb:799:in `block in <main>'
	from ./tool/rbinstall.rb:950:in `block in <main>'
	from ./tool/rbinstall.rb:947:in `each'
	from ./tool/rbinstall.rb:947:in `<main>'
make: *** [uncommon.mk:373: do-install-all] Error 1

ビルドでエラーになった。必要なパッケージが足りないらしいので追加。

$ sudo dnf install gcc openssl-devel readline-devel zlib-devel

再試行したら無事に成功。

$ sudo rbenv install 2.7.4
Downloading ruby-2.7.4.tar.bz2...
-> https://cache.ruby-lang.org/pub/ruby/2.7/ruby-2.7.4.tar.bz2
Installing ruby-2.7.4...
Installed ruby-2.7.4 to /usr/local/rbenv/versions/2.7.4

インストールしたバージョンをグローバルに設定。

$ sudo rbenv global 2.7.4
$ sudo rbenv rehash

確認のため sudo なしでバージョンを表示。

$ ruby --version
ruby 2.7.4p191 (2021-07-07 revision a21a3b7d23) [x86_64-linux]

OK。

Bundler と Passenger、失敗編

Redmine を動作させるために Bundler と Passenger をインストール。まずは Bundler。過去にはオプションとして --no-rdoc --no-ri を指定していたが現行バージョンだと invalid option: --no-rdoc というエラーになる。これを踏まえてオプションなしで実行。

$ sudo gem install bundler
Fetching bundler-2.2.25.gem
Successfully installed bundler-2.2.25
Parsing documentation for bundler-2.2.25
Installing ri documentation for bundler-2.2.25
Done installing documentation for bundler after 2 seconds
1 gem installed

次は Passenger。これを使って Apache や Nginx 上で Rails アプリを動かす。

$ sudo gem install passenger
Fetching passenger-6.0.10.gem
Fetching rack-2.2.3.gem
Successfully installed rack-2.2.3
Building native extensions. This could take a while...
Successfully installed passenger-6.0.10
Parsing documentation for rack-2.2.3
Installing ri documentation for rack-2.2.3
Parsing documentation for passenger-6.0.10
Installing ri documentation for passenger-6.0.10
Done installing documentation for rack, passenger after 39 seconds
2 gems installed

グローバルな Ruby 環境に gem をインストールしたので rbenv をリフレッシュ。

$ sudo rbenv rehash

Passenger の Apache 用モジュールをインストール。

$ sudo passenger-install-apache2-module
Use <space> to select.
If the menu doesn't display correctly, press '!'

 ‣ ⬢  Ruby
   ⬡  Python
   ⬡  Node.js
   ⬡  Meteor

--------------------------------------------

Checking for required software...

...中略
      Found: no
      Error: Cannot find the `curl-config` command.
 * Checking for Apache 2 development headers...
      Found: no
 * Checking for Apache Portable Runtime (APR) development headers...
      Found: no
 * Checking for Apache Portable Runtime Utility (APU) development headers...
      Found: no

Some required software is not installed.
But don't worry, this installer will tell you how to install them.
Press Enter to continue, or Ctrl-C to abort.

エラーになった。curl-config が足りないとのこと。パッケージとしてはこの名前ではなく curl-devel らしいので入れてみる。

$ sudo dnf install curl-devel

Some required software is not installed. のほうも入れる。

$ sudo dnf install httpd-devel

再試行するも途中でエラー。

mkdir -p buildout/apache2/module_libpassenger_common
rake aborted!
ArgumentError: Malformed version number string Stream

Tasks: TOP => apache2 => buildout/apache2/mod_passenger.so => buildout/apache2/module_libpassenger_common/LoggingKit.o
(See full trace by running task with --trace)

--------------------------------------------

It looks like something went wrong

Please read our documentation for troubleshooting tips:

   https://www.phusionpassenger.com/library/install/apache/
   https://www.phusionpassenger.com/library/admin/apache/troubleshooting/

If that doesn't help, please use our support facilities. We'll do our best to help you.

   https://www.phusionpassenger.com/support

--help オプションでヘルプを表示してみたら --no-compile というオプションがあった。コンパイルしないでインストールするらしい。これで再試行してみたらいけた。

$ sudo passenger-install-apache2-module --no-compile

Apache 用モジュール設定。httpd.conf 本体に書くのではなく専用ファイルを用意する。passenger.conf という名前で作成。

$ sudo vi /etc/httpd/conf.d/passenger.conf

設定は以下で確認できる。

$ sudo passenger-install-apache2-module --snippet
LoadModule passenger_module /usr/local/rbenv/versions/2.7.4/lib/ruby/gems/2.7.0/gems/passenger-6.0.10/buildout/apache2/mod_passenger.so
<IfModule mod_passenger.c>
  PassengerRoot /usr/local/rbenv/versions/2.7.4/lib/ruby/gems/2.7.0/gems/passenger-6.0.10
  PassengerDefaultRuby /usr/local/rbenv/versions/2.7.4/bin/ruby
</IfModule>

これを passenger.conf に記述。してついでに Redmine を公開するときのディレクトリ設定も加えて保存。今回は http://ホスト名/redmine に公開するので以下のようになる。パスを見ると gem のバージョンが含まれているため rbenv でバージョンを切り替える場合はここも変更する必要あり。

LoadModule passenger_module /usr/local/rbenv/versions/2.7.4/lib/ruby/gems/2.7.0/gems/passenger-6.0.10/buildout/apache2/mod_passenger.so
<IfModule mod_passenger.c>
  PassengerRoot /usr/local/rbenv/versions/2.7.4/lib/ruby/gems/2.7.0/gems/passenger-6.0.10
  PassengerDefaultRuby /usr/local/rbenv/versions/2.7.4/bin/ruby
</IfModule>

RailsBaseURI /redmine

しかし Apache の構文確認でエラーになる。

$ sudo apachectl configtest
[sudo] password for akabeko:
httpd: Syntax error on line 357 of /etc/httpd/conf/httpd.conf: Syntax error on line 1 of /etc/httpd/conf.d/passenger.conf: Cannot load /usr/local/rbenv/versions/2.7.4/lib/ruby/gems/2.7.0/gems/passenger-6.0.10/buildout/apache2/mod_passenger.so into server: /usr/local/rbenv/versions/2.7.4/lib/ruby/gems/2.7.0/gems/passenger-6.0.10/buildout/apache2/mod_passenger.so: cannot open shared object file: No such file or directory

mod_passenger.so が見つからないそうだ。実際、このパス上に存在しない。コンパイルなしではダメなのだろうか?Passenger を uninstall してら再試行してみたが、やはりコンパイル途中で rake abort するしで対処のしようがない。

Passenger 再び

Passenger のインストールで失敗して困っていることを Twitter でつぶやいていたら以下のリプがあった。

試しに OS のバージョンを表示。

$ cat /etc/centos-release
CentOS Stream release 8

これはプレーン テキスト ファイルに記述されているので Twitter で提案されているとおり編集してみる。

$ sudo vi /etc/centos-release

内容は Stream を削除して CentOS release 8 とした。:wq で保存後にバージョン表示すると変更が反映されていた。

$ cat /etc/centos-release
CentOS release 8

この状態で再実行したらエラーにならず成功した!嬉しい!!!

$ sudo passenger-install-apache2-module

--snippet オプション付きで実行して設定を確認。

$ sudo passenger-install-apache2-module --snippet
LoadModule passenger_module /usr/local/rbenv/versions/2.7.4/lib/ruby/gems/2.7.0/gems/passenger-6.0.10/buildout/apache2/mod_passenger.so
<IfModule mod_passenger.c>
  PassengerRoot /usr/local/rbenv/versions/2.7.4/lib/ruby/gems/2.7.0/gems/passenger-6.0.10
  PassengerDefaultRuby /usr/local/rbenv/versions/2.7.4/bin/ruby
</IfModule>

RailsBaseURI /redmine

これに対して Redmine を URL のサブディレクトリーとする設定を加える。

$ sudo passenger-install-apache2-module --snippet
LoadModule passenger_module /usr/local/rbenv/versions/2.7.4/lib/ruby/gems/2.7.0/gems/passenger-6.0.10/buildout/apache2/mod_passenger.so
<IfModule mod_passenger.c>
  PassengerRoot /usr/local/rbenv/versions/2.7.4/lib/ruby/gems/2.7.0/gems/passenger-6.0.10
  PassengerDefaultRuby /usr/local/rbenv/versions/2.7.4/bin/ruby
</IfModule>

RailsBaseURI /redmine

この内容を Apache の設定ファイルとして書き込み保存。構文確認もしておく。

$ sudo vi /etc/httpd/conf.d/passenger.conf
$ sudo apachectl configtest
Syntax OK

OK だったので OS のバージョン情報を書き戻す。CentOS release 8 としたものを CentOS Stream release 8 にして保存後、反映を確認。

$ sudo vi /etc/centos-release
$ cat /etc/centos-release

これで Passenger 構築は完了。

Redmine

作業用ユーザーの HOME に最新版 Redmine をダウンロード。この時点の最新は 2021/8/1 リリースの 4.2.2 だった。

$ curl -OL https://www.redmine.org/releases/redmine-4.2.2.zip
$ unzip redmine-4.2.2.zip
$ rm redmine-4.2.2.zip

/var/lib 直下へ redmine というディレクトリー名で移動。

$ sudo mv redmine-4.2.2 /var/lib/redmine

Redmine 専用のユーザーとデータベースを作成。XXXXXXXXXXXXXXXX 部分はパスワード。私は KeePassXC ランダム生成したものにした。ユーザーは 'redmine'@'localhost' としておく。文字エンコーディングは旧環境の DB ダンプを utf8mb4 に変換したのであわせる。

$ mysql -u root -p
mysql> CREATE DATABASE redmine DEFAULT CHARACTER SET utf8mb4;
mysql> CREATE USER 'redmine'@'localhost'' IDENTIFIED BY 'XXXXXXXXXXXXXXXX';
mysql> GRANT ALL PRIVILEGES ON redmine.* TO 'redmine'@'localhost';
mysql> FLUSH PRIVILEGES;
mysql> exit;

旧環境の移行

新規ならこの部分は実行しなくてよい。

旧環境から持ってきたバックアップが作業用ユーザー HOME 直下に置かれていると仮定する。サブ ディレクトリー内なら以降のパス指定やカレントを適宜、自分の環境にあわせて変更すること。

ファイル 内容
redmine_utf8mb4.sql MySQL DB のダンプ。CHARSETutf8 から utf8mb4 に変換済み。
files/ Redmine の添付ファイル格納ディレクトリー。
config Redmine の設定ファイル格納ディレクトリー。

バックアップを新環境のデータベースに取り込む。

$ cd
$ mysql -u redmine -p redmine < redmine_utf8mb4.sql

添付ファイルの移行。

$ cd
$ mv /var/lib/redmine/files/ /var/lib/redmine/_files/
$ mv files/ /var/lib/redmine/
$ rm -rf /var/lib/redmine/_files/

config/ は旧環境の有無に関わらず編集が必要なので、バックアップしたものを参考に次項で書き換えること。

セットアップ

以下を参考にしながら Redmine をセットアップしてゆく。

設定ファイル置き場に移動。

$ cd /var/lib/redmine/config/

データベース設定ファイルを作成して編集する。

$ cp database.yml.example database.yml
$ vi database.yml

データベースの設定にあわせて変更してゆく。ここまでの手順を実行しているなら usernameredmine にして password へ MySQL の redmine ユーザーへ割り当てたパスワードを指定すればよい。編集したら保存する。

production:
  adapter: mysql2
  database: redmine
  host: localhost
  username: redmine
  password: "XXXXXXXXXXXXXXXX"
  # Use "utf8" instead of "utfmb4" for MySQL prior to 5.7.7
  encoding: utf8mb4

メール設定。

$ cp configuration.yml.example configuration.yml
$ vi configuration.yml

旧環境だとシンプルだった。

production:
  email_delivery:
    delivery_method: :sendmail

しかし Redmine 4.2 では設定やサンプルが大量に定義されている。途中に

# ==== Sendmail command
#
#  email_delivery:
#    delivery_method: :sendmail

という箇所があるのでこれを参考に冒頭の方を書き換えて保存。前述の logwatch 用に sendmail をインストール済みなので、これを Redmine でも利用することにした。

# default configuration options for all environments
default:
  # Outgoing emails configuration
  # See the examples below and the Rails guide for more configuration options:
  # http://guides.rubyonrails.org/action_mailer_basics.html#action-mailer-configuration
  email_delivery:
    delivery_method: :sendmail

Redmine の依存ソフトウェアをインストール。まずは基本となる bundler から。

$ cd
$ sudo gem install bundler

次に Redmine 関連。

$ cd /var/lib/redmine
$ sudo bundle install --without development test

An error occurred while installing mysql2 (0.5.3), and Bundler cannot continue.

エラーになった。ググると以下の記事が出たので

参考に設定を足してみたが

$ sudo bundle config --local build.mysql2 "--with-ldflags=-L/usr/local/opt/openssl/lib"

エラーになった。ログを見るとビルドに失敗しているのでもしかすると mysql-devel がインストールされていないからだろうか。追加してみる。

$ sudo dnf install mysql-devel

再び実行したら成功した。

$ sudo bundle install --without development test

Installing mysql2 0.5.3 with native extensions
Bundle complete! 36 Gemfile dependencies, 63 gems now installed.
Gems in the groups 'development' and 'test' were not installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.

セッション管理用の鍵を初期化し、データベースをマイグレート。

$ bundle exec rake generate_secret_token
$ RAILS_ENV=production bundle exec rake db:migrate

Web サイトとしてはサブディレクトリー公開するので var/www/html にシンボリック リンクを貼る。

$ sudo ln -s /var/lib/redmine/public /var/www/html/redmine

firewalld で IP 制限しているなら VPN 接続などでその IP となってから http://xxxx.vs.sakura.ne.jp/redmine のようにアクセスすると Redmine が表示されるはず。私の環境では正常に動作することを確認できた。

テーマ追加

手前味噌だが私の作成したテーマをインストールしておく。

$ cd
$ curl -OL https://github.com/akabekobeko/redmine-theme-minimalflat2/releases/download/v1.7.0/minimalflat2-1.7.0.zip
$ unzip minimalflat2-1.7.0.zip
$ mv minimalflat2 /var/lib/redmine/public/themes/

Redmine 管理画面でこれを有効にすれば OK。

HTTPS 化

Redmine サイトを HTTPS 化。証明書は Let's Encrypt で運用する。そのためのパッケージとして certbot が提供されているものの標準リポジトリーにはないので EPEL を追加しておく。

$ sudo dnf install epel-release

certbot をインストール。依存として膨大な Python 関連が表示されるが、そのまま実行。この時点のバージョンは 1.18.0 であった。

$ sudo dnf --enablerepo=epel install certbot
$ certbot --version
certbot 1.18.0

証明書を取得する。xxxx.vs.sakura.ne.jp 部分は自分のドメインに変更すること。しかし実行したらエラーになった。

$ sudo systemctl stop httpd
$ sudo certbot certonly --webroot -w /var/www/html/ -d xxxx.vs.sakura.ne.jp


Certbot failed to authenticate some domains (authenticator: webroot). The Certificate Authority reported these problems:
  Domain: xxxx.vs.sakura.ne.jp
  Type:   connection
  Detail: Fetching http://xxxx.vs.sakura.ne.jp/.well-known/acme-challenge/XXXX: Error getting validation data

Hint: The Certificate Authority failed to download the temporary challenge files created by Certbot. Ensure that the listed domains serve their content from the provided --webroot-path/-w and that files created there can be downloaded from the internet.

Some challenges have failed.
Ask for help or search for solutions at https://community.letsencrypt.org. See the logfile /var/log/letsencrypt/letsencrypt.log or re-run Certbot with -v for more details.

チャレンジ ファイルのダウンロードに失敗したのだという。Detail に示されたファイルを curl でダウンロードしてみる。

$ curl -OL http://xxxx.vs.sakura.ne.jp/.well-known/acme-challenge/XXX
... 中略
Failed to connect to xxxx.vs.sakura.ne.jp port 80: Connection refused

原因判明。Let's Encrypt 側からもポート 80 でこのサーバーへアクセスする必要があるのに firewalld で遮断されているようだ。なので制限用のゾーン設定を削除して HTTP/HTTPS を許可する。

$ sudo firewall-cmd --permanent --delete-zone=myWeb
$ sudo firewall-cmd --zone=public --add-service=http --permanent
$ sudo firewall-cmd --zone=public --add-service=https --permanent

certbot を再実行したら成功した。

$ sudo certbot certonly --webroot -w /var/www/html/ -d xxxx.vs.sakura.ne.jp
Successfully received certificate.

firewalld の設定を戻しておく。

$ sudo firewall-cmd --permanent --remove-service=http
$ sudo firewall-cmd --permanent --remove-service=https
$ sudo firewall-cmd --permanent --new-zone=myWeb
$ sudo firewall-cmd --permanent --zone=myWeb --set-target=ACCEPT
$ sudo firewall-cmd --permanent --zone=myWeb --add-source=xxx.xxx.xxx.xxx
$ sudo firewall-cmd --permanent --zone=myWeb --add-service=http
$ sudo firewall-cmd --permanent --zone=myWeb --add-service=https
$ sudo firewall-cmd --reload
$ sudo firewall-cmd --list-all --zone=myWeb

証明書を更新するたびにこれを実行するのは面倒だ。IP 制限については Redmine ユーザー全員が 2 要素認証したら廃止したい。

Apache 関連の設定

Apache に設定するための証明書を確認。

$ sudo ls -l /etc/letsencrypt/live/xxxx.vs.sakura.ne.jp
total 4
lrwxrwxrwx 1 root root  42 Aug 22 17:51 cert.pem -> ../../archive/xxxx.vs.sakura.ne.jp/cert1.pem
lrwxrwxrwx 1 root root  43 Aug 22 17:51 chain.pem -> ../../archive/xxxx.vs.sakura.ne.jp/chain1.pem
lrwxrwxrwx 1 root root  47 Aug 22 17:51 fullchain.pem -> ../../archive/xxxx.vs.sakura.ne.jp/fullchain1.pem
lrwxrwxrwx 1 root root  45 Aug 22 17:51 privkey.pem -> ../../archive/xxxx.vs.sakura.ne.jp/privkey1.pem
-rw-r--r-- 1 root root 692 Aug 22 17:51 README

Apache に証明書を設定して HTTPS 対応させる。はじめに SSL モジュールを追加してから設定ファイルを開く。

$ sudo dnf install mod_ssl
$ sudo vi /etc/httpd/conf.d/ssl.conf

以下のように設定変更。SSLCertificateFileSSLCertificateKeyFile はデフォルト設定をコメントアウトしてから追記。SSLCertificateChainFile はもともとコメントアウトされた状態だったのでそのまま追記した。ひととおり設定したら保存。

#SSLCertificateFile /etc/pki/tls/certs/localhost.crt
SSLCertificateFile /etc/letsencrypt/live/xxxx.vs.sakura.ne.jp/cert.pem

#SSLCertificateKeyFile /etc/pki/tls/private/localhost.key
SSLCertificateKeyFile /etc/letsencrypt/live/xxxx.vs.sakura.ne.jp/privkey.pem

#SSLCertificateChainFile /etc/pki/tls/certs/server-chain.crt
SSLCertificateChainFile /etc/letsencrypt/live/xxxx.vs.sakura.ne.jp/fullchain.pem

Apache 設定ファイルの構文チェック & 再起動 & ステータス確認。

$ sudo apachectl configtest
Syntax OK
$ sudo systemctl restart httpd
$ sudo systemctl status httpd

Redmine の URL 先頭を http から https に変更してアクセス可能であることを確認。私の環境では OK だった。

HTTP でアクセスされた場合、自動的に HTTPS へリダイレクトさせる。まずはこの機能を担当するモジュールの存在を確認。

$ sudo httpd -M | grep rewrite
 rewrite_module (shared)

有効なので設定ファイルを追加。

$ sudo vi /etc/httpd/conf.d/rewrite.conf

以下を記述して保存。

<ifModule mod_rewrite.c>
  RewriteEngine On
  LogLevel alert rewrite:trace3
  RewriteCond %{HTTPS} off
  RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R,L]
</ifModule>

構文チェック、Apache 再起動、状態確認。

$ sudo apachectl configtest
Syntax OK
$ sudo systemctl restart httpd
$ sudo systemctl status httpd

HTTP の URL でアクセスして HTTPS にリダイレクトされることを確認。また HTTP の時に開いていたページをリロードすると自動的に HTTPS へリダイレクトされることを確認できた。

まとめ

ひとまず HTTPS で Redmine が動作し、旧環境のデータが引き継げているところまで確認できた。次回は Git 関連の移行と Redmine 連携について書く。

Copyright © 2009 - 2023 akabeko.me All Rights Reserved.