プログラマーのメモ書き

伊勢在住のプログラマーが気になることを気ままにメモったブログです

Redmine のアップデート 3.3.2 -> 4.1.1

下記の記事で仕立てた Bitnami の Redmine スタックが ubuntu 14.04 ベースだったため、LTSのサポートも切れていて、はらはらしながら使っていました。

blog.mori-soft.com

まあ、さっさとOSアップグレードするか別のスタック立ち上げてもよかったんですが、時間がないことに加えて、2020年6月末でこの Redmine を運用していた EC2 のリザーブドインスタンスの期限が迫っていたので、見て見ぬふりをしながらなんとかやり過ごしていました。

先日、晴れてリザーブドインスタンスの期限が来たので、新たに Redmine を立ち上げ直すことにしました。

今回も、 Bitnami の Redmine スタックを利用しますが、サーバーは EC2 のスポットインスタンスで立てます。というのも、別サーバーをスポットインスタンスで運用しているのですが、価格が高騰してストップすることもなく結構安定して使えているのと、今はスポットインスタンが停止してもデータ(ストレージ)が残り、価格が下がってから改めて再起動できるので、自分用のサーバーならスポットでも十分かな?と思ったためです。

前回の移行時と同じく比較しておきます。

移行前 移行後
EC2インスタンス t2.nano t3.nano
OS Ubuntu 14.04, 64bit Debian 10, 64bit
Redmine 3.3.2 4.1.1

EC2 インスタンスの立ち上げ

というわけで、まずは t3.nano のインスタンスを立ち上げます。今回も Birnami を利用してお手軽にサーバーと Redmine を立ち上げたいと思います。下記のAMI一覧のページから使いたいリージョンのAMIをクリックするか、AWSのコンソールでコミュニティAMIで検索して立ち上げます。

Redmine Public AMIs

インスタンスタイプは t3.nano を選び、インスタンスの設定でスポットインスタンスを選択します。

f:id:junichim:20200701085506p:plain

上限金額(今回はオンデマンドの料金未満としました)を入力し、もしも停止しても再度インスタンスを立ち上げ直したいので『永続的リクエスト』には忘れずにチェックを入れます。また、『中断動作』として『停止』を選んでおきます。

あとは、デフォルト設定で起動すれば、新しい環境が出来上がりです。 次は、データのマイグレーションになります。

Redmine 4.1.1 へマイグレーション

さて、新しいサーバー(とRedmine)が立ち上がったので、古いサーバー上の Redmine のデータを移行したいと思います。前回のマイグレーション時の記事を参考にしてもよいですし、移行手順が下記にまとまっているので、この手順を参考に進めても OK です。

Upgrade Redmine

旧サーバーでの作業

まず、添付ファイルのバックアップを取ります。

bitnami@ip-172-30-0-73:/opt/bitnami/apps/redmine/htdocs$ tar zcvf ~/redmine_files.tgz ./files

次に、データベースのダンプを取ります。

bitnami@ip-172-30-0-73:~$ mysqldump -u bitnami -pxxxxxxx bitnami_redmine > redmine.dump

作成したファイルを新サーバーにアップロードしておきます。

新サーバーでの作業

まずは apache を停止します。

bitnami@ip-172-30-0-111:~/stack$ sudo ./ctlscript.sh stop apache

DB を復元します。パスワードは初期設定されているものを使用しています。初期パスワードは、立ち上げたインスタンスの bitnami ユーザーのホームディレクトリにファイルがあり、そこに記載されています(~/bitnami_credentials に記載)。

bitnami@ip-172-30-0-111:~/stack$ mysql -u root -p bitnami_redmine < ~/redmine.dump 
Enter password: 
bitnami@ip-172-30-0-111:~/stack$ 

下記ディレクトリで、添付ファイルを復元します。

bitnami@ip-172-30-0-111:~/stack/apps/redmine/htdocs$ tar zxvf redmine_files.tgz

Redmine のマイグレーションを行います。

bitnami@ip-172-30-0-111:~/stack/apps/redmine/htdocs$ sudo ruby bin/rake db:migrate RAILS_ENV=production

掃除

bitnami@ip-172-30-0-111:~/stack/apps/redmine/htdocs$ ruby bin/rake tmp:clear

最後に、apache の再起動を行えば完了です。

bitnami@ip-172-30-0-111:~/stack$ sudo ./ctlscript.sh start apache

前回よりもずいぶんと簡単になってました。

なお、マイグレーションが完了すると、ユーザー名・パスワードなども旧サーバーに設定したあるものになるので、ご注意ください。

サーバーの設定

Redmine が使えるようになったので、あとはサーバーの運用上必要な設定を行います。基本的には、前回マイグレーション時の下記記事に従っているのですが、

blog.mori-soft.com

最近の環境に合わせて、変えているところだけメモしておきます。

NTPクライアント起動

NTP クライアントは ntpd ではなく chrony を使うようです。

chrony は既にインストール済みでしたので、起動してあげればOKです。

bitnami@ip-172-30-0-111:/etc/chrony$ sudo systemctl status chrony
● chrony.service - chrony, an NTP client/server
   Loaded: loaded (/lib/systemd/system/chrony.service; enabled; vendor preset: enabled)
   Active: inactive (dead) since Sat 2020-06-27 00:10:36 JST; 1 day 14h ago
     Docs: man:chronyd(8)
           man:chronyc(1)
           man:chrony.conf(5)
 Main PID: 547 (code=exited, status=0/SUCCESS)

Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.
bitnami@ip-172-30-0-111:/etc/chrony$ sudo systemctl start chrony
bitnami@ip-172-30-0-111:/etc/chrony$ sudo systemctl status chrony
● chrony.service - chrony, an NTP client/server
   Loaded: loaded (/lib/systemd/system/chrony.service; enabled; vendor preset: enabled)
   Active: active (running) since Sun 2020-06-28 14:51:24 JST; 3s ago
     Docs: man:chronyd(8)
           man:chronyc(1)
           man:chrony.conf(5)
  Process: 25274 ExecStart=/usr/sbin/chronyd $DAEMON_OPTS (code=exited, status=0/SUCCESS)
  Process: 25278 ExecStartPost=/usr/lib/chrony/chrony-helper update-daemon (code=exited, status=0/SUCCESS)
 Main PID: 25276 (chronyd)
    Tasks: 2 (limit: 535)
   Memory: 1.3M
   CGroup: /system.slice/chrony.service
           ├─25276 /usr/sbin/chronyd -F -1
           └─25277 /usr/sbin/chronyd -F -1

 6月 28 14:51:24 ip-172-30-0-111 systemd[1]: Starting chrony, an NTP client/server...
 6月 28 14:51:24 ip-172-30-0-111 chronyd[25276]: chronyd version 3.4 starting (+CMDMON +NTP +REFCLOCK +RTC +PRIVDROP +SCFILTER +SIGND +ASYNCDNS +SECHASH +IPV6 -DEBUG)
 6月 28 14:51:24 ip-172-30-0-111 chronyd[25276]: Frequency 6.546 +/- 0.030 ppm read from /var/lib/chrony/chrony.drift
 6月 28 14:51:24 ip-172-30-0-111 chronyd[25276]: Loaded seccomp filter
 6月 28 14:51:24 ip-172-30-0-111 systemd[1]: Started chrony, an NTP client/server.
bitnami@ip-172-30-0-111:/etc/chrony$

unattended-upgrade と メール送信

一応、このサーバーにも unattended-upgrade を入れておきます。

(参考) Debian 系で unattended-upgrades を有効にする場合の追加設定 (メール通知, autoremove, autoclean, 再起動) - Qiita

とは言っても、この stack では最初から unattended-upgrade が有効になっていたので、やることは autoremove, autoclean を追加で設定するのと、更新時にメールを送る設定だけです。

msmtp によるメール送信

以前よく使っていた smtp はメンテナンスされていないので、今は msmtp を使うほうが良いようです。

インストールします。

bitnami@ip-172-30-0-111:~$ sudo apt install msmtp msmtp-mta

設定ファイルのひな形をコピーします。

bitnami@ip-172-30-0-111:/etc$ sudo cp -p /usr/share/doc/msmtp/examples/msmtprc-user.example msmtprc

編集します。最終的に下記のような設定としました。

# Example for a user configuration file ~/.msmtprc
#
# This file focusses on TLS and authentication. Features not used here include
# logging, timeouts, SOCKS proxies, TLS parameters, Delivery Status Notification
# (DSN) settings, and more.


# Set default values for all following accounts.
defaults

# Use the mail submission port 587 instead of the SMTP port 25.
port 587

# Always use TLS.
tls on

# Set a list of trusted CAs for TLS. The default is to use system settings, but
# you can select your own file.
#tls_trust_file /etc/ssl/certs/ca-certificates.crt
# If you select your own file, you should also use the tls_crl_file command to
# check for revoked certificates, but unfortunately getting revocation lists and
# keeping them up to date is not straightforward.
#tls_crl_file ~/.tls-crls


# Syslog logging with facility LOG_MAIL instead of the default LOG_USER
syslog LOG_MAIL


# sakura via Amazon SES
account sakura_via_ses

# Host name of the SMTP server
host xxxxx.xxxxxx.amazonaws.com

# As an alternative to tls_trust_file/tls_crl_file, you can use tls_fingerprint
# to pin a single certificate. You have to update the fingerprint when the
# server certificate changes, but an attacker cannot trick you into accepting
# a fraudulent certificate. Get the fingerprint with
# $ msmtp --serverinfo --tls --tls-certcheck=off --host=smtp.freemail.example
#tls_fingerprint 00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33

# Envelope-from address
from xxxxx@mori-soft.com

# Authentication. The password is given using one of five methods, see below.
auth on
user (Amazon SES のユーザー名)

# Password method 1: Add the password to the system keyring, and let msmtp get
# it automatically. To set the keyring password using Gnome's libsecret:
# $ secret-tool store --label=msmtp \
#   host smtp.freemail.example \
#   service smtp \
#   user joe.smith

# Password method 2: Store the password in an encrypted file, and tell msmtp
# which command to use to decrypt it. This is usually used with GnuPG, as in
# this example. Usually gpg-agent will ask once for the decryption password.
#passwordeval gpg2 --no-tty -q -d ~/.msmtp-password.gpg

# Password method 3: Store the password directly in this file. Usually it is not
# a good idea to store passwords in plain text files. If you do it anyway, at
# least make sure that this file can only be read by yourself.
#password secret123
password (Amazon SES のパスワード)

# Password method 4: Store the password in ~/.netrc. This method is probably not
# relevant anymore.

# Password method 5: Do not specify a password. Msmtp will then prompt you for
# it. This means you need to be able to type into a terminal when msmtp runs.


# A second mail address at the same freemail service
#account freemail2 : freemail
#from joey@freemail.example


# The SMTP server of your ISP
#account isp
#host mail.isp.example
#from smithjoe@isp.example
#auth on
#user 12345


# Set a default account
account default : sakura_via_ses

今回は、直接自分のメールサーバーに送るのではなく、 Amazon SES 経由でメールを送ることにしました。これは、SES経由にして、送信先アドレスを指定したもの以外に送れなくするためです。

なお、SES の設定については、下記の記事を参照してください。 blog.mori-soft.com

設定ができたらテストしておきます。

bitnami@ip-172-30-0-111:/etc$ echo "mail test" | sudo msmtp -a default メール送信先のアドレス

syslog を見ると、メール送信のログが出ています。

Jun 29 09:27:29 ip-172-30-0-111 msmtp: host=xxxxx.xxxxxx.amazonaws.com tls=on auth=on user=(Amazon SES のユーザー名) from=xxxxx@mori-soft.com recipients=メール送信先のアドレス mailsize=76 smtpstatus=250 smtpmsg='250 Ok 01000172fd78c077-73fd5f8e-8e2c-426b-9be9-a932fc2a0290-000000' exitcode=EX_OK

実際に宛先のメールアドレスで確認すると、メールが受信できてました。

あとは、 unattended-upgrade がメールを送る際は mailx が必要なので、これをインストールすればOKです。

bitnami@ip-172-30-0-111:/etc/apt/apt.conf.d$ sudo apt install mailutils

(参考)

Let's Encrypt の設定

Birnami の Redmine スタックには Let's Encrypt による HTTPS の利用が簡単にできるようになっています。至れり尽くせりですね。

Generate and Install a Let's Encrypt SSL Certificate for a Bitnami Application

上記リンク先の手順に従って、設定したいと思います。 なお、設定開始前に、http(80)とhttps(443)でアクセスできるようにポートを開けておきます。

最初に動かすとツールを更新するか?と聞かれるので、yesを選択しておきます。

bitnami@ip-172-30-0-111:~/stack$ sudo ./bncert-tool 
An updated version is available. Would you like to download it? You would need to run it manually later. [Y/n]: y

The tool will exit now. To run the updated version run the following command: 

/opt/bitnami/bncert-tool 

bitnami@ip-172-30-0-111:~/stack$ 

ちなみに更新前のバージョン

lrwxrwxrwx  1 root    root         46  6月 10 02:15 bncert-tool -> /opt/bitnami/bncert/bncert-0.5.9-linux-x64.run

こちらが更新後のバージョン

lrwxrwxrwx  1 root    root         47  6月 27 16:06 bncert-tool -> /opt/bitnami/bncert/bncert-0.5.10-linux-x64.run*

もう一度、ツールを起動します。

bitnami@ip-172-30-0-111:~/stack$ sudo ./bncert-tool 
----------------------------------------------------------------------------
Welcome to the Bitnami HTTPS Configuration tool.

----------------------------------------------------------------------------
Domains

Please provide a valid space-separated list of domains for which you wish to 
configure your web server.

Domain list []: このサーバーのドメイン名

最初はドメイン名を入力します。

入力したのが、 www なしのドメイン名だったので、 www 付も作るか聞かれますが、なしにします。

The following domains were not included: www.このサーバーのドメイン名. Do you want to add them? [Y/n]: n

警告がでるので、一通り読んで、次に進みます。

Warning: No www domains (e.g. www.example.com) or non-www domains (e.g. 
www.example.com) have been provided, so the following redirections will be 
disabled: non-www to www, www to non-www.
Press [Enter] to continue:

HTTP -> HTTPS のリダイレクトです。 下記では、リダイレクトをしないとしてますが、実はあとから、リダイレクトありに変更しました(変更は再度同じツールを起動するだけでOKです)。

----------------------------------------------------------------------------
Enable/disable redirections

Please select the redirections you wish to enable or disable on your Bitnami 
installation.



Enable HTTP to HTTPS redirection [Y/n]: n

今から起きることが説明されるので、問題なければ y を入力します。

----------------------------------------------------------------------------
Changes to perform

The following changes will be performed to your Bitnami installation:

1. Stop web server
2. Configure web server to use a free Let's Encrypt certificate for the domains: 
このサーバーのドメイン名
3. Configure a cron job to automatically renew the certificate each month
4. Configure web server name to: このサーバーのドメイン名
5. Start web server once all changes have been performed



Do you agree to these changes? [Y/n]: y

メールアドレスを入力します。何かあるとき、 Let's Encrypt からメールが来ます。

----------------------------------------------------------------------------
Create a free HTTPS certificate with Let's Encrypt

Please provide a valid e-mail address for which to associate your Let's Encrypt 
certificate.

Domain list: このサーバーのドメイン名

Server name: このサーバーのドメイン名

E-mail address []: xxxxx@mori-soft.com

subscriber agreement を読んで同意するかどうか決めます。

The Let's Encrypt Subscriber Agreement can be found at:

https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf

Do you agree to the Let's Encrypt Subscriber Agreement? [Y/n]: y

設定処理の結果が表示されます。

----------------------------------------------------------------------------
Performing changes to your installation

The Bitnami HTTPS Configuration Tool will perform any necessary actions to your 
Bitnami installation. This may take some time, please be patient.

----------------------------------------------------------------------------
Success

The Bitnami HTTPS Configuration Tool succeeded in modifying your installation.

The configuration report is shown below.

Backup files:
* /opt/bitnami/apache2/conf/httpd.conf.back.202006271629
* /opt/bitnami/apache2/conf/bitnami/bitnami-apps-prefix.conf.back.202006271629
* /opt/bitnami/apache2/conf/bitnami/bitnami.conf.back.202006271629

Find more details in the log file:

/tmp/bncert-202006271629.log

If you find any issues, please check Bitnami Support forums at:

https://community.bitnami.com

Press [Enter] to continue:

bitnami@ip-172-30-0-111:~/stack$ 

特にエラーが表示されなければこれでOKです。 ブラウザから、指定したドメインに https でアクセスして問題なくアクセスできることを確認します。

最初にうまくいかなかった理由

さて、上記では何も問題がなかったように書きましたが、最初に設定した際はエラーになりました。その時はログにこんな感じのエラーが出てました。

2020/06/27 16:12:28 Could not obtain certificates:
        error: one or more domains had a problem:
[このサーバーのドメイン名] acme: error: 400 :: urn:ietf:params:acme:error:connection :: Timeout during connect (likely firewall problem), url: 

これは、AWS の セキュリティグループで https のアクセス元 ipアドレス を制限していたことが原因だったようです。

一時的にセキュリティグループの制限をなくすと、設定に成功し、その時のログを見ると、設定した証明書で正しく応答しているか確認しているとありました。

2020/06/27 16:30:47 [INFO] [このサーバーのドメイン名] Server responded with a certificate.

なので、IPアドレスで制限していたのがダメだったようです。

(参考) bitnami redmineにSSL証明書(Let's Encrypt)を導入する - Qiita

あと、cronjob に renew も登録されています。

bitnami@ip-172-30-0-111:~/stack$ crontab -u bitnami -l

0 0 * * * sudo /opt/bitnami/letsencrypt/lego --path /opt/bitnami/letsencrypt --email="xxxxx@mori-soft.com" --http --http-timeout 30 --http.webroot /opt/bitnami/apps/letsencrypt --domains=このサーバーのドメイン名 renew && sudo /opt/bitnami/apache2/bin/httpd -f /opt/bitnami/apache2/conf/httpd.conf -k graceful # bncert-autorenew
bitnami@ip-172-30-0-111:~/stack$ 

cron と同じコマンドを発行してみて、動作確認しておきます。

bitnami@ip-172-30-0-111:~/stack/letsencrypt$ sudo /opt/bitnami/letsencrypt/lego --path /opt/bitnami/letsencrypt --email="xxxxx@mori-soft.com" --http --http-timeout 30 --http.webroot /opt/bitnami/apps/letsencrypt --domains=このサーバーのドメイン名 renew
2020/06/29 11:05:29 [このサーバーのドメイン名] The certificate expires in 88 days, the number of days defined to perform the renewal is 30: no renewal.
bitnami@ip-172-30-0-111:~/stack/letsencrypt$ 

大丈夫そうですね。

送信元IPアドレス制限と http でのアクセス

元々 Redmine のサーバーは自分の仕事の管理で使っているので、EC2 のセキュリティグループを使って送信元のIPアドレスを制限していました。また、 http でのアクセスも禁止していました。 今回はこれらに加えて、 Let's Encrypt の更新を有効にしたいと思います。

この条件を整理すると、下記のような動作になると思います。

  • サーバーには https でのみアクセスする
  • 送信元 IP アドレスを制限する
  • Let's Encrypt による更新(http を利用)を有効にする

これを実現するために、 Let's Encrypt の http -> https 転送を設定しました。 この転送設定(/opt/bitnami/apache2/conf/bitnami/bitnami.conf に設定があります)では、

  # BEGIN: Enable HTTP to HTTPS redirection
  RewriteEngine On
  RewriteCond %{HTTPS} !=on
  RewriteCond %{HTTP_HOST} !^localhost
  RewriteCond %{HTTP_HOST} !^[0-9]+.[0-9]+.[0-9]+.[0-9]+(:[0-9]+)?$
  RewriteCond %{REQUEST_URI} !^/\.well-known
  RewriteRule ^/(.*) https://%{SERVER_NAME}/$1 [R,L]
  # END: Enable HTTP to HTTPS redirection

となっています。一部の条件に当てはまるもの以外は https へ転送しています。この一部の条件とは

  • localhost へのアクセス
  • IP アドレスへのアクセス
  • /.well-known へのアクセス

です。なので、 サーバー名/.well-known へのアクセスは https へ転送されないとなっています。

これを踏まえて、セキュリティグループの設定として

  • http は送信元IPアドレス制限なし
  • https は送信元IPアドレス制限あり

としておけば、 http でアクセスした際は、基本的に https に転送され、https は送信元IPアドレスが制限されているので、許可されたIPアドレスから接続するクライアント以外からは接続できなくなります。

一方、Let's Encrypt が更新に使う /.well-known ディレクトリへの http でのアクセスは https に転送されないので、送信元IPアドレスにかかわらず接続できます。

こうすることで、目的のアクセス制御ができました。

一応、最終的には、

  # BEGIN: Enable HTTP to HTTPS redirection
  RewriteEngine On
  RewriteCond %{HTTPS} !=on
  RewriteCond %{HTTP_HOST} !^localhost
  #RewriteCond %{HTTP_HOST} !^[0-9]+.[0-9]+.[0-9]+.[0-9]+(:[0-9]+)?$
  RewriteCond %{REQUEST_URI} !^/\.well-known
  RewriteRule ^/(.*) https://%{SERVER_NAME}/$1 [R,L]
  # END: Enable HTTP to HTTPS redirection

として、IPアドレスによる接続も、 https に転送するようにしています(証明書的には意味がありませんが、送信元IPアドレス制限を使いたいためです)。