完全無料。GCE で公開している HTTP サーバを Freenom 独自ドメイン + Let's Encrypt で HTTPS 化した

無料枠の GCE (Google Compute Engine) インスタンスを使って、Apache サーバを公開している。コレまでサーバ証明書を用意していなかったので、IP アドレス直打ちの HTTP でしかアクセスできなかった。

今回この環境を、無料で独自ドメインが取得できる Freenom と、無料でサーバ証明書が取得できる Let's Encrypt を使って、完全無料で HTTPS 化することにした。

目次

前提条件

Freenom でドメイン取得・DNS 設定

まずは Freenom でドメインを取得する。今回は neos21-gce.ga というドメインを取った。

ドメインを取得する際でも良いし、取得後の画面でも良いが、Freenom DNS の設定画面を開く。

そしたら次のキャプチャのように設定する。

Freenom 設定

Name Type TTL Target
(空白) A 300 【GCE の Public IP】
www A 300 【GCE の Public IP】

いわゆる「A レコード」を指定している。このドメインはこの IP アドレスに紐付けるぞー、という指定。

設定後、5~10分くらいすると、取得した独自ドメインで GCE に対して HTTP アクセスができるようになっているはず。

HTTPS でアクセスしようとすると、証明書エラーの警告が出る状態であろう。

Let's Encrypt でサーバ証明書を取得する

HTTP アクセスができるようになったら、続いてサーバ証明書の取得に移る。

GCE インスタンスに SSH 接続し、次のように叩いていく。

$ yum install -y epel-release
$ yum install -y certbot python-certbot-apache

# Apache で公開しているディレクトリと、取得したドメイン名を指定する
$ certbot certonly --webroot -w /var/www/html -d neos21-gce.ga
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
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for neos21-gce.ga
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/neos21-gce.ga/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/neos21-gce.ga/privkey.pem
   Your cert will expire on 2020-08-25. 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"
 - 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/neos21-gce.ga/
合計 4
-rw-r--r-- 1 root root 692 2020-05-27 18:25 README
lrwxrwxrwx 1 root root  37 2020-05-27 18:25 cert.pem -> ../../archive/neos21-gce.ga/cert1.pem
lrwxrwxrwx 1 root root  38 2020-05-27 18:25 chain.pem -> ../../archive/neos21-gce.ga/chain1.pem
lrwxrwxrwx 1 root root  42 2020-05-27 18:25 fullchain.pem -> ../../archive/neos21-gce.ga/fullchain1.pem
lrwxrwxrwx 1 root root  40 2020-05-27 18:25 privkey.pem -> ../../archive/neos21-gce.ga/privkey1.pem

Apache 設定ファイルにサーバ証明書を読み込ませる

コレだけだと Let's Encrypt のサーバ証明書を取得しただけで、Apache サーバがこの証明書を利用していないので、状況が変わらない。

次の設定ファイルを開き、以下の抜粋のとおりに編集する。

$ vi /etc/httpd/conf.d/ssl.conf

元の行と、書き換えた行を記載している。ディレクトリパスなどは各自のモノに読み替えること。

#   Server Certificate:
# Point SSLCertificateFile at a PEM encoded certificate.  If
# the certificate is encrypted, then you will be prompted for a
# pass phrase.  Note that a kill -HUP will prompt again.  A new
# certificate can be generated using the genkey(1) command.

# Original
#SSLCertificateFile /etc/pki/tls/certs/localhost.crt
# My Domain
SSLCertificateFile /etc/letsencrypt/live/neos21-gce.ga/cert.pem

#   Server Private Key:
#   If the key is not combined with the certificate, use this
#   directive to point at the key file.  Keep in mind that if
#   you've both a RSA and a DSA private key you can configure
#   both in parallel (to also allow the use of DSA ciphers, etc.)

# Original
#SSLCertificateKeyFile /etc/pki/tls/private/localhost.key
# My Domain
SSLCertificateKeyFile /etc/letsencrypt/live/neos21-gce.ga/privkey.pem

#   Server Certificate Chain:
#   Point SSLCertificateChainFile at a file containing the
#   concatenation of PEM encoded CA certificates which form the
#   certificate chain for the server certificate. Alternatively
#   the referenced file can be the same as SSLCertificateFile
#   when the CA certificates are directly appended to the server
#   certificate for convinience.

# Original (Comment-out)
#SSLCertificateChainFile /etc/pki/tls/certs/server-chain.crt
# My Domain
SSLCertificateChainFile /etc/letsencrypt/live/neos21-gce.ga/chain.pem

設定ファイルを書き換えたら、Apache サーバを再起動する。

$ systemctl restart httpd

なぜか再起動が上手く行かず

当方環境ではなぜか Apache サーバの再起動が上手く行かなくて詰まった。

# よー分からん
$ systemctl status httpd
● httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled)
   Active: failed (Result: exit-code) since 水 2020-05-27 18:44:23 JST; 3min 58s ago
     Docs: man:httpd(8)
           man:apachectl(8)
  Process: 29373 ExecStop=/bin/kill -WINCH ${MAINPID} (code=exited, status=1/FAILURE)
  Process: 21731 ExecReload=/usr/sbin/httpd $OPTIONS -k graceful (code=exited, status=0/SUCCESS)
  Process: 29372 ExecStart=/usr/sbin/httpd $OPTIONS -DFOREGROUND (code=exited, status=0/SUCCESS)
 Main PID: 29372 (code=exited, status=0/SUCCESS)

 527 18:44:23 gce systemd[1]: Starting The Apache HTTP Server...
 527 18:44:23 gce httpd[29372]: httpd (pid 15739) already running
 527 18:44:23 gce kill[29373]: kill: cannot find process ""
 527 18:44:23 gce systemd[1]: httpd.service: control process exited, code=exited status=1
 527 18:44:23 gce systemd[1]: Failed to start The Apache HTTP Server.
 527 18:44:23 gce systemd[1]: Unit httpd.service entered failed state.
 527 18:44:23 gce systemd[1]: httpd.service failed.
 527 18:46:08 gce systemd[1]: Unit httpd.service cannot be reloaded because it is inactive.
 527 18:48:17 gce systemd[1]: Unit httpd.service cannot be reloaded because it is inactive.

# やっぱり分からん
$ journalctl -xe
 527 18:48:44 gce systemd[1]: Starting The Apache HTTP Server...
-- Subject: Unit httpd.service has begun start-up
-- Defined-By: systemd
-- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
--
-- Unit httpd.service has begun starting up.
 527 18:48:44 gce httpd[29789]: httpd (pid 15739) already running
 527 18:48:44 gce kill[29790]: kill: cannot find process ""
 527 18:48:44 gce systemd[1]: httpd.service: control process exited, code=exited status=1
 527 18:48:44 gce systemd[1]: Failed to start The Apache HTTP Server.
-- Subject: Unit httpd.service has failed
-- Defined-By: systemd
-- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
--
-- Unit httpd.service has failed.
--
-- The result is failed.
 527 18:48:44 gce systemd[1]: Unit httpd.service entered failed state.
 527 18:48:44 gce systemd[1]: httpd.service failed.

# こうなってる
$ apachectl
httpd (pid 29997) already running

# 設定ファイルに記述誤りがあるワケではない模様
$ apachectl -t
Syntax OK

設定ファイルの書き間違いだとそういう文言がエラーメッセージに出てくるのだが、そうではないようだった。

他に原因が見当たらなかったので、httpd already running というところかなと思い、$ pkill httpd で一旦強引に全ての httpd プロセスを切った。

それから $ systemctl start httpd でやり直したら上手くいった。よかった。

アクセスしてみる

設定が終わったら HTTPS でアクセスしてみる。

無事アクセスできた。おけおけ。

サーバ証明書を自動更新する

Let's Encrypt の証明書は3ヶ月ごとに切れるので、毎月ぐらいのペースで

$ certbot renew && systemctl restart httpd

を実行するよう cron を書いておくと良さそう。

# crontab を編集する
$ crontab -u root -e
no crontab for root - using an empty one
crontab: installing new crontab

# 内容を確認する
$ crontab -u root -l
00 03 01 * * certbot renew && systemctl restart httpd

以上。