目次

FreeBSD 13とApache 2.4とcertbotでLet's Encrypt!

自宅鯖を間違ってsudo rm -rf /してしまったので、再度certbotでLet's Encryptの設定を行った。公式サイトにOSとhttpdごとの設定方法が載ってるが、portsでは更にFreeBSDの定期ジョブ設定による更新が行える。

試した環境

手順

certbtのインストール

certbotをpkgでサクッとインストールする。webrootモードで更新したいのでapache用のプラグインも入れる。

$ sudo pkg install py38-certbot py38-certbot-apache
(略)
=====
Message from py38-certbot-1.14.0,1:

--
This port installs the "standalone" client only, which does not use and
is not the certbot-auto bootstrap/wrapper script.

The simplest form of usage to obtain certificates is:

 # sudo certbot certonly --standalone -d <domain>, [domain2, ... domainN]>

NOTE:

The client requires the ability to bind on TCP port 80 or 443 (depending
on the --preferred-challenges option used). If a server is running on that
port, it will need to be temporarily stopped so that the standalone server
can listen on that port to complete the challenge authentication process.

For more information on the 'standalone' mode, see:

  https://certbot.eff.org/docs/using.html#standalone

The certbot plugins to support apache and nginx certificate installation
will be made available in the following ports:

 * Apache plugin: security/py-certbot-apache
 * Nginx plugin: security/py-certbot-nginx

In order to automatically renew the certificates, add this line to
/etc/periodic.conf:

    weekly_certbot_enable="YES"

More config details in the certbot periodic script:

    /usr/local/etc/periodic/weekly/500.certbot-3.8

certbotにはStandaloneとWebrootの2つのモードがあり、前者はその名の通りcertbot単体で、後者は他のサービスと連携して証明書の取得&更新を行うモードとのこと。

証明書の取得

certbotで証明書の取得を行う。

-wにApacheのドキュメントルート、-dに証明を受けるドメインのFQDNを指定する。初回のみメールアドレス関連のあれこれが聞かれるので、適切に回答する。

Webrootモードでの認証は、certbotが-wで指定したディレクトリに.well-known/acme-challenge/xxxyyyzzzという認証用ファイルを作成し、Let's Encrypt側からそのファイルへアクセスすることで、ドメインの正当性が検証される。

証明書は/usr/local/etc/letsencrypt/live/指定したFQDN/の下に置かれる。

$  sudo certbot certonly --webroot -w /usr/home/www/ -d hoge.example.com
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator webroot, Installer None
Requesting a certificate for hoge.example.com

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /usr/local/etc/letsencrypt/live/hoge.example.com/fullchain.pem
   Your key file has been saved at:
   /usr/local/etc/letsencrypt/live/hoge.example.com/privkey.pem
   Your certificate will expire on 2021-08-02. 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

ApacheのSSL設定

ApacheのSSLの設定を行う。Mozilla SSL Configuration Generatorで生成したものを使う方が確実かも…。

サンプルファイルをコピー。

$ cd /usr/local/etc/apache24
$ sudo cp extra/httpd-ssl.conf Includes/
$ sudo emacs Includes/httpd-ssl.conf

重要なのはSSLCertificateFileSSLCertificateKeyFile

SSLRandomSeed startup file:/dev/random  512
SSLRandomSeed connect file:/dev/random  512

Listen 443

SSLCipherSuite !3DES:!aNULL:EDH+HIGH:ECDH+HIGH:-AES128:-3DES:-DSS:ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-SHA
SSLProxyCipherSuite !3DES:!aNULL:EDH+HIGH:ECDH+HIGH:-AES128:-3DES:-DSS:ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-SHA

SSLHonorCipherOrder on

SSLProtocol all -SSLv2 -SSLv3
SSLProxyProtocol all -SSLv2 -SSLv3

SSLPassPhraseDialog  builtin

SSLSessionCache        "shmcb:/var/run/ssl_scache(512000)"
SSLSessionCacheTimeout  300

<VirtualHost _default_:443>
DocumentRoot "/usr/home/www"
ServerName hoge.example.com:443
ServerAdmin you@example.com
ErrorLog "/var/log/httpd-error.log"
TransferLog "/var/log/httpd-access.log"

SSLEngine on
SSLCertificateFile "/usr/local/etc/letsencrypt/live/hoge.example.com/fullchain.pem"
SSLCertificateKeyFile "/usr/local/etc/letsencrypt/live/hoge.example.com/privkey.pem"

<FilesMatch "\.(cgi|shtml|phtml|php)$">
    SSLOptions +StdEnvVars
</FilesMatch>
<Directory "/usr/local/www/apache24/cgi-bin">
    SSLOptions +StdEnvVars
</Directory>

BrowserMatch "MSIE [2-5]" \
         nokeepalive ssl-unclean-shutdown \
         downgrade-1.0 force-response-1.0

CustomLog "/var/log/httpd-ssl_request.log" \
          "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"

</VirtualHost>

証明書の自動更新の設定

Let's Encryptの証明書は有効期限が90日なので、忘れずに自動更新設定を行う。

証明書の更新はHTTP経由で行われる。HTTPSじゃなくてHTTPね。ここ、重要。

外部からHTTPでhttp://対象ドメイン/.well-known/acme-challenge/に到達できるよう、ルータのポートフォワードやらApacheのVirtualHostやらを適切に設定のこと。宅内DNSで、宅内では対象ドメインにプライベートIPアドレスを割り当ててたりすると、宅内の作業PCからはhttpアクセスできるように見えて、外部からは到達不可で証明書の更新が行えないなんていう事も起こりうるので要注意(実際にハマった。)

まずはテスト。

$ sudo certbot --dry-run renew
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /usr/local/etc/letsencrypt/renewal/hoge.example.com.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cert not due for renewal, but simulating renewal for dry run
Plugins selected: Authenticator webroot, Installer None
Simulating renewal of an existing certificate for hoge.example.com
Performing the following challenges:
http-01 challenge for hoge.example.com
Using the webroot path /usr/home/www for all unmatched domains.
Waiting for verification...
Cleaning up challenges

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
new certificate deployed without reload, fullchain is
/usr/local/etc/letsencrypt/live/hoge.example.com/fullchain.pem
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

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

問題なさそうなので、/etc/periodic.confに追加。

# echo 'weekly_certbot_enable="YES"' >> /etc/periodic.conf

証明書のリロード設定

更新済みの証明書をApacheでリロードする。これをしないと、古い証明書が使われ続ける挙句、httpdがCPUに100%張り付くという残念なことになる。参考:certbot renewでApacheがCPU 100%に張り付くでござるの巻き

certbotは良くできていて、証明書更新時にフックスクリプトを実行できるようになっている。/usr/local/etc/letsencrypt/renewal-hooks/deploy/service apache24 reloadを呼ぶスクリプトを配置する。

reload_apache24.sh
#!/bin/sh
service `echo $0|sed -e 's/.*\/\(.*\)_\(.*\).sh/\2 \1/'`

ファイル名から対象のサービスとコマンドを切り出す形なので、中身は同一でファイル名を変えるだけで様々なサービスに対応できる。それこそハードリンクで良い感じに処理できるかも?

参考サイト