QNAP Container Station certbot-dns-route53 ワイルドカード証明書発行
「TS-h1283XU-RP」上のコンテナ(Container Station)でCertbotを使用し、Let's Encryptのワイルドカード証明書を設定します。
基本のセットアップ方法については、「QNAP QuTS hero 5 セットアップ」をご覧ください。
ページ内目次
ワイルドカード証明書を自動更新するには
ワイルドカード証明書を発行するにはDNSチャレンジ認証をする必要があります。
「QNAP QuTS hero 5 セットアップ」のページ中でも述べましたが、QNAP自体に証明書を入れて更新したいです。
Route53管理のドメインに対して証明書を発行したいため、「certbot-dns-route53」のDockerイメージを使用します。
Amazon Route53 アクセスキー作成
Amazon Route53 で管理しているドメインを操作するために、アクセスキーとシークレットキーが必要になります。
人間が操作する場合には、AWSマネジメントコンソールにログインをすれば良いですが、今回はcertbotにDNSの操作を自動で行ってもらうために、certbotがRoute53にアクセスするための権限設定が必要になります。
このアクセスキーとシークレットキーのペアが外部に漏れると悪用されるので、最低限必要な操作の権限だけを与えたものを作成するのが基本になります。
AWS マネジメントコンソールにログインします。
「Identity and Access Management (IAM)」を検索してIAMを開きます。
左側の「アクセス管理」より「ユーザー」を選択。
現在のIAMユーザーの一覧が表示されるので、右上の「ユーザーの作成」ボタンをクリック。
「ユーザー名」には「qnap-docker-certbot」など、わかりやすい名前を入力します。
「次へ」を押して進みます。
許可を設定画面になるので、Route53の変更許可だけ入れます。
「許可のオプション」を「ポリシーを直接アタッチする」に変更し、その下に表示される許可ポリシーを探すことにします。
これは、AWS側が様々なポリシーを用意しているもので、Route53の操作権限のみのポリシーを選択すれば良いということになります。
- AmazonRoute53DomainsFullAccess
- AmazonRoute53FullAccess
あたりを選択しておけばOKです。
もしくは、「ポリシーの作成」ボタンよりポリシーを作成します。
こちらのページのサンプルです。
最低限必要な権限しか与えないので、こちらのほうが安全です。
{
"Version": "2012-10-17",
"Id": "certbot-dns-route53-policy",
"Statement": [
{
"Effect": "Allow",
"Action": [
"route53:ListHostedZones",
"route53:GetChange"
],
"Resource": [
"*"
]
},
{
"Effect" : "Allow",
"Action" : [
"route53:ChangeResourceRecordSets"
],
"Resource" : [
"arn:aws:route53:::hostedzone/YOURHOSTEDZONEID_1",
"arn:aws:route53:::hostedzone/YOURHOSTEDZONEID_2",
"arn:aws:route53:::hostedzone/YOURHOSTEDZONEID_3"
]
}
]
}ホストゾーンを増やす場合には、上記のようにResourceの行を増やして、カンマ区切りで続けておきます。
なお、このポリシーを適用する場合には、Route53で表示されている対象のホストゾーンIDを入れておかないと操作できないので注意。
次に進み、「ユーザーの作成」でユーザーを作成します。
ユーザーが作成されたので、アクセスキーを作成します。
作成されたユーザーをクリックして開き、「セキュリティ認証情報」からアクセスキーのセクションを参照します。
「アクセスキーを作成」をクリックして、「AWS の外部で実行されるアプリケーション」を選択、「次へ」で進みます。
説明タグ値は自分がわかりやすいように名付ければOKです。
「家のQNAPサーバー上でのDocker-Certbot」など、使用している場所がわかりやすいようにメモを残せば良いと思います。
「アクセスキーを作成」をクリックするとアクセスキーとシークレットアクセスキーが生成されます。
この情報でAWSを操作できてしまうため、ネットに上げないようにすることと、ポリシーで必要以上の権限を与えないことが重要なのがわかると思います。
取り扱いに注意して、保存するのであればパスワードマネージャー等で管理するのが良いと思います。
基本的には、一度Dockerに設定したら次からは触れないものなので、一時的にメモするでも良いでしょう。
certbot/dns-route53 を Container Station に設定
- https://hub.docker.com/r/certbot/dns-route53
- https://eff-certbot.readthedocs.io/en/latest/using.html#dns-plugins
- https://certbot-dns-route53.readthedocs.io/en/stable/
詳細はこちらにある通りで、このDockerイメージを動かす場合には、AWSのアクセスキーの設定や、証明書の保存先の設定が必要になります。
事前準備
証明書の保存先として以下のディレクトリを作成します。
- /share/Container/certbot/etc/letsencrypt/
- /share/Container/certbot/var/lib/letsencrypt/
デフォルトで生成された「/share/Container」以下、適当に「certbot」フォルダにしましたが何でもいいと思います。
ドメインが複数ある場合でも、内部でドメインごとのフォルダに分けられるようです。
mkdir -p /share/Container/certbot/etc/letsencrypt/ && mkdir -p /share/Container/certbot/var/lib/letsencrypt/
ディレクトリの作成はSSH経由で上記コマンドのように行ってもいいですし、ブラウザからFile Station 5を使用してもいいです。
(File Station 5やCIFSの共有からは、上位の/shareディレクトリは見えずに/Containerになりますが内部では/share/Containerです)
Dockerコンテナの設定
「Container Station」を開き、「コンテナ」タブから「探索」ボタンを押してDockerHubからcertbot-dns-route53を探します。
「コンテナまたはアプリケーションの作成」という画面が表示されるので、検索欄に「certobot」などと入力して「certbot/dns-route53」を探します。
「certbot/dns-route53」の右に表示される「デプロイ」ボタンを押します。
確認画面が表示されますが、certbot公式なので大丈夫でしょう。
イメージバージョンの選択画面になりますが、latestのまま進めてしまいます。
バージョンにこだわる人は指定していいと思います。
コンテナ作成の画面になるので、以下のように設定していきます。
- 名前:任意(わかりやすいもの)
- 設定・再起動ポリシー:「停止時以外」から「なし」に変更(更新するときだけ動かすコンテナなので常時起動はしません)
- 設定・自動削除:チェックを入れない(チェックを入れてしまうと1度実行されたあとにコンテナが削除されてしまいます)
- ネットワーク設定・露出ポート:80/tcp, 443/tcpが公開だが、これを2つとも削除する
- ネットワーク設定・デフォルトの Web URL ポート:これも無効にする
「詳細設定」をクリックして、詳細設定に進む。
「コマンド」ページ
エントリポイントを「デフォルト:certbot」から「Override」に変更し以下の内容を入力。
certbot certonly --dns-route53 -d example.com -d *.example.com -n -m admin@example.com --agree-tos
ドメインは自分のドメインに置き換えてください。メールアドレスも同様に。
ポイントは、www無しとwww有り(ワイルドカードで*を指定しているのでwww以外も対応可能)に対応できるように指定することです。
サブドメイン以下にもワイルドカードが欲しければ、それも同時に指定しておきます。(*.sub.example.com等)
--test-cert をつければ実行テスト(Route53側にアクセスはされない)が出来ますし、-dオプションを増やして1つの証明書に全く別のドメインを追加することもできます。
(すでに設定した証明書からドメインを増やす場合には--expandオプションで拡張することを忘れずに)
「環境」ページ
「新しい変数の追加」ボタンで以下の内容を増やす。
- 変数「AWS_ACCESS_KEY_ID」 値「AKIAIOSFODNN7EXAMPLE」
- 変数「AWS_SECRET_ACCESS_KEY」 値「wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY」
値はそれぞれの環境に応じて書き換えてください。(先程AWSで設定したIAMのアクセスキーとシークレットキーを入力します)
「ストレージ」ページ
ボリュームの設定が2つ入っているため、それを削除。
「ボリュームの追加」ボタン横の矢印から「マウントされたホストのパスをバインド」を選択して追加。
- ホスト「/Container/certbot/etc/letsencrypt」に対してコンテナ「/etc/letsencrypt」
- ホスト「/Container/certbot/var/lib/letsencrypt」に対してコンテナ「/var/lib/letsencrypt」
(なお、ボリュームの設定のままでも、ボリュームに /share/Container/certbot/~ のパスで設定を入れると勝手にマウントになります)
この設定でコンテナ内のディレクトリをファイルシステムにマッピングさせます。
(パス設定が表示されていなければ「ボリュームの追加」ボタン横の矢印から「マウントされたホストのパスをバインド」を選択して追加)
設定が完了したら、実行してみましょう。
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Account registered.
Requesting a certificate for example.com and 3 more domains
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 2025-12-25.
These files will be updated when the certificate renews.
NEXT STEPS:
- The certificate will need to be renewed before it expires. Certbot can automatically renew the certificate in the background, but you may need to take steps to enable that functionality. See https://certbot.org/renewal-setup for instructions.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
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
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -というメッセージが表示されて、証明書の取得が完了します。
$ docker ps -a
コマンドにてコンテナを確認して、
$ docker start [コンテナ名 or コンテナID]
でも更新を開始できることも確認しておきます。
QNAP上の「/share/Container/certbot/etc/letsencrypt/live/ドメイン名/」ディレクトリを参照すると証明書が生成されていることがわかります。
$ ls
cert.pem@ chain.pem@ fullchain.pem@ privkey.pem@ README*なお、コンテナの設定内容を変更する場合は、Container Stationで対象のコンテナから、歯車アイコンで「再作成」にします。
情報を変更するたびにコンテナは作り直す必要があるため、コンテナIDが変化することに気をつけてください。
さて、Certbotのサイトを確認する限り、サーバーの設定でこれらのファイルを直接指定するか、シンボリックリンクを作成してくださいとのことですが、QNAPではそれは出来ません。
コマンドラインからQNAPへ証明書を設定する
QNAPの証明書について調査すると、以下のようなメーカーのページが出てきます。
こちらによると、「/etc/stunnel/stunnel.pem」にサーバー証明書と秘密鍵、「/etc/stunnel/uca.pem」に中間証明書を指定するようにあります。
QuTS hero 5上で確認してみると、実際に存在するファイルはstunnel.pemだけです。
$ sudo cat /etc/stunnel/stunnel.conf で設定を確認してみると、指定されているファイルは同様にstunnel.pemだけで、uca.pemは指定されていないようです。
Let's Encryptの場合は、fullchain.pemにサーバー証明書と中間証明書、privkey.pemに秘密鍵が生成されるため、これを1つのファイルに結合して、stunnel.pemに用意すれば更新できそうです。
証明書についてはテキストファイルですので、catコマンド等でそのまま結合させてしまってOKです。
証明書更新のシェルスクリプトを書く
以下の内容のシェルスクリプトを書きました。
#!/bin/bash
CONTAINER_NAME="[コンテナ名 or コンテナID]"
CERT_PATH="/share/Container/certbot/etc/letsencrypt/live/[ドメイン名]"
docker start $CONTAINER_NAME >/dev/null 2>&1
docker wait $CONTAINER_NAME >/dev/null 2>&1
cat $CERT_PATH/privkey.pem $CERT_PATH/fullchain.pem > /etc/stunnel/stunnel.pem
chmod 600 /etc/stunnel/stunnel.pem
chown admin:administrators /etc/stunnel/stunnel.pem
/etc/init.d/stunnel.sh restart
/etc/init.d/Qthttpd.sh restart
/etc/init.d/thttpd.sh restart先程用意したDockerコンテナを実行させて、終了まで待機。そして証明書を配置してWebサーバー類を再起動する内容になっています。
コンテナIDでの指定は出来ますが、アップデートの際にコンテナを再作成する形になりIDが変更されるため、コンテナ名で指定しておいたほうが良いとは思います。
上記内容のファイルを「/share/Container/certbot/certbot-dns-route53.sh」に保存しました。
vi /share/Container/certbot/certbot-dns-route53.sh
sudo chmod +x /share/Container/certbot/certbot-dns-route53.sh
実行可能な権限を与えておきます。
また、何かあったときに戻せるように、オリジナルの証明書は必ず避難させておきます。
sudo mv /etc/stunnel/stunnel.pem /etc/stunnel/stunnel.pem.org
実行してみます
sudo /share/Container/certbot/certbot-dns-route53.sh
以下のような実行結果が表示されます。
$ sudo /share/Container/certbot/certbot-dns-route53.sh
Shutting down apache proxy: OK
Start apache proxy: OK
Shutting down Qthttpd services:/etc/config/php.d/php_ext.ini not found
OK.
Starting Qthttpd services:/etc/config/php.d/php_ext.ini not found
OK
Stop apache proxy: Shutting down php-fpm-proxy service: OK
Shutting down thttpd service: OK
Starting thttpd service: OK
Start apache proxy: OKコントロールパネルのWebサーバーから、「セキュリティ保護された接続(HTTPS)を有効にする」にチェックを入れて、ポート番号を443にします。
ブラウザからNASのアドレスに対してHTTPSアクセスして証明書が反映されているか確認しましょう。
Crontabを設定してシェルスクリプトを定期的に実行する
公式情報を見る限り、通常の方法でcrontabを編集すると、アップデート時等に上書きされてしまうとあります。
そのため、QNAP公式が推奨する編集方法を使用します。
sudo vi /etc/config/crontab
直接crontabを編集します。
末尾に設定を追記します。
例:毎日0時0分に実行させる場合。
0 0 * * * sh /share/Container/certbot/certbot-dns-route53.sh > /dev/null 2>&1
例:毎月1日の3時0分に実行させる場合。
0 3 1 * * sh /share/Container/certbot/certbot-dns-route53.sh > /dev/null 2>&1
例:毎週月曜日の4時0分に実行させる場合。
0 4 * * 1 sh /share/Container/certbot/certbot-dns-route53.sh > /dev/null 2>&1
有効期限が30日以上ある場合は、「Certificate not yet due for renewal; no action taken.」と言われるだけなので、月1ぐらいの頻度で更新かけるぐらいで良いとは思います。
ただ、月1だと更新が失敗した場合に残りのcron実行回数が少なく、更新できない場合もあるので、毎日実行しておいても良いでしょう。
--force-renewalオプションをつけると強制的に更新もできますが、レート制限があるのでこのオプションを使用する場合は毎日実行しないほうがいいです。
保存したら、以下のコマンドで反映します。
sudo crontab /etc/config/crontab && sudo /etc/init.d/crond.sh restart
あとは動作を確認してみましょう。
なお、crontabはシステム側で適宜編集されていて、アップデートのタイミング等で追記されていますので、末尾に追加したとしてもそれが末尾のままにはなりません。
よって編集の際は入力した行を検索するところから始めることになります。
また、加えてこちらの手順でLDAPサーバーを構築しているため、そちらからも証明書を参照しています。
そのため、証明書の更新後に新しい証明書を確実に参照させるため、Dockerコンテナの再起動を行いたいです。
シェルスクリプト中ではLLDAPのDockerコンテナを再起動させるためにdocker restartコマンドも仕込んでいます。
Apacheの設定をいじる方法
試してはいないですが、Apache側の設定をいじって証明書を参照する方法も出来ると思います。
ただ、仮想ホスト(VirtualHost)環境下だと、Webサーバー起動毎に設定ファイルが書き戻されるので面倒かもしれません。
「QNAP QuTS hero 5 セットアップ」でWebサーバーの設定については書いています。
