無料サーバー証明書の導入

無料のサーバー証明書Let's Encryptから発行できるので試してみました。ただし、固定グローバルIPアドレスのサーバーは用意できないので、外部公開はダイナミックDNSサービスを使用します。

CentOS7のインストール

以前の記事を参考に設定します。今回もインストールメディアは、CentOS7(7.7.1908)を使用します。

インストール設定は、以下のとおりです。

  • インストール時に使用する言語 : 日本語
  • 日付と時刻 : アジア/東京 タイムゾーン
  • キーボード : 日本語
  • 言語サポート : 日本語(日本)
  • インストールソース : ローカルメディア
  • ソフトウェアの選択 : 最小限のインストール
  • インストール先 : パーティションを自動構成
  • KDUMP : 有効
  • ネットワークとホスト名 : 未設定
  • SECURITY PROFILE : 未設定
  • ユーザーの作成 : ユーザーを作成(管理者権限は付与しない)

OSインストール後の設定

OSインストール後の設定は、以下のとおりです。

SELinuxFirewallを無効に設定

SELinuxFirewallを無効設定します。

# setenforce 0
# vi /etc/sysconfig/selinux
 SELINUX=disabled

# systemctl stop firewalld
# systemctl disable firewalld

システム設定の変更

システム設定を変更します。

CTRL-ALT-DELでの再起動を抑止します。
# systemctl mask ctrl-alt-del.target
Created symlink from /etc/systemd/system/ctrl-alt-del.target to /dev/null.

連続でCTRL-ALT-DELを押し続けた時の再起動を抑止します。
# vi /etc/systemd/system.conf
 [Manager]
 CtrlAltDelBurstAction=none

抑止設定を反映させます。
# systemctl daemon-reexec

messagesログを確認しながら、CTRL-ALT-DELキーを連続で押し続けて、再起動が発生しないことを確認します。
※systemdのバージョンが223以降でないと抑止設定は反映されません。
# tail -f /var/log/messages

ネットワーク設定

IPアドレスなどを設定します。

ホスト名とIPアドレスを設定します。
# nmtui
※プロンプトのホスト名は、再ログイン時に更新されます。

pingで外部との疎通を確認します。
# ping www.yahoo.co.jp

パッケージの追加とシステムの更新

外部との接続が確認できたので、パッケージの追加とシステムの更新をおこないます。

必要と思うパッケージをインストールします。
# yum install bash-completion net-tools

システムを更新します。
# yum update
※kernelも最新のバージョンに更新します。

不要なログ出力を抑止

/var/log/messagesに出力するログを減らすように修正します。

不要な設定をコメントアウトします。
# vi /usr/lib/systemd/system/firstboot-graphical.service
 #SysVStartPriority=99

CentOS7のmdadm-4.1-4には不具合があるので、CentOS8のmdadm4-1.13を参考に設定ファイルを修正します。

設定ファイルを修正します。
# vi /usr/lib/systemd/system/mdcheck_start.timer
 #OnCalendar=Sun *-*-1..7 1:00:00
 OnCalendar=Sun *-*-1,2,3,4,5,6,7 1:00:00

# vi /usr/lib/systemd/system/mdcheck_start.service
 #Environment= MDADM_CHECK_DURATION="6 hours"
 Environment="MDADM_CHECK_DURATION=6 hours"

# vi /usr/lib/systemd/system/mdcheck_continue.service
 #Environment= MDADM_CHECK_DURATION="6 hours"
 Environment="MDADM_CHECK_DURATION=6 hours"

使用しないパッケージを削除して、ログ出力を減らします。

指紋認証デーモンの削除
# yum remove fprintd

Webサーバーのセットアップ

Webサーバー(Apache 2.4)をインストールします。

インストール可能なパッケージグループを確認します。
# yum grouplist 

環境構築に必要なパッケージをインストールします。
# yum groupinstall "Server with GUI"
# yum groupinstall "Basic Web Server"

Webサービスを開始します。
# systemctl enable httpd
# systemctl start httpd

システムの再起動

起動モードを変更して、再起動します。

デフォルトの起動モードをGUIに変更して、再起動します。
# systemctl set-default graphical.target
# reboot

GUI環境の設定

GUI環境の設定は、以下のとおりです。

  • 言語 : 日本語
  • 入力 : 日本語(かな漢字)
  • 位置情報サービス : オン
  • オンラインアカウント : スキップ

Firefoxhttp://localhost/にアクセスして、Webサービスが稼働していることを確認します。

f:id:uso59634:20200624204035p:plain
Webサービスの稼働確認

ポートフォワード設定

ルーターにポートフォワード設定を追加して、外部からWebサーバーにアクセスできるようにします。

ポートフォワード設定方法は、ルーターの機種によって異なるので割愛しますが、設定内容は以下のとおりです。

転送先IPアドレス プロトコル ポート範囲
Webサーバーに設定したIPアドレス TCP 80 - 80
Webサーバーに設定したIPアドレス TCP 443 - 443

ダイナミックDNSサービスの設定とアクセス確認

ダイナミックDNSサービスは、無料で使用できるMyDNS.JPを選びました。

ダイナミックDNSサービスの初期登録

手順の詳細は割愛しますが、以下の作業をおこないました。

  1. 新規利用なので、ユーザー登録をおこないます。
  2. ルーターWAN側に割り当てられているグローバルIPアドレスを、取得したドメイン名に登録します。

グローバルIPアドレスは、MyDNS.JPサイトのトップページ(赤枠部分)から確認できます。

f:id:uso59634:20200626021810p:plain
グローバルIPアドレスの確認

ドメイン情報を登録します。

f:id:uso59634:20200706210548p:plain
ドメイン情報登録

Webサーバーの設定変更

ダイナミックDNSサービスで設定したホスト名をhttpd.confに設定します。

ホスト名を設定します。
# vi /etc/httpd/conf/httpd.conf
 ServerName www.xxxxx.mydns.jp

設定ファイルを再読み込みします。
# systemctl reload httpd

外部からのアクセス確認

スマホ(キャリア回線)から、取得したホスト名にHTTPおよびHTTPSでアクセスできることを確認します。

HTTPでアクセスできることを確認します。

f:id:uso59634:20200626010348p:plain
外部からのHTTPアクセス

HTTPSでアクセスできることを確認します。ただし、正しいサーバー証明書がインストールされていないので、警告が表示されます。

f:id:uso59634:20200629015418p:plain
外部からのHTTPSアクセス

ダイナミックDNSサービスへのIPアドレス自動登録

フリーソフトDiCEを使用して、ダイナミックDNSサービスにIPアドレスを自動登録するように設定します。

DiCEのインストール

ダウンロードしたDiCEを展開します。
# tar xvzf ./diced01914.tar.gz 
# cp ./DiCE/ /opt/ -r
# rm ./DiCE -rf

DiCEを動作させるのに必要な32bitパッケージをインストールします。
# yum install libstdc++
# yum install libstdc++.i686

DiCEの日本語文字化け対策にnkfパッケージをインストールします。
# yum install epel-release
# yum install nkf

IPアドレスの検出方法と更新間隔の設定

# /opt/DiCE/diced | nkf -uw
=-=-=- DiCE DynamicDNS Client -=-=-=
Version 0.19 for Japanese
Copyright(c) 2001 sarad
:setup
IPアドレスの検出方法を指定してください
(0) 自動検出
(1) ローカルのネットワークアダプタから検出
(2) 外部のスクリプトから検出
<現在:0>
(N)変更しない  (P)戻る
>2
-------------------------------------------------
スクリプトのURLを入力してください
<現在:>
(N)変更しない  (P)戻る
>http://info.ddo.jp/remote_addr.php
-------------------------------------------------
プライベートIPアドレスも検出対象ですか? (Y/N)
<現在:いいえ>
(P)戻る
>n
-------------------------------------------------
IPアドレスの検出をテストしますか? (Y/N)
(P)戻る
>y
検出IPアドレス>xxx.xxx.xxx.249
-------------------------------------------------
IPアドレスの検出をテストしますか? (Y/N)
(P)戻る
>n
-------------------------------------------------
IPアドレスをチェックする間隔を指定してください(分)
設定可能範囲は5分以上です
<現在:10>
(N)変更しない  (P)戻る
>n
=================================================
DNSサーバーの負荷を軽減するために頻繁なDNS更新を防ぐ必要があります
前回の更新から一定時間DNS更新処理を行わないように保護時間を設定して
ください(分)  設定可能範囲は10分から1440分です
<現在:60>
(N)変更しない  (P)戻る
>20
=================================================
設定を保存しますか? (Y/N)
(P)戻る
>y
設定を保存しました
=================================================
:

続いて、使用するダイナミックDNSサービスと更新間隔を設定します。

:add
新しくイベントを追加します

DynamicDNSサービス名を入力してください
"?"で対応しているサービスを一覧表示します
(P)戻る
>MyDNS.JP
-------------------------------------------------
<< MyDNS.JP >>
URL: http://www.mydns.jp/
*** 情報 ***
ドメイン名、ホスト名についてはマスターID(ユーザー名)にて管理されています。
IPアドレスはサーバー側で自動検出します。
(これらは入力しても無視されます)
=================================================
ドメイン名を入力してください
"?"でドメイン一覧を表示します
(P)戻る
>xxxxx.mydns.jp ※マスターIDにて管理されているので、入力しても無視されます。
=================================================
ホスト名を入力してください
(P)戻る
>www ※マスターIDにて管理されているので、入力しても無視されます。
=================================================
ログインユーザ名を入力してください
(P)戻る
>mydnsxxxxxx
=================================================
ログインパスワードを入力してください
(P)戻る
>xxxxxxxxxxx
=================================================
登録するIPアドレスを入力してください
空白にすると現在のIPアドレスを自動検出します
(P)戻る
>
=================================================
このイベントに題名を付けてください
(P)戻る
>Update_MyDNS.JP
=================================================
このイベントを実行するスケジュールを設定します
-------------------------------------------------
実行する頻度を指定してください (番号入力)
(0)1回のみ (1)1日1回 (2)1週間に1回 (3)1ヵ月に1回
(4)その他の周期 (5)IPアドレス変化時 (6)起動時
(P)戻る
>5
-------------------------------------------------
IPアドレスがあまり変化しない環境の場合、更新せずに一定期間を過ぎると
アカウントを削除されてしまうことがあります
IPアドレスの変化が無い時に実行する間隔を指定してください
(0)7日毎   (1)14日毎  (2)21日毎  (3)28日毎
(4)35日毎  (5)56日毎  (6)84日毎
(P)戻る
>1
=================================================
=================================================
このイベントを有効にしますか? (Y/N)
(イベントの有効/無効は"EN/DIS"コマンドで切替えられます)
>y
=================================================
イベントを保存しますか? (Y/N)
>y
イベント"Update_MyDNS.JP"を保存しました
=================================================
:

更新イベントを実行して、正常に動作することを確認します。

:ex 0
+ xx/xx xx:xx にUpdate_MyDNS.JPが実行されました
  IPアドレスを更新しました
:exit
#

DiCEをサービスとして登録

DiCEをサービスとして登録します。設定ファイルについては、こちらを参考にしました。

DiCEのサービス用設定ファイルを作成します。
# vi /usr/lib/systemd/system/dice.service
 [Unit]
 Description=The DiCE Server
 After=network.target remote-fs.target nss-lookup.target

 [Service]
 Type=simple
 ExecStart=/opt/DiCE/diced -s -l
 ExecReload=/bin/kill -HUP ${MAINPID}
 ExecStop=/bin/kill ${MAINPID}
 PrivateTmp=true

 [Install]
 WantedBy=multi-user.target

設定ファイルの再読み込みをおこないます。
# systemctl daemon-reload

システム起動時に自動起動するように設定します。
# systemctl enable dice.service

サービスを開始します。
# systemctl start dice.service

サーバー証明書の導入

Let's Encrpytからサーバー証明書を発行します。手順については、こちらを参考にしました。

必要なパッケージのインストール

サーバー証明書の発行に必要なパッケージをインストールします。

EPELリポジトリを追加して、必要なパッケージをインストールします。
# yum install epel-release
# yum install certbot python-certbot-apache

サーバー証明書の発行

DocumentRootのパスは、デフォルトの/var/www/html/とします。

certbotコマンドについては、こちらを参照してください。

ドメイン名とホスト名用のサーバー証明書を作成します。
# certbot certonly --webroot -w /var/www/html/ -d xxxxx.mydns.jp -d www.xxxxx.mydns.jp \
 --agree-tos -m (連絡先メールアドレス)

Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator webroot, Installer None
Starting new HTTPS connection (1): acme-v02.api.letsencrypt.org

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
Would you be willing to share your email address with the Electronic Frontier
Foundation, a founding partner of the Let's Encrypt project and the non-profit
organization that develops Certbot? We'd like to send you email about our work
encrypting the web, EFF news, campaigns, and ways to support digital freedom.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: n ※初回のみ表示
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for xxxxx.mydns.jp
http-01 challenge for www.xxxxx.mydns.jp
Using the webroot path /var/www/html for all unmatched domains.
Waiting for verification...
Cleaning up challenges

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/xxxxx.mydns.jp/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/xxxxx.mydns.jp/privkey.pem
   Your cert will expire on 2020-xx-xx. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot
   again. To non-interactively renew *all* of your certificates, run
   "certbot renew"
 - Your account credentials have been saved in your Certbot
   configuration directory at /etc/letsencrypt. You should make a
   secure backup of this folder now. This configuration directory will
   also contain certificates and private keys obtained by Certbot so
   making regular backups of this folder is ideal.
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le

#

発行されたサーバー証明書を確認します。

# ls -l /etc/letsencrypt/live/xxxxx.mydns.jp/
合計 4
-rw-r--r-- 1 root root 692  xx月 xx xx:xx README
lrwxrwxrwx 1 root root  41  xx月 xx xx:xx cert.pem -> ../../archive/xxxxx.mydns.jp/cert1.pem
lrwxrwxrwx 1 root root  42  xx月 xx xx:xx chain.pem -> ../../archive/xxxxx.mydns.jp/chain1.pem
lrwxrwxrwx 1 root root  46  xx月 xx xx:xx fullchain.pem -> ../../archive/xxxxx.mydns.jp/fullchain1.pem
lrwxrwxrwx 1 root root  44  xx月 xx xx:Xx privkey.pem -> ../../archive/xxxxx.mydns.jp/privkey1.pem

SSL設定の変更

発行されたサーバー証明書を使用するように設定を変更します。

# vi /etc/httpd/conf.d/ssl.conf
 デフォルトの設定を変更します。
 SSLCertificateFile /etc/letsencrypt/live/xxxxx.mydns.jp/cert.pem
 SSLCertificateKeyFile /etc/letsencrypt/live/xxxxx.mydns.jp/privkey.pem
 SSLCertificateChainFile /etc/letsencrypt/live/xxxxx.mydns.jp/chain.pem

設定ファイルを再読み込みします。

# systemctl reload httpd

外部からのHTTPSアクセスの確認

スマホ(キャリア回線)からHTTPSアクセスを確認します。

警告が表示されないので、サーバー証明書に問題がないことが確認できます。

f:id:uso59634:20200701014206p:plain
外部からのHTTPSアクセス

サーバー証明書の更新

Let’s Encryptから発行したサーバー証明書の有効期限が90日なので、定期的に更新をおこなうようにスケジュールを設定します。

サーバー証明書の更新テスト

スケジュールを設定する前に、--dry-runオプションを指定して、サーバー証明書の更新に問題がないかテストします。

# certbot renew --dry-run
(省略)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
** DRY RUN: simulating 'certbot renew' close to cert expiry
**          (The test certificates below have not been saved.)

Congratulations, all renewals succeeded. The following certs have been renewed: ※テスト成功
  /etc/letsencrypt/live/xxxxx.mydns.jp/fullchain.pem (success) 
** DRY RUN: simulating 'certbot renew' close to cert expiry
**          (The test certificates above have not been saved.)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(省略)

更新テストに問題がないことが確認できました。

更新スクリプトの設定

サーバー証明書の更新は、certbotパッケージのスクリプトを使用して更新スケジュールを設定します。

certbotパッケージの内容を確認します。
# rpm -ql certbot
(省略)
/usr/lib/systemd/system/certbot-renew.service
/usr/lib/systemd/system/certbot-renew.timer
(省略)

certbot-renew.timerの内容を確認します。

# cat /usr/lib/systemd/system/certbot-renew.timer
[Unit]
Description=This is the timer to set the schedule for automated renewals

[Timer]
OnCalendar=*-*-* 00/12:00:00
RandomizedDelaySec=12hours
Persistent=true

[Install]
WantedBy=timers.target

0時と12時に実行(最大12時間のランダムな遅延)するよう設定されています。

certbot-renew.serviceの内容を確認します。

# cat /usr/lib/systemd/system/certbot-renew.service
[Unit]
Description=This service automatically renews any certbot certificates found

[Service]
EnvironmentFile=/etc/sysconfig/certbot
Type=oneshot
ExecStart=/usr/bin/certbot renew --noninteractive --no-random-sleep-on-renew $PRE_HOOK $POST_HOOK $RENEW_HOOK $DEPLOY_HOOK $CERTBOT_ARGS

ExecStartに設定したコマンドを一度だけ実行(Type=oneshot)するように設定されています。

サーバー証明書の更新が成功した時の動作を/etc/sysconfig/certbotに設定します。こちらを参考にしました。

# vi /etc/sysconfig/certbot
 サーバー証明書の更新が成功した時に実行するコマンドを設定します。
 DEPLOY_HOOK="--post-hook 'systemctl reload httpd'" 

更新スケジュールの設定

更新スケジュールを設定します。

有効なsystemdタイマー(スケジュール)を確認します。
# systemctl list-timers 
NEXT                         LEFT    LAST                         PASSED  UNIT                         ACTIVATES
x  2020-xx-xx 00:00:00 JST  6h left x  2020-xx-xx 00:48:21 JST  16h ago unbound-anchor.timer         unbound-anchor.service
x  2020-xx-xx 01:03:10 JST  7h left x  2020-xx-xx 01:03:10 JST  16h ago systemd-tmpfiles-clean.timer systemd-tmpfiles-clean.service

2 timers listed.
Pass --all to see loaded but inactive timers, too.

システム起動時にcertbot-renew.timerが起動するように設定します。
# systemctl enable certbot-renew.timer 
Created symlink from /etc/systemd/system/timers.target.wants/certbot-renew.timer to /usr/lib/systemd/system/certbot-renew.timer.

certbot-renew.timerを開始します。
# systemctl start certbot-renew.timer 

certbot-renew.timerがスケジュールに登録されたことを確認します。
# systemctl list-timers 
NEXT                         LEFT     LAST                         PASSED  UNIT                         ACTIVATES
X 2020-xx-xx 00:00:00 JST  6h left  X 2020-xx-xx 00:48:21 JST  17h ago unbound-anchor.timer         unbound-anchor.service
X 2020-xx-xx 01:03:10 JST  7h left  X 2020-xx-xx 01:03:10 JST  16h ago systemd-tmpfiles-clean.timer systemd-tmpfiles-clean.service
X 2020-xx-xx xx:xx:xx JST 12h left  n/a                        n/a     certbot-renew.timer          certbot-renew.service

3 timers listed.
Pass --all to see loaded but inactive timers, too.

スケジュールの実行と確認

スケジュールから呼び出すサービスを手動実行して、サーバー証明書を更新します。

サーバー証明書の有効期限まで30日以上残っていると更新されないので、一時的に更新を強制する設定にします。

# vi /etc/sysconfig/certbot
 CERTBOT_ARGS="--force-renewal"

実行前に、現在のサーバー証明書の有効期間を確認しておきます。

f:id:uso59634:20200718161638p:plain
更新前の確認

certbot-renew.timerが呼び出すcertbot-renew.serviceサービスを手動で実行します。

# systemctl start certbot-renew.service

実行後、ログを確認します。
# tail /var/log/messages -n 30
(省略)
 xxx x xx:xx:xx xxxxx systemd: Starting This service automatically renews any certbot certificates found...
 xxx x xx:xx:xx xxxxx certbot: Saving debug log to /var/log/letsencrypt/letsencrypt.log
 xxx x xx:xx:xx xxxxx certbot: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 xxx x xx:xx:xx xxxxx certbot: Processing /etc/letsencrypt/renewal/xxxxx.mydns.jp.conf
 xxx x xx:xx:xx xxxxx certbot: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 xxx x xx:xx:xx xxxxx certbot: Plugins selected: Authenticator webroot, Installer None
 xxx x xx:xx:xx xxxxx certbot: Starting new HTTPS connection (1): acme-v02.api.letsencrypt.org
 xxx x xx:xx:xx xxxxx certbot: Renewing an existing certificate
 xxx x xx:xx:xx xxxxx certbot: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 xxx x xx:xx:xx xxxxx certbot: new certificate deployed without reload, fullchain is
 xxx x xx:xx:xx xxxxx certbot: /etc/letsencrypt/live/xxxxx.mydns.jp/fullchain.pem
 xxx x xx:xx:xx xxxxx certbot: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 xxx x xx:xx:xx xxxxx certbot: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 xxx x xx:xx:xx xxxxx certbot: Congratulations, all renewals succeeded. The following certs have been renewed:
 xxx x xx:xx:xx xxxxx certbot: /etc/letsencrypt/live/xxxxx.mydns.jp/fullchain.pem (success)
 xxx x xx:xx:xx xxxxx certbot: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 xxx x xx:xx:xx xxxxx certbot: Running post-hook command: systemctl reload httpd
 xxx x xx:xx:xx xxxxx systemd: Reloading The Apache HTTP Server.
 xxx x xx:xx:xx xxxxx systemd: Reloaded The Apache HTTP Server.
 xxx x xx:xx:xx xxxxx systemd: Started This service automatically renews any certbot certificates found.

問題なく完了できたことが確認できます。

一時的な設定変更を元に戻します。

# vi /etc/sysconfig/certbot
 CERTBOT_ARGS=""

サーバー証明書が更新されたことを確認します。

f:id:uso59634:20200718162010p:plain
更新後の確認

常時SSL化HTTPSへのリダイレクト)

サーバー証明書が利用できるようになったので、こちらを参考にして、HTTPSにリダイレクトするように設定します。

httpd.confの末尾に、以下のように追記して、設定ファイルを再読み込みします。

# vi /etc/httpd/conf/httpd.conf
 RewriteEngine on
 RewriteCond %{HTTPS} off
 RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

# systemctl reload httpd

サイトにアクセスして、リダイレクトが成功していることを確認します。