👣

Let's EncryptでワイルドカードなSSLサーバー証明書が安価なVPSとDNSでマルチドメインWEBサーバーな話

2021/09/09に公開

はじめに

前置き

  • タイトルから感じ取れるとおり、この記事はゆるいメモです。ご了承ください。
  • ゆるいメモですので、端折るところはごっそり端折っています。ご了承ください。
  • メモと言いつつ、誰かに話しかけるような文体になっています。未来の自分に話しかけています。ご了承ください。

ゆるいメモと言いましたが、一つ一つメモを記載していったところ、まったくゆるくなくなっていました。必要な個所だけ参照されるのが良いかと思います。

Let's Encryptについて

さて、まずはLet's Encryptについて本記事に関連することを少し。

  • Let's Encryptでワイルドカード証明書を取得(新規発行および更新)するにはDNS認証を行う必要があります。
  • DNS認証を行うにあたっては、証明書発行のタイミングで、対象のドメインのDNSにTXTレコードを登録する必要があります。
    つまり、Let's Encryptでワイルドカード証明書を取得するには、何らかの仕組み(というかAPI)で外部からレコードを制御できるDNSを利用する必要があります。

Let's EncryptのツールのCertbotは、DNS認証を行うプラグインを利用できます。
プラグインは、代表的なDNSサービスのものが用意されています。
https://certbot.eff.org/docs/using.html?highlight=dns#dns-plugins
これを利用することで、比較的簡単にDNS認証を実現できます。

あるいは、独自のプラグインを組むこともできます。
https://certbot.eff.org/docs/using.html?highlight=dns#manual
ネットを検索すると、実際に独自プラグインを組んで自動更新を実現している方もいらっしゃるので興味があると同様にやってみると良いかも知れません。

本題

この記事は、前述のようなLet's Encryptでワイルドカード証明書を発行、自動更新の仕組みを構築した際のメモを整理したものです。

  • DNSは、DNSプラグインが用意されているさくらのクラウドを利用します。
    月額44円と、とても安価です。

  • WEBサーバーはWebARENA Indigo(Linux)のメモリ1GBのVPSを利用します。
    月額349円と、とても安価です。

  • ドメインの取得(と管理)は、お名前.comを利用します。
    ただただ安いです。

ワイルドカード証明書の更新自動化のための追加費用という意味では、DNS利用料の月額44円くらいですので、とても安価です。

前提

参考まで、前述の各サービスと、利用しているツールは以下のとおりです。
※ちなみに、ローカル環境は Windowsです。

各サービス

利用ツール

その他必要なもの

  • 有料サービスを利用するため、クレジットカードなど決済手段も必要です、念のため

手順概要

大まかな流れは以下のとおり

  1. 事前準備
    • WEB用VPSの構築
    • ドメインの取得
    • さくらのクラウドのクラウドアカウント登録
  2. WEBサーバーのセットアップ
  3. ドメイン関連の設定
  4. Certbotのセットアップ
  5. ワイルドカード証明書発行

実行手順

(1) 事前準備

実際の構築手順を行うにあたって、予め以下が完了している必要があります。

  • VPSのインスタンスにSSH接続できる状態になっていること
  • ドメインを取得済みであること

事前準備として概要を記述します。

1. WEB用VPSの構築

※WebARENAのアカウントを持っていない場合、先にアカウント登録(サインアップ)を行う必要があります。

WebARENA IndigoでVPSを構築します。
ここでは、ubuntu 20.04LTSのインスタンスを作成することを前提としています。
具体的な手順は、公式ヘルプが分かりやすいです。
https://help.arena.ne.jp/hc/ja/sections/360009023513
インスタンスを作成し、SSH接続できるようになればまずはOKです。

続いて、STEP5:ファイアウォールを設定する を行います。
https://help.arena.ne.jp/hc/ja/articles/360049808354/

手順を参考に、以下の3つが作成したインスタンスに適用されている状態にします。

タイプ プロトコール ポート IPアドレス
HTTP TCP 80 0.0.0.0
HTTPS TCP 443 0.0.0.0
Custom TCP 22 0.0.0.0

IPアドレスは「0.0.0.0」ではなく、接続元のIPアドレスの方がより安全です。(特に22番ポート)
VPSにSSH接続し以下のコマンドを実行することで接続元のIPアドレス(=FROMのIP)が確認できます。

ubuntu@indigo01:~$ w -i
:
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
ubuntu   pts/0    XXX.XXX.XXX.XXX    10:00    4.00s  0.04s  0.00s w -i

2. ドメインの取得

お名前.comで、ドメイン名を取得します。
手順は、https://www.onamae.com/ から欲しいドメインを入力して、画面表示に従って手続きを行えば取得できると思います。

お名前.comは、ドメイン名の管理だけでなく、DNS機能も提供していますが、今回の構成はお名前.comのDNSは利用しません。
そのため、お名前.comでネームサーバーを切り替える必要がありますが、それは後程実施します。

3. さくらのクラウドのクラウドアカウント登録

さくらのクラウドのクラウドアカウントを持っていない場合、先にアカウント登録を行う必要があります。

すでにさくらインターネットの他のサービスを利用中の場合、さくらインターネット会員IDを持っていると思いますが、この場合でもクラウドアカウントの登録が必要です。
初めてさくらインターネットのサービスを利用する場合、新規にクラウドアカウントの登録を行います。
実際に一度登録してしまえば難しいことはないのですが、後で手順を思い出そうとするとややこしくて説明に困ります。

詳しくは以下を参照すると良いでしょう。
https://manual.sakura.ad.jp/ds/phy/manual/cpanel/account.html

(2) WEBサーバーのセットアップ

ここからが具体的な手順です。

まずは、ワイルドカード証明書を組み込むWEBサーバーをセットアップします。
具体的には nginx のインストール、初期設定です。

ネットで検索すると分かりやすい手順がたくさん出てくると思いますので、ここでは手順の流れを簡単に記述します。

1. とりあえずパッケージリスト更新

ubuntu@indigo01:~$ sudo apt update
以降の実行イメージ
Get:1 http://security.ubuntu.com/ubuntu focal-security InRelease [114 kB]
Hit:2 http://archive.ubuntu.com/ubuntu focal InRelease   
Get:3 http://archive.ubuntu.com/ubuntu focal-updates InRelease [114 kB]
Get:4 http://archive.ubuntu.com/ubuntu focal-backports InRelease [101 kB]
Fetched 328 kB in 2s (180 kB/s)  
Reading package lists... Done
Building dependency tree       
Reading state information... Done
127 packages can be upgraded. Run 'apt list --upgradable' to see them.

2. nginxのインストール (ubuntuのリポジトリから)

ubuntu@indigo01:~$ sudo apt install nginx
以降の実行イメージ
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following additional packages will be installed:
  fontconfig-config fonts-dejavu-core libfontconfig1 libgd3 libjbig0 libjpeg-turbo8 libjpeg8 libnginx-mod-http-image-filter libnginx-mod-http-xslt-filter libnginx-mod-mail libnginx-mod-stream libtiff5 libwebp6
  libxpm4 nginx-common nginx-core
Suggested packages:
  libgd-tools fcgiwrap nginx-doc ssl-cert
The following NEW packages will be installed:
  fontconfig-config fonts-dejavu-core libfontconfig1 libgd3 libjbig0 libjpeg-turbo8 libjpeg8 libnginx-mod-http-image-filter libnginx-mod-http-xslt-filter libnginx-mod-mail libnginx-mod-stream libtiff5 libwebp6
  libxpm4 nginx nginx-common nginx-core
0 upgraded, 17 newly installed, 0 to remove and 127 not upgraded.
Need to get 2431 kB of archives.
After this operation, 7891 kB of additional disk space will be used.
Do you want to continue? [Y/n] Y
Get:1 http://archive.ubuntu.com/ubuntu focal/main amd64 fonts-dejavu-core all 2.37-1 [1041 kB]
Get:2 http://archive.ubuntu.com/ubuntu focal/main amd64 fontconfig-config all 2.13.1-2ubuntu3 [28.8 kB]
Get:3 http://archive.ubuntu.com/ubuntu focal/main amd64 libfontconfig1 amd64 2.13.1-2ubuntu3 [114 kB]
Get:4 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 libjpeg-turbo8 amd64 2.0.3-0ubuntu1.20.04.1 [117 kB]
Get:5 http://archive.ubuntu.com/ubuntu focal/main amd64 libjpeg8 amd64 8c-2ubuntu8 [2194 B]
Get:6 http://archive.ubuntu.com/ubuntu focal/main amd64 libjbig0 amd64 2.1-3.1build1 [26.7 kB]
Get:7 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 libwebp6 amd64 0.6.1-2ubuntu0.20.04.1 [185 kB]
Get:8 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 libtiff5 amd64 4.1.0+git191117-2ubuntu0.20.04.1 [162 kB]
Get:9 http://archive.ubuntu.com/ubuntu focal/main amd64 libxpm4 amd64 1:3.5.12-1 [34.0 kB]
Get:10 http://archive.ubuntu.com/ubuntu focal/main amd64 libgd3 amd64 2.2.5-5.2ubuntu2 [118 kB]
Get:11 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 nginx-common all 1.18.0-0ubuntu1.2 [37.5 kB]
Get:12 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 libnginx-mod-http-image-filter amd64 1.18.0-0ubuntu1.2 [14.4 kB]
Get:13 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 libnginx-mod-http-xslt-filter amd64 1.18.0-0ubuntu1.2 [12.7 kB]
Get:14 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 libnginx-mod-mail amd64 1.18.0-0ubuntu1.2 [42.5 kB]
Get:15 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 libnginx-mod-stream amd64 1.18.0-0ubuntu1.2 [67.3 kB]
Get:16 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 nginx-core amd64 1.18.0-0ubuntu1.2 [425 kB]
Get:17 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 nginx all 1.18.0-0ubuntu1.2 [3620 B]
Fetched 2431 kB in 3s (815 kB/s)
Preconfiguring packages ...
Selecting previously unselected package fonts-dejavu-core.
(Reading database ... 63425 files and directories currently installed.)
Preparing to unpack .../00-fonts-dejavu-core_2.37-1_all.deb ...
Unpacking fonts-dejavu-core (2.37-1) ...
Selecting previously unselected package fontconfig-config.
Preparing to unpack .../01-fontconfig-config_2.13.1-2ubuntu3_all.deb ...
Unpacking fontconfig-config (2.13.1-2ubuntu3) ...
Selecting previously unselected package libfontconfig1:amd64.
Preparing to unpack .../02-libfontconfig1_2.13.1-2ubuntu3_amd64.deb ...
Unpacking libfontconfig1:amd64 (2.13.1-2ubuntu3) ...
Selecting previously unselected package libjpeg-turbo8:amd64.
Preparing to unpack .../03-libjpeg-turbo8_2.0.3-0ubuntu1.20.04.1_amd64.deb ...
Unpacking libjpeg-turbo8:amd64 (2.0.3-0ubuntu1.20.04.1) ...
Selecting previously unselected package libjpeg8:amd64.
Preparing to unpack .../04-libjpeg8_8c-2ubuntu8_amd64.deb ...
Unpacking libjpeg8:amd64 (8c-2ubuntu8) ...
Selecting previously unselected package libjbig0:amd64.
Preparing to unpack .../05-libjbig0_2.1-3.1build1_amd64.deb ...
Unpacking libjbig0:amd64 (2.1-3.1build1) ...
Selecting previously unselected package libwebp6:amd64.
Preparing to unpack .../06-libwebp6_0.6.1-2ubuntu0.20.04.1_amd64.deb ...
Unpacking libwebp6:amd64 (0.6.1-2ubuntu0.20.04.1) ...
Selecting previously unselected package libtiff5:amd64.
Preparing to unpack .../07-libtiff5_4.1.0+git191117-2ubuntu0.20.04.1_amd64.deb ...
Unpacking libtiff5:amd64 (4.1.0+git191117-2ubuntu0.20.04.1) ...
Selecting previously unselected package libxpm4:amd64.
Preparing to unpack .../08-libxpm4_1%3a3.5.12-1_amd64.deb ...
Unpacking libxpm4:amd64 (1:3.5.12-1) ...
Selecting previously unselected package libgd3:amd64.
Preparing to unpack .../09-libgd3_2.2.5-5.2ubuntu2_amd64.deb ...
Unpacking libgd3:amd64 (2.2.5-5.2ubuntu2) ...
Selecting previously unselected package nginx-common.
Preparing to unpack .../10-nginx-common_1.18.0-0ubuntu1.2_all.deb ...
Unpacking nginx-common (1.18.0-0ubuntu1.2) ...
Selecting previously unselected package libnginx-mod-http-image-filter.
Preparing to unpack .../11-libnginx-mod-http-image-filter_1.18.0-0ubuntu1.2_amd64.deb ...
Unpacking libnginx-mod-http-image-filter (1.18.0-0ubuntu1.2) ...
Selecting previously unselected package libnginx-mod-http-xslt-filter.
Preparing to unpack .../12-libnginx-mod-http-xslt-filter_1.18.0-0ubuntu1.2_amd64.deb ...
Unpacking libnginx-mod-http-xslt-filter (1.18.0-0ubuntu1.2) ...
Selecting previously unselected package libnginx-mod-mail.
Preparing to unpack .../13-libnginx-mod-mail_1.18.0-0ubuntu1.2_amd64.deb ...
Unpacking libnginx-mod-mail (1.18.0-0ubuntu1.2) ...
Selecting previously unselected package libnginx-mod-stream.
Preparing to unpack .../14-libnginx-mod-stream_1.18.0-0ubuntu1.2_amd64.deb ...
Unpacking libnginx-mod-stream (1.18.0-0ubuntu1.2) ...
Selecting previously unselected package nginx-core.
Preparing to unpack .../15-nginx-core_1.18.0-0ubuntu1.2_amd64.deb ...
Unpacking nginx-core (1.18.0-0ubuntu1.2) ...
Selecting previously unselected package nginx.
Preparing to unpack .../16-nginx_1.18.0-0ubuntu1.2_all.deb ...
Unpacking nginx (1.18.0-0ubuntu1.2) ...
Setting up libxpm4:amd64 (1:3.5.12-1) ...
Setting up nginx-common (1.18.0-0ubuntu1.2) ...
Created symlink /etc/systemd/system/multi-user.target.wants/nginx.service → /lib/systemd/system/nginx.service.
Setting up libjbig0:amd64 (2.1-3.1build1) ...
Setting up libnginx-mod-http-xslt-filter (1.18.0-0ubuntu1.2) ...
Setting up libwebp6:amd64 (0.6.1-2ubuntu0.20.04.1) ...
Setting up fonts-dejavu-core (2.37-1) ...
Setting up libjpeg-turbo8:amd64 (2.0.3-0ubuntu1.20.04.1) ...
Setting up libjpeg8:amd64 (8c-2ubuntu8) ...
Setting up libnginx-mod-mail (1.18.0-0ubuntu1.2) ...
Setting up fontconfig-config (2.13.1-2ubuntu3) ...
Setting up libnginx-mod-stream (1.18.0-0ubuntu1.2) ...
Setting up libtiff5:amd64 (4.1.0+git191117-2ubuntu0.20.04.1) ...
Setting up libfontconfig1:amd64 (2.13.1-2ubuntu3) ...
Setting up libgd3:amd64 (2.2.5-5.2ubuntu2) ...
Setting up libnginx-mod-http-image-filter (1.18.0-0ubuntu1.2) ...
Setting up nginx-core (1.18.0-0ubuntu1.2) ...
Setting up nginx (1.18.0-0ubuntu1.2) ...
Processing triggers for ufw (0.36-6) ...
Processing triggers for systemd (245.4-4ubuntu3.4) ...
Processing triggers for man-db (2.9.1-1) ...
Processing triggers for libc-bin (2.31-0ubuntu9.2) ...

3. nginxの稼働確認

ubuntu@indigo01:~$ systemctl status nginx
以降の実行イメージ
● nginx.service - A high performance web server and a reverse proxy server
     Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
     Active: active (running) since Wed 2021-09-01 18:01:46 UTC; 30s ago
       Docs: man:nginx(8)
   Main PID: 1853 (nginx)
      Tasks: 2 (limit: 1137)
     Memory: 6.6M
     CGroup: /system.slice/nginx.service
             ├─ 1853 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
             └─33841 nginx: worker process

Sep 01 18:01:46 indigo01 systemd[1]: Starting A high performance web server and a reverse proxy server...
Sep 01 18:01:46 indigo01 systemd[1]: Started A high performance web server and a reverse proxy server.

Activeの項目が「active (running)」になっていれば起動中です。

起動していない場合、以下のコマンドで起動します。

ubuntu@indigo01:~$ systemctl start nginx

実際にブラウザでアクセスします。
※まだSSLの設定はしていないので、httpでアクセスします。
http://{VPSインスタンスのIPアドレス}/
「Welcome to nginx!」の画面が表示されればOKです。

WEBサーバーのセットアップは一旦ここまでです。
※この記事ではnginxの設定を初期値のままとしていますが、必要に応じて適宜調整してください。

(3) ドメイン関連の設定

続いて、ドメインに関する設定を行います。

実際に行うことは以下です。

  • さくらのクラウドでDNSゾーンを追加
  • さくらのクラウドのDNS設定
  • お名前.comの対象ドメインのネームサーバーを設定
  • さくらのクラウドのLetsEncryptCertbot用のAPIキー発行

予めさくらのクラウドのアカウント登録(および決済情報の登録)が済んでおり利用可能な状態であることを前提としています。

1. さくらのクラウドでDNSゾーンを追加

公式ドキュメントのとおり追加します。
https://manual.sakura.ad.jp/cloud/appliance/dns/index.html#id7

ゾーン名は、お名前.comで取得したドメイン名です。

追加後、DNSゾーンの一覧に登録したドメイン名でDNSゾーンが表示されます。
ゾーン名をダブルクリックし、DNSゾーン情報を表示します。

DNSゾーン情報のDNSサーバー欄に2つのサーバー名が表示されます。こちらがさくらのクラウドのDNSサーバー名です。
後で、DNSの確認と、お名前.comの設定で使いますのでメモしておきましょう。

2. さくらのクラウドのDNS設定

公式ドキュメントのとおりの手順で、引き続きレコードの登録を行います。
https://manual.sakura.ad.jp/cloud/appliance/dns/index.html#id9

登録するレコードは、以下の内容です。

  • 名前:入力欄に*(アスタリスク)を入力します。(*.example.com のような名前になります)
  • タイプ:プルダウンからAを選択します。(Aレコードを登録します)
  • IPアドレス:「入力」を選択し、入力欄にVPSのIPアドレスを入力します。
  • TTL:特に必要がなければ未入力とし、デフォルト値が設定されるようにします。

手順のとおり、「反映」ボタンをクリックして設定を反映します。

確認のため、セットアップを行ったWEBサーバーにSSH接続し、実際にさくらのクラウドのDNSにIPアドレスを問い合わせしてみます。

DNS問い合わせ方法

問い合わせはdigコマンドで行うことができます。
digコマンドでは@をつけてネームサーバーを指定することができるため、以下のような内容でコマンド実行します。
dig @{メモしたさくらのクラウドのDNSサーバー名} www.{取得したドメイン名}
以下はwww.example.comのIPアドレスを問い合わせした場合のイメージです。(内容は編集されたものです)

ubuntu@indigo01:~$ dig @ns1.gslb2.sakura.ne.jp www.example.com

; <<>> DiG 9.16.1-Ubuntu <<>> @ns1.gslb2.sakura.ne.jp www.example.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 34245
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;www.example.com.              IN      A

;; ANSWER SECTION:
www.example.com.       3600    IN      A       XXX.XXX.XXX.XXX
:

XXX.XXX.XXX.XXX の箇所に、設定したIPアドレスが表示されればうまく設定できています。

ここまででさくらのクラウドのDNSの準備は整いました。
ただし、この時点でこのDNSサーバーは、取得したドメインの情報を保持していることをどこにも知らせていないため、問い合わせを受けることはありません。
そのため、まだブラウザからドメイン名でアクセスすることはできません。

3. 対象ドメインのネームサーバー設定

というわけで、さくらのクラウドのDNSが、取得したドメインの情報を保持していることを、お名前.comに知らせる設定を行います。
具体的には、お名前.comのネームサーバーの変更です。

設定手順は、お名前.comの公式ガイドのとおりです。
https://www.onamae.com/guide/p/67

手順の3の「その他のネームサーバーを使う」の設定で、ネームサーバー1とネームサーバー2に、前手順でメモしたさくらのクラウドのDNSサーバー名をそれぞれ1つずつ入力します。

設定完了後、しばらく経つとネームサーバーが切り替わります。
WEBサーバーにSSH接続し、先ほども使ったdigコマンドで設定を確認しましょう。今回はネームサーバーを指定せずに問い合わせします。

ubuntu@indigo01:~$ dig www.example.com

Aレコードとして設定したIPアドレスが表示されればネームサーバーの変更完了です。
想定のIPアドレスが表示されない場合、時間を置いて改めて確認をします。

ネームサーバーの切り替えが完了すると、ブラウザからドメイン名でWEBサーバーにアクセスできるようになります。
※この時点でもまだSSLの設定はしていないので、httpでアクセスします。
http://www.{取得したドメイン名}/
「Welcome to nginx!」の画面が表示されればOKです。

4. さくらのクラウドのLetsEncryptCertbot用のAPIキー発行

さくらのクラウドで、DNSを外部から制御するために必要な、APIキーを作成します。

手順は以下です。
https://manual.sakura.ad.jp/cloud/api/apikey.html

APIキー作成時の入力内容は以下のとおりです。

  • APIキーの種類:リソース操作APIキー
  • 名前:任意(例えば「LetsEncryptCertbot用」など)
  • 説明:任意(省略可能)
  • アクセスレベル:作成・削除
  • 他サービスへのアクセス権:チェック不要

APIキー作成後、内容を確認し以下の2つの文字列をメモしておきましょう。

  • アクセストークン
  • アクセストークンシークレット

(4) Certbotのセットアップ

ようやくCertbotのセットアップです。
セットアップ手順は以下です。(表示時、defaultタブが表示されるので、wildcardタブに切り替えましょう)
https://certbot.eff.org/lets-encrypt/snap-nginx.html

ここでは以下を行います。

  • snapdのインストール等
  • Certbotのインストール等
  • DNSプラグインのインストール等

1. snapdのインストール等

まずは、certbotの管理ツールであるspapdをインストールします。

ubuntu@indigo01:~$ sudo apt-get install snapd -y
以降の実行イメージ
Reading package lists... Done
Building dependency tree       
Reading state information... Done
Suggested packages:
  zenity | kdialog
The following packages will be upgraded:
  snapd
1 upgraded, 0 newly installed, 0 to remove and 126 not upgraded.
Need to get 30.6 MB of archives.
After this operation, 7361 kB of additional disk space will be used.
Get:1 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 snapd amd64 2.49.2+20.04 [30.6 MB]
Fetched 30.6 MB in 5s (5590 kB/s)
(Reading database ... 63652 files and directories currently installed.)
Preparing to unpack .../snapd_2.49.2+20.04_amd64.deb ...
Unpacking snapd (2.49.2+20.04) over (2.48.3+20.04) ...
Setting up snapd (2.49.2+20.04) ...
Installing new version of config file /etc/apparmor.d/usr.lib.snapd.snap-confine.real ...
snapd.failure.service is a disabled or a static unit, not starting it.
snapd.snap-repair.service is a disabled or a static unit, not starting it.
Processing triggers for man-db (2.9.1-1) ...
Processing triggers for dbus (1.12.16-2ubuntu2.1) ...
Processing triggers for mime-support (3.64ubuntu1) ...

(参考)バージョン確認

ubuntu@indigo01:~$ snap version
snap    2.51.4
snapd   2.51.4
series  16
ubuntu  20.04
kernel  5.4.0-66-generic

2. Certbotのインストール等

続いて、snapdのcoreモジュールと、certbotのインストールを行います。

ubuntu@indigo01:~$ sudo snap install core
core 16-2.51.4 from Canonical✓ installed

ubuntu@indigo01:~$ sudo snap install --classic certbot
certbot 1.18.0 from Certbot Project (certbot-eff✓) installed

ubuntu@indigo01:~$ sudo ln -s /snap/bin/certbot /usr/bin/certbot

3. DNSプラグインのインストール等

DNSプラグインを利用する場合に必要なプラグインの設定、そして利用するDNSプラグインのインストールを行います。

ubuntu@indigo01:~$ sudo snap set certbot trust-plugin-with-root=ok

ubuntu@indigo01:~$ sudo snap install certbot-dns-sakuracloud
certbot-dns-sakuracloud 1.18.0 from Certbot Project (certbot-eff✓) installed

さくらのクラウドDNSプラグインを利用する際に必要な設定も行います。
※詳細は以下
https://certbot-dns-sakuracloud.readthedocs.io/en/stable/

まずは、API認証用ファイルを設置するディレクトリを作成します。

ubuntu@indigo01:~$ sudo mkdir -p /root/.secrets/certbot

続いて、作成したディレクトリにAPI認証用ファイルを作成します。

ubuntu@indigo01:~$ sudo vi /root/.secrets/certbot/sakuracloud.ini

sakuracloud.iniに以下の内容を記述します。

/root/.secrets/certbot/sakuracloud.ini
# Sakura Cloud API credentials used by Certbot
dns_sakuracloud_api_token  = 00000000-0000-0000-0000-000000000000
dns_sakuracloud_api_secret = MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw
  • dns_sakuracloud_api_tokenの設定値に、メモしたアクセストークンを記載します。
  • dns_sakuracloud_api_secretの設定値に、メモしたアクセストークンシークレットを記載します。

sakuracloud.iniは適切な権限設定である必要があるため、パーミッション変更を行います。

ubuntu@indigo01:~$ sudo chmod 600 /root/.secrets/certbot/sakuracloud.ini

(5) ワイルドカード証明書発行

ここまでが適切に行われていれば、あとはコマンドを実行するだけでワイルドカード証明書が発行されます。
発行された証明書をnginxに組み込めば、以降は自動で証明書の更新も行われます。

というわけで、ここでの実施内容は以下です。

  • 証明書の発行
  • nginxに証明書を設定
  • ブラウザで確認
  • 証明書更新の確認

1. 証明書の発行

補足:Let's Encryptの制限について

証明書発行の前に補足です。
Let's Encryptの証明書発行は、期間に応じた回数制限があります。
https://letsencrypt.org/ja/docs/rate-limits/
無駄な発行を行わないよう、ステージング環境を利用する(--dry-runフラグ)などしましょう。

以下、証明書発行コマンド内容です。長いため複数行を連結する\付きです。

sudo certbot certonly --dns-sakuracloud \
 --dns-sakuracloud-credentials /root/.secrets/certbot/sakuracloud.ini \
 -d 'example.com' \
 -d '*.example.com' \
 -m "your-mail-address@example.com" \
 --post-hook 'systemctl reload nginx' \
 --preferred-challenges 'dns-01' \
 --server 'https://acme-v02.api.letsencrypt.org/directory' \
 --agree-tos \
 --manual-public-ip-logging-ok

簡単に補足します。

  • --dns-sakuracloud:さくらのクラウドのDNSプラグインを利用する宣言です。
  • --dns-sakuracloud-credentials:DNSプラグインのAPI認証ファイルの指定です。
  • -d:対象のドメイン名の指定です。2つ指定はおまじない的なものです(内容後述)。example.comの箇所に取得したドメイン名を設定します。
  • -m:連絡先メールアドレスです。your-mail-address@example.com の箇所に正しいメールアドレスを設定しましょう。
  • --post-hook:証明書発行・更新後に実行されるコマンドです。nginxの設定リロードコマンドを記述しています。certbot renewの実行時にも適用されるためこのタイミングで指定しておきます。

上記以外は、以下の説明がすばらしいです。ありがたいです。しっかり理解しましょう。
https://qiita.com/s-katsumata/items/629222b24113d7a49b79

さて、実行イメージです。

ubuntu@indigo01:~$ sudo certbot certonly --dns-sakuracloud \
>  --dns-sakuracloud-credentials /root/.secrets/certbot/sakuracloud.ini \
>  -d 'example.com' \
>  -d '*.example.com' \
>  -m "your-mail-address@example.com" \
>  --post-hook 'systemctl reload nginx' \
>  --preferred-challenges 'dns-01' \
>  --server 'https://acme-v02.api.letsencrypt.org/directory' \
>  --agree-tos \
>  --manual-public-ip-logging-ok
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Would you be willing, once your first certificate is successfully issued, 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
Account registered.
Requesting a certificate for example.com and *.example.com
Waiting 90 seconds for DNS changes to propagate

ここで、90秒程度の待機が入ります。
この間に、さくらのクラウドの管理コンソールでDNSのレコードを確認すると、DNS認証用のTXTレコードが登録されていることが分かります。(DNS認証完了後にTXTレコードは削除されます)

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/example.com/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/example.com/privkey.pem
This certificate expires on 2021-12-01.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the background.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
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
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

これで、表示されたパスで、fullchain.pemとprivkey.pemを参照できるようになりました。

2. nginxに証明書を設定

発行された証明書をnginxに組み込みます。

例として、以下のようなドメイン名のアクセスをそれぞれ設定することにします。

  • www.example.com:メインのアクセス
  • www2.example.com:サブのアクセス
  • その他.example.com:適当なサブドメインが指定された場合のアクセス
    (とりあえず503を返す)

※httpアクセスについては未考慮のため、標準設定が適用される想定です。

動作確認したいだけなので、ここでは conf.d にダミー設定ファイルを設置してまとめて設定します。

ubuntu@indigo01:/etc/nginx/conf.d$ sudo vi /etc/nginx/conf.d/test.conf

設定内容は以下です。

/etc/nginx/conf.d/test.conf
server {
    listen      443 ssl;

    server_name www.example.com;
    root   /var/www/www.example.com/html;

    ssl_certificate      /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key  /etc/letsencrypt/live/example.com/privkey.pem;
}
server {
    listen      443 ssl;

    server_name www2.example.com;
    root   /var/www/www2.example.com/html;

    ssl_certificate      /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key  /etc/letsencrypt/live/example.com/privkey.pem;
}
server {
    listen      443 ssl;

    server_name *.example.com;
    location / {
        return 503;
    }

    ssl_certificate      /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key  /etc/letsencrypt/live/example.com/privkey.pem;
}

以下のようなドメインごとのディレクトリを作成し、それぞれを区別可能なindex.htmlファイルも設置しておきます。
/var/www/www.example.com/html/index.html
/var/www/www2.example.com/html/index.html

設定が終わったら設定ファイルの内容をチェック(test configuration)します。

ubuntu@indigo01:/etc/nginx/conf.d$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

ちなみに、rootディレクティブのパスに誤りがあっても、構文があっていればチェックを通過します。
その状態でアクセスすると404 Not Foundが返されます。後で行う確認の際に混乱することの無いよう、適切なパスが記述されていることを改めて確認しましょう。
証明書ファイルへのパスに誤りがあるときは、チェックで No such file or directory と、エラーになります。

チェックを通過したら設定内容をリロードします。

ubuntu@indigo01:/etc/nginx/conf.d$ sudo systemctl reload nginx

3. ブラウザで確認

実際にブラウザからアクセスして確認しましょう。

確認1

まずはメインのドメインのhttpsアクセスから確認します。
https://www.example.com/
設置したindex.htmlの内容が表示されることを確認します。
それと、ブラウザで証明書の内容を確認し、証明書が有効であること、接続が保護されていることなどを確認します。
証明書の内容の発行先に取得したドメインが表示されていると思います。(ここに"*."が付いている場合、おまじないをしなったということでしょう)

補足:いくつかのエラーについて
  • 404 Not Found
    404が返される場合、test.confのrootディレクトリのパスを疑います。実際にディレクトリ、ファイルが存在するか確認しましょう。
  • 403 Forbidden
    403が返される場合、text.confのrootディレクトリのパスに、index.htmlが存在しないことでしょう。
  • 503 Service Temporarily Unavailable
    503が返される場合、test.confのserver_nameが一致せずに、後述の適当なドメイン向けの設定で処理されている可能性が高いです。
  • その他
    その他のレスポンスが返される場合、もっと深刻な問題が発生していることでしょう。がんばって抜け出しましょう。

確認2

続いて、他のドメインです。
https://www2.example.com/
同様に、設置したindex.htmlの内容が表示されることなどを確認します。

確認3

次に、適当なドメインです。サブドメインは何でもよいです。
https://dummy.example.com/
503 Service Temporarily Unavailable が返されることを確認します。

補足確認

ついでに他のアクセスに関しても確認しておきましょう。

ここまでは、すべてtest.confの設定の確認ですが、test.confはhttpsに関する設定しか行っていません。
そのため、それぞれのドメインにhttpでアクセスすると、nginxの標準設定が適用され、「Welcome to nginx!」が表示されます。
同様にIPアドレスでhttp接続しても「Welcome to nginx!」が表示されます。

続いて、IPアドレスでhttps接続した場合ですが、この場合はtest.confに最初に記述されたSSL設定のwww.example.comが適用されます。
証明書のドメインが一致しないため、証明書は無効と判断され、保護されていない通信となります。

こちらの仕様や、サーバー名のマッチングルールなどは以下に記載されています。
http://nginx.org/en/docs/http/server_names.html

4. 証明書更新の確認

最後に、Certbotの証明書更新に関する確認です。
詳細は以下に記載されています。
https://certbot.eff.org/docs/using.html#modifying-the-renewal-configuration-file

証明書更新の試行の確認

以下のように、certbotに--dry-runフラグを指定し証明書更新の試行を要求します。

ubuntu@indigo01:~$ sudo certbot renew --dry-run
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/example.com.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Simulating renewal of an existing certificate for example.com and *.example.com
Waiting 90 seconds for DNS changes to propagate

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations, all simulated renewals succeeded: 
  /etc/letsencrypt/live/example.com/fullchain.pem (success)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

あるいは、--force-renewalフラグを付けることで強制更新することもできます。が、事情がない限り--dry-runによる確認で十分でしょう。
https://certbot.eff.org/docs/using.html#re-creating-and-updating-existing-certificates

WEBサーバーの再起動の確認

念のため、post-hookに記述したnginxのリロードが行われていることも確認します。

ubuntu@indigo01:~$ sudo journalctl -u nginx -n 1
-- Logs begin at Thu 2021-09-02 02:25:24 JST, end at Thu 2021-09-09 17:52:31 JST. --
Sep 09 13:10:48 indigo01 systemd[1]: Reloaded A high performance web server and a reverse proxy server.

post-hookは、--dry-run指定時にも実行されるとのことです。
ということで、リロード時刻が certbot renew --dry-runの完了時刻と同タイミングであれば問題ないでしょう。

参考:タイムゾーン設定

タイムゾーンを設定しないと時刻がUTCで表示されます。とりあえずJSTに切り替える場合は以下のコマンドを実行します。以降、JSTで表示されます。

ubuntu@indigo01:~$ export TZ="Asia/Tokyo"

タイマーの確認

もうひとつ確認点があります。
certbotは、systemdで管理されており(厳密には、systemdで管理されたsnapdで…)、certbot renewコマンドもsystemdのタイマーにより実行されます。

というわけで、実行スケジュールを確認しておきましょう。
https://certbot.eff.org/docs/using.html?highlight=renewal#automated-renewals

実行スケジュールは「systemctl list-timers」コマンドで確認できます。
※以下は、表示UNITをsnap関連のみに絞っています。

ubuntu@indigo01:~$ systemctl list-timers snap.*
NEXT                        LEFT    LAST                        PASSED       UNIT                     ACTIVATES                 
Fri 2021-09-10 01:23:00 JST 8h left Thu 2021-09-09 11:29:11 JST 6h 11min ago snap.certbot.renew.timer snap.certbot.renew.service

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

snap.certbot.renew.timerの最終実行日時(LAST)と、次の実行日時(NEXT)を確認し適切な日時になっていれば問題ないでしょう。(場合によっては翌日以降に確認した方が良いでしょう)

以上で終了です。おつかれさまでした。

Discussion