📦

MYDNS.JPのサブドメイン用SSL証明書取得に、Docker版PHPでLet's EncryptのDNS-01を用いた際にエラー

2023/09/18に公開

TL;DR

  • エラー内容
    /bin/sh: 1: txtregist.php: not found
  • 対策
    #!/usr/local/phpに変更 or hookオプションを"php ファイル名"にする
    対策内容
  • その他
    PHPにこだわる必要はない

背景

  • MYDNS.JPのサブドメインに対するSSL証明書をLet's Encryptから自動で取得したかった
  • CertbotのHTTP-01のために80や443ポートは使いたくなかった
  • ホスト環境は汚したくなかったのでDockerで実行したかった
  • MYDNS.JP公式でDNS-01用のphpスクリプトが公開されているので、それを使おうとした

事前準備:MYDNS.JPにサブドメイン登録

User Info→追加する子IDの数で追加したい分の数を選択→確認→送信


メールで子IDとパスワードが通知される。

Domain Infoで以下を追加

  • Hostname:使いたいサブドメイン名
  • Type:DELEGATE
  • Content:空
  • Target ID:上記で追加された子ID

    User Infoに追加したサブドメイン名.メインドメイン名.mydns.jpが設定されることを確認

    https://MYDNSの子ID:子IDのパスワード@www.mydns.jp/login.htmlにアクセスすればIPが通知される。
    下記はIPv4のみを通知
wget --inet4-only -O /dev/null https://MYDNSの子ID:パスワード@www.mydns.jp/login.html
--2023-**-** **:**:**--  https://MYDNSの子ID:*password*@www.mydns.jp/login.html`
www.mydns.jp (www.mydns.jp) をDNSに問いあわせています... *.*.*.*, *.*.*.*, *.*.*.*, ...
www.mydns.jp (www.mydns.jp)|*.*.*.*|:443 に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 401 Unauthorized
選択された認証形式: Basic realm="Enter MasterID and Password."
www.mydns.jp:443 への接続を再利用します。
HTTP による接続要求を送信しました、応答を待っています... 200 OK
長さ: 特定できません [text/html]
‘/dev/null’ に保存中

/dev/null                             [ <=>                                                          ]     620  --.-KB/s    in 0s

>2023-**-** **:**:** (224 MB/s) - ‘/dev/null’ へ保存終了 [620]

直面した問題

php:cli-bullseyeをpullし、Certbotをインストールした後README.mdの使い方/Usageの通りに実行した。

docker run -it --rm \
-v ./etc:/etc/letsencrypt \
-v ./log:/var/log/letsencrypt \
-v ./DirectEdit:/workdir php:mycertbot \
certbot certonly --manual \
--preferred-challenges=dns \
--manual-auth-hook /workdir/txtregist.php \
--manual-cleanup-hook /workdir/txtdelete.php \
-d *.メインドメイン.mydns.jp \
--server https://acme-v02.api.letsencrypt.org/directory \
--agree-tos -m メールアドレス \
--manual-public-ip-logging-ok

※./etcと./logディレクトリは事前に作成
※イメージ名は適当にphp:mycertbotでcommit

以下のようなエラーとなった。

Use of --manual-public-ip-logging-ok is deprecated.
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator manual, Installer None
Requesting a certificate for *.メインドメイン.mydns.jp
Performing the following challenges:
dns-01 challenge for メインドメイン.mydns.jp
Running manual-auth-hook command: /workdir/txtregist.php
manual-auth-hook command "/workdir/txtregist.php" returned error code 127
Error output from manual-auth-hook command txtregist.php:
/bin/sh: 1: /workdir/txtregist.php: not found
 
 Waiting for verification...
Challenge failed for domain メインドメイン.mydns.jp
dns-01 challenge for メインドメイン.mydns.jp
Cleaning up challenges
Running manual-cleanup-hook command: /workdir/txtdelete.php
manual-cleanup-hook command "/workdir/txtdelete.php" returned error code 127
Error output from manual-cleanup-hook command txtdelete.php:
/bin/sh: 1: /workdir/txtdelete.php: not found
 
 Some challenges have failed.
 
 IMPORTANT NOTES:
  - The following errors were reported by the server:
 
    Domain: メインドメイン.mydns.jp
   Type:   dns
   Detail: DNS problem: NXDOMAIN looking up TXT for
   _acme-challenge.メインドメイン.mydns.jp - check that a DNS record exists for
   this domain

直後に試したこと

当初「/bin/sh: 1: /workdir/txtregist.php: not found」は、txtregist.phpのパスをCertbotが認識出来ていないと思っていたので、マウント先を変えたりコピーしたりしていた(後で認識違いだったことを理解)が、そのやり方では解決しなかった。

DNS-01の仕様確認

そもそもDNS-01では何をしているのかを改めて確認した。

長々と書かれているが、MYDNS.JPを例に挙げると以下の手順が必要であると理解。

  1. _acme-challenge.メインドメイン.mydns.jpにType:TXTでContentにチャレンジコードを設定する
  2. 設定が完了してサーバー側で反映されたら、ドメインを検証する
  3. 同じチャレンジコード値の取得に成功したら、証明書が発行・取得できる

おそらくCertbotがやってくれることの一つとして、この一連の処理があるということになる。

Certbotの仕様確認

Certbotでのオプション指定は何をしているのかも確認した。

--manual-auth-hook MANUAL_AUTH_HOOK
Path or command to execute for the authentication
script (default: None)
--manual-cleanup-hook MANUAL_CLEANUP_HOOK
Path or command to execute for the cleanup script
(default: None)

ざっくりいうと、チャレンジコードを発行した後に

  1. --manual-auth-hookで「 _acme-challenge.メインドメイン.mydns.jpにType:TXTでContentにチャレンジコードを設定する」処理
  2. --manual-cleanup-hookで「_acme-challenge.メインドメイン.mydns.jpの設定を削除する」処理

を実行するコマンドかスクリプトをそれぞれ指定すれば良い、ということになる。
MYDNS.JPではtxtregist.phpが1に相当し、txtdelete.phpが2に相当する。
逆に、これらを指定しない場合はいずれも手動でやる必要があるということになる。

Let's Encryptのステージング環境

SSL証明書取得にhttps://acme-v02.api.letsencrypt.org/directoryを使う場合、
短時間に連続失敗するとすぐ制限がかかってしまう。

以下のステージング環境を用いるとレート制限が大幅に緩和され1時間当たり60回まで失敗できるようなので、動作確認ではこちらを使用することが強く推奨されている。
https://acme-staging-v02.api.letsencrypt.org/directory

※本番環境とほとんど同じ動作だが、あくまでテスト用の証明書しか取得できないので注意。

Certbotの仕様では、--test-certもしくは--stagingを指定すれば自動的にステージング環境が選択される模様。

Use the Let's Encrypt staging server to obtain or revoke test (invalid) certificates; equivalent to --server https://acme-staging-v02.api.letsencrypt.org/directory (default: False)

以降の動作確認における手順では--serverでステージング環境のURLを指定している。おそらくどちらでも良い。

MYDNS.JPへ手動設定で証明書取得を確認

上記仕様から実動作を理解するために、まず以下コマンドで手動で取得してみる。
今回はphpスクリプトを使用しないのでCertbot公式のDocker Image(certbot/certbot:amd64-v2.6.0)を使用。
※Certbot公式ImageにはPHPが入っていない。

docker run -it --rm \
-v ./etc:/etc/letsencrypt \
-v ./log:/var/log/letsencrypt \
certbot/certbot:amd64-v2.6.0 \
certonly --manual \
--preferred-challenges=dns \
-d *.メインドメイン.mydns.jp \
--server https://acme-staging-v02.api.letsencrypt.org/directory \
--agree-tos -m メールアドレス

※Entrypointに「certbot」が設定されているので、上書きしないのであればコマンドは「certonly」から書き始める必要がある。

以下のようにチャレンジコードが出て、手動設定を求められる。

Saving debug log to /var/log/letsencrypt/letsencrypt.log
Requesting a certificate for *.メインドメイン.mydns.jp

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please deploy a DNS TXT record under the name:

_acme-challenge.メインドメイン.mydns.jp.

with the following value:

<<ここにチャレンジコード>>

Before continuing, verify the TXT record has been deployed. Depending on the DNS
provider, this may take some time, from a few seconds to multiple minutes. You can
check if it has finished deploying with aid of online tools, such as the Google
Admin Toolbox: https://toolbox.googleapps.com/apps/dig/#TXT/_acme-challenge.メインドメイン.mydns.jp.
Look for one or more bolded line(s) below the line ';ANSWER'. It should show the
value(s) you've just added.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Press Enter to Continue

この状態で、MYDNS.JPのDomain Infoで以下を追加

  • Hostname:_acme-challenge
  • Type:TXT
  • Content:チャレンジコード
  • Target ID:メインID

    ドメイン情報変更画面が出た後、ターミナル側でEnter。
Press Enter to Continue

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/メインドメイン.mydns.jp/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/メインドメイン.mydns.jp/privkey.pem
This certificate expires on 2023-**-**.
These files will be updated when the certificate renews.

NEXT STEPS:
- This certificate will not be renewed automatically. Autorenewal of --manual certificates requires the use of an authentication hook script (--manual-auth-hook) but one was not provided. To renew this certificate, repeat this same certbot command before the certificate's expiry date.
We were unable to subscribe you the EFF mailing list because your e-mail address appears to be invalid. You can try again later by visiting https://act.eff.org.

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

テスト用の証明書が取得できていることを確認

sudo ls -al ./etc/live/メインドメイン.mydns.jp
合計 12
drwxr-xr-x 2 root root 4096  *月 ** **:** .
drwx------ 3 root root 4096  *月 ** **:** ..
-rw-r--r-- 1 root root  692  *月 ** **:** README
lrwxrwxrwx 1 root root   37  *月 ** **:** cert.pem -> ../../archive/メインドメイン.mydns.jp/cert1.pem
lrwxrwxrwx 1 root root   38  *月 ** **:** chain.pem -> ../../archive/メインドメイン.mydns.jp/chain1.pem
lrwxrwxrwx 1 root root   42  *月 ** **:** fullchain.pem -> ../../archive/メインドメイン.mydns.jp/fullchain1.pem
lrwxrwxrwx 1 root root   40  *月 ** **:** privkey.pem -> ../../archive/メインドメイン.mydns.jp/privkey1.pem

※_acme-challenge.メインドメイン.mydns.jpは、証明書取得後削除しておく。
HostnameとContentを空にして更新すれば削除される。

Docker版PHP上でtxtregist.phpが動かなかった原因

手動であればMYDNS.JPでも問題なくDocker版Certbotで証明書が取得できることが分かったので、やはりDocker版のPHPの時だけに何か問題があるということでスクリプトを再確認した。

前述の「/bin/sh: 1: /workdir/txtregist.php: not found」エラーは.phpファイルが見つかっていないわけではなく、.phpファイルを実行するときに何かおかしな動きをしているのではと推測した。
シェルスクリプトの仕様やエラーメッセージはよくわからないが、おそらく「1:」というのはファイル内1行目に対してのエラーと解釈し中身を見たところ、Shebangが書かれており

#!/usr/bin/php

となっていた。
Docker版phpのPHPの場所は

docker run -it --rm php:cli-bullseye /bin/bash -c "which php"
/usr/local/bin/php

となっていた。
念のため確認。

docker run -it --rm php:cli-bullseye /bin/bash -c "/usr/bin/php -v"
/bin/bash: line 1: /usr/bin/php: No such file or directory

/usr/bin/phpにはシンボリックリンクは張られていない。
つまりDocker版PHPで/usr/bin/phpを呼ぼうとしてもそのパスがないため、そこでエラー処理に移りhookの実行が失敗と判定されていると推測した。

最初のエラーはシェルでのエラーだったので、シェルでも確認

docker run -it --rm php:cli-bullseye /bin/sh -c "/usr/bin/php -v"
/bin/sh: 1: /usr/bin/php: not found

.phpファイルから/usr/bin/phpに変わっただけで全く同じエラー形式だったので、ここでPHPが見つからないためのエラーであることでほぼ間違いないと判断した。

検証パターン1:phpファイルの修正

  • /usr/bin/php→/usr/local/bin/phpに置換
    ※おそらくこれが最適解。
for hook in txtregist.php txtdelete.php; do sed -i 's/^#!\/usr\/bin\/php$/#!\/usr\/local\/bin\/php/g' ./DirectEdit/$hook && echo $hook: `head -n 1 ./DirectEdit/$hook`; done
txtregist.php: #!/usr/local/bin/php
txtdelete.php: #!/usr/local/bin/php

以下コマンドを実行

docker run -it --rm \
-v ./etc:/etc/letsencrypt \
-v ./log:/var/log/letsencrypt \
-v ./DirectEdit:/workdir php:mycertbot \
certbot certonly --manual \
--preferred-challenges=dns \
--manual-auth-hook /workdir/txtregist.php \
--manual-cleanup-hook /workdir/txtdelete.php \
-d *.メインドメイン.mydns.jp \
--server https://acme-staging-v02.api.letsencrypt.org/directory \
--agree-tos -m メールアドレス
  • ※Certbot公式Docker Imageで一度取得したディレクトリをマウントさせるとバージョンの違いのせいか以下エラーになるので、一旦中身を削除する。
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator manual, Installer None
Attempting to parse the version 2.6.0 renewal configuration file found at /etc/letsencrypt/renewal/メインドメイン.mydns.jp.conf with version 1.12.0 of Certbot. This might not work.
Are you trying to change the key type of the certificate named メインドメイン.mydns.jp from ECDSA to RSA? Please provide both --cert-name and --key-type on the command line confirm the change you are trying to make.

実行結果

Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator manual, Installer None
Requesting a certificate for *.メインドメイン.mydns.jp
Performing the following challenges:
dns-01 challenge for メインドメイン.mydns.jp
Running manual-auth-hook command: /workdir/txtregist.php
Waiting for verification...
Cleaning up challenges
Running manual-cleanup-hook command: /workdir/txtdelete.php

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/メインドメイン.mydns.jp/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/メインドメイン.mydns.jp/privkey.pem
   Your certificate will expire on 2023-**-**. 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

手動の時と同様に、テスト用の証明書が取得できていることを確認した。

余談

FreeBSDで試した先人の方の記事の中で同様に修正していたので、ちゃんと調べて記事をよく読めばすぐ解決するような非常に単純な問題である。

しかも、公式のREADME.mdの必要環境に「phpが/usr/bin/下に設置されているサーバ」と記載があるので、ここをちゃんと理解していればすぐに特定できる話でもあった。

検証パターン2:オプションを「php スクリプト名」に変更

ファイルの変更はせず呼び方を変えてみる。
Certbotの仕様の通り、スクリプトファイル名の指定だけではなくコマンド呼び出しでも実行できるようなので、コマンドとしてPHPを呼び出すようにしてみた。

まず、/usr/local/bin/php→/usr/bin/phpに戻しておく。

for hook in txtregist.php txtdelete.php; do sed -i 's/^#!\/usr\/local\/bin\/php$/#!\/usr\/bin\/php/g' ./Di
rectEdit/$hook && echo $hook: `head -n 1 ./DirectEdit/$hook`; done
txtregist.php: #!/usr/bin/php
txtdelete.php: #!/usr/bin/php

実行権限はなくても行けるはずなので、念のため外しておく。

chmod 600 DirectEdit/*.php && ls -al DirectEdit/*.php
-rw------- 1 * * 3317  *月 ** **:** DirectEdit/txtdelete.php
-rw------- 1 * * 3317  *月 ** **:** DirectEdit/txtregist.php

以下コマンドを実行

docker run -it --rm \
-v ./etc:/etc/letsencrypt \
-v ./log:/var/log/letsencrypt \
-v ./DirectEdit:/workdir php:mycertbot \
certbot certonly --manual \
--preferred-challenges=dns \
--manual-auth-hook "php /workdir/txtregist.php" \
--manual-cleanup-hook "php /workdir/txtdelete.php" \
-d *.メインドメイン.mydns.jp \
--server https://acme-staging-v02.api.letsencrypt.org/directory \
--agree-tos -m メールアドレス
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator manual, Installer None
Requesting a certificate for *.メインドメイン.mydns.jp
Performing the following challenges:
dns-01 challenge for メインドメイン.mydns.jp
Running manual-auth-hook command: php /workdir/txtregist.php
Waiting for verification...
Cleaning up challenges
Running manual-cleanup-hook command: php /workdir/txtdelete.php
・・・

コマンドが"php スクリプト名"でphpファイルが実行権限無しでも同様に取得できることを確認。
ただし、ファイル内1行目の「#!/usr/bin/php」がPHPでどう解釈されているかよく知らないため、環境によっては正しく動作しなくなることも考えられるのであまり推奨しない。

どうしても公式のスクリプトに手を入れたくなければこのようにするか、
もしくはDocker Image側で/usr/bin/phpに/usr/local/bin/phpへのシンボリックリンクを張ればよいと思う。

検証パターン3:PHPを使わない

そもそもCertbotのmanual-auth-hookとmanual-cleanup-hookは、DDNS側でDNSレコードを書き換えられるAPIが提供されていて、ただ単にユーザの作ったスクリプトでそのAPIが呼び出される前提としてそのスクリプト・コマンドを叩いているだけに過ぎない。
つまり、DDNS側のAPI仕様さえ分かっていれば言語にこだわらず自前でスクリプトを組めば良いということである。
ちなみに戻り値も特に見ていないようである(実行結果が標準出力されるだけ)が、コマンドとしてエラーが発生していれば失敗と判定される。

しかしながら、MYDNS.JPではAPI仕様を公開しているようなページを見つけることができなかった。あるのは上記公式phpスクリプトのみのように思われる。
そのため、このスクリプトを読み解いてレコードへの追加・削除をどのように実現しているかを見たうえでAPI仕様を推測するしかない。

MYDNS.JPのAPI仕様(推測)

  • APIのエンドポイント:https://www.mydns.jp/directedit.html
  • DNSレコードの追加/削除のメソッドはどちらもPOST
  • 追加/削除共通
    • メインドメインのアカウントでBasic認証が必要
    • Certbot側で設定される環境変数を、同一変数名でそのままPOSTのパラメータに設定 ※一部Certbotの仕様にない環境変数もPHP側で取ろうとしているので、おそらく古い仕様に合わせている?
  • 追加の場合:パラメータEDIT_CMDに「REGIST」指定
  • 削除の場合:パラメータEDIT_CMDに「DELETE」指定

調べると既に先人の方がPythonで書いていた。

こちらはCertbotの環境変数の仕様通りのものだけをパラメータに設定している。

以上より、少なくとも上記推測の仕様を満たせばCertbotの動作としては正常に処理されるようである。

Docker版Certbot用にPythonで記述

上記先人の方のPythonをそのまま使っても行けるはずだが、引数にパスワードを渡すのは少し怖いので処理を参考に環境変数で渡すようにした。

dns01.py
import json
import os
from argparse import ArgumentParser
from enum import Enum, auto

import requests
from requests import Response
from requests.auth import HTTPBasicAuth


class RequestMode(Enum):
    REGIST = auto()
    DELETE = auto()


MYDNS_ENDPOINT: str = "https://www.mydns.jp/directedit.html"


def request_certbot(mode: RequestMode) -> Response:
    data: dict = {
        **{
            key: os.environ[key]
            for key in [
                "CERTBOT_DOMAIN",
                "CERTBOT_VALIDATION",
                "CERTBOT_TOKEN",
                "CERTBOT_REMAINING_CHALLENGES",
                "CERTBOT_ALL_DOMAINS",
                "CERTBOT_AUTH_OUTPUT",
            ]
            if isinstance(os.environ.get(key), str)
        },
        **dict(EDIT_CMD=mode.name),
    }
    print(f"mode: {mode.name}\n{json.dumps(data)}")
    return requests.post(
        MYDNS_ENDPOINT, data=data, auth=HTTPBasicAuth(os.environ["MYDNS_ID"], os.environ["MYDNS_PASS"])
    )


if __name__ == "__main__":
    parser: ArgumentParser = ArgumentParser()
    parser.add_argument("mode", choices=["r", "d"], help="mode r:regist, d:delete")
    print(request_certbot(RequestMode.DELETE).status_code)
    if "r" == parser.parse_args().mode:
        print(request_certbot(RequestMode.REGIST).status_code)

環境変数で、MYDNS_IDにメインドメインのID、MYDNS_PASSにパスワードを設定し、
スクリプト呼び出し時に引数rで登録、dで削除となるようにした。
また、事前に_acme-challenge.メインドメイン.mydns.jpの登録があると登録失敗するので、登録の前に必ず削除するようにしている。

ちなみにDocker版CertbotにはPython3が入っておりrequestsモジュールもあるので追加のインストールは不要。

環境変数MYDNS_IDとMYDNS_PASSに設定するファイルを渡すようにコマンド実行

.env
MYDNS_ID=MYDNS.JPのメインドメインのID
MYDNS_PASS=MYDNS.JPのパスワード
docker run -it --rm \
--env-file ./.env \
-v ./etc:/etc/letsencrypt \
-v ./log:/var/log/letsencrypt \
-v ./pyauth:/workdir certbot/certbot:amd64-v2.6.0 \
certonly --manual \
--preferred-challenges=dns \
--manual-auth-hook "python3 /workdir/dns01.py r" \
--manual-cleanup-hook "python3 /workdir/dns01.py d" \
-d *.メインドメイン.mydns.jp \
--server https://acme-staging-v02.api.letsencrypt.org/directory \
--agree-tos -m メールアドレス
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Requesting a certificate for *.メインドメイン.mydns.jp
Hook '--manual-auth-hook' for メインドメイン.mydns.jp ran with output:
 mode: DELETE
 {"CERTBOT_DOMAIN": "メインドメイン.mydns.jp", "CERTBOT_VALIDATION": "チャレンジコード", "CERTBOT_REMAINING_CHALLENGES": "0", "CERTBOT_ALL_DOMAINS": "メインドメイン.mydns.jp", "EDIT_CMD": "DELETE"}
 200
 mode: REGIST
 {"CERTBOT_DOMAIN": "メインドメイン.mydns.jp", "CERTBOT_VALIDATION": "チャレンジコード", "CERTBOT_REMAINING_CHALLENGES": "0", "CERTBOT_ALL_DOMAINS": "メインドメイン.mydns.jp", "EDIT_CMD": "REGIST"}
 200
Hook '--manual-cleanup-hook' for メインドメイン.mydns.jp ran with output:
 mode: DELETE
 {"CERTBOT_DOMAIN": "メインドメイン.mydns.jp", "CERTBOT_VALIDATION": "チャレンジコード", "CERTBOT_REMAINING_CHALLENGES": "0", "CERTBOT_ALL_DOMAINS": "メインドメイン.mydns.jp", "CERTBOT_AUTH_OUTPUT": "mode: DELETE\n{\"CERTBOT_DOMAIN\": \"メインドメイン.mydns.jp\", \"CERTBOT_VALIDATION\": \"チャレンジコード\", \"CERTBOT_REMAINING_CHALLENGES\": \"0\", \"CERTBOT_ALL_DOMAINS\": \"メインドメイン.mydns.jp\", \"EDIT_CMD\": \"DELETE\"}\n200\nmode: REGIST\n{\"CERTBOT_DOMAIN\": \"メインドメイン.mydns.jp\", \"CERTBOT_VALIDATION\": \"チャレンジコード\", \"CERTBOT_REMAINING_CHALLENGES\": \"0\", \"CERTBOT_ALL_DOMAINS\": \"メインドメイン.mydns.jp\", \"EDIT_CMD\": \"REGIST\"}\n200", "EDIT_CMD": "DELETE"}
 200

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/メインドメイン.mydns.jp/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/メインドメイン.mydns.jp/privkey.pem
This certificate expires on 2023-**-**.
These files will be updated when the certificate renews.
・・・

補足・その他

  • Certbotのオプション-nでユーザー入力を飛ばせる。期限切れになっていなければ更新しない。

  • --expandオプションがよくわからない。以前取得した証明書の上位ドメインを取得しようとした場合に拡張した証明書を取る?

    If an existing certificate is a strict subset of the requested names, always expand and replace it with the additional names. (default: Ask)

    Certbotの引数全仕様は把握していない。

  • メインドメインに対する証明書も取得したければ、オプションに"-d メインドメイン.mydns.jp"も指定すること。本題ではないので詳細は割愛。

Discussion