親バカエンジニアのナレッジ帳

webのエンジニアをやっており、日頃の開発で詰まったことや書き残しておきたいことを載せています。

Nginxでリバースプロキシ設定をしている場合のLet's Encrypt設定


リバースプロキシを設定している場合でも、サーバを停止させずに更新できる

以前以下の記事で、Nginxでリバースプロキシの設定をしている場合、一度リバースプロキシの設定箇所をコメントアウトする方法を書きましたが、

ti-tomo-knowledge.hatenablog.com

コメントアウトしなくても設定する方法がありますので、そちらの方法を記します。
※今回はLet's Encryptのインストール手順などは省きますので、まだインストールしていない方は上記のリンクを参考にしてください。

今回の対応内容は以下を参考にさせていただきました。

Let’s Encrypt Auto-Renewal for Nginx Reverse Proxies | Tom Busby

リバースプロキシを設定している場合、通常通りcertbotコマンドを実行すると。。。

今回ドメインは例としてtest.comとします。
リバースプロキシを設定しており、何も対応をしない場合、コマンドを実行すると、

sudo /usr/bin/certbot-auto certonly --webroot -w /usr/share/nginx/html --debug -d test.com --email testmail@test.com

以下のようになります。

Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator webroot, Installer None
Cert is due for renewal, auto-renewing...
Renewing an existing certificate
Performing the following challenges:
http-01 challenge for test.com
Using the webroot path /usr/share/nginx/html for all unmatched domains.
Waiting for verification...
Cleaning up challenges
Exiting abnormally:
Traceback (most recent call last):
  File "/opt/eff.org/certbot/venv/bin/letsencrypt", line 11, in <module>
    sys.exit(main())
  File "/opt/eff.org/certbot/venv/local/lib/python2.7/site-packages/certbot/main.py", line 1364, in main
    return config.func(config, plugins)
  File "/opt/eff.org/certbot/venv/local/lib/python2.7/site-packages/certbot/main.py", line 1249, in certonly
    lineage = _get_and_save_cert(le_client, config, domains, certname, lineage)
  File "/opt/eff.org/certbot/venv/local/lib/python2.7/site-packages/certbot/main.py", line 116, in _get_and_save_cert
    renewal.renew_cert(config, domains, le_client, lineage)
  File "/opt/eff.org/certbot/venv/local/lib/python2.7/site-packages/certbot/renewal.py", line 310, in renew_cert
    new_cert, new_chain, new_key, _ = le_client.obtain_certificate(domains, new_key)
  File "/opt/eff.org/certbot/venv/local/lib/python2.7/site-packages/certbot/client.py", line 353, in obtain_certificate
    orderr = self._get_order_and_authorizations(csr.data, self.config.allow_subset_of_names)
  File "/opt/eff.org/certbot/venv/local/lib/python2.7/site-packages/certbot/client.py", line 389, in _get_order_and_authorizations
    authzr = self.auth_handler.handle_authorizations(orderr, best_effort)
  File "/opt/eff.org/certbot/venv/local/lib/python2.7/site-packages/certbot/auth_handler.py", line 82, in handle_authorizations
    self._respond(aauthzrs, resp, best_effort)
  File "/opt/eff.org/certbot/venv/local/lib/python2.7/site-packages/certbot/auth_handler.py", line 161, in _respond
    self._poll_challenges(aauthzrs, chall_update, best_effort)
  File "/opt/eff.org/certbot/venv/local/lib/python2.7/site-packages/certbot/auth_handler.py", line 232, in _poll_challenges
    raise errors.FailedChallenges(all_failed_achalls)
FailedChallenges: Failed authorization procedure. test.com (http-01): urn:ietf:params:acme:error:unauthorized :: The client lacks sufficient authorization :: Invalid response from http://test.com/.well-known/acme-challenge/CrmMBKALG8X3ZzRER-qeDdMqw2DNghlupryqq1z6oAo: "<!DOCTYPE html>\n<html lang=\"ja\"><head><meta charset=\"utf-8\" /><meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\" /><meta name="
Please see the logfiles in /var/log/letsencrypt for more details.

IMPORTANT NOTES:
 - The following errors were reported by the server:

   Domain: test.com
   Type:   unauthorized
   Detail: Invalid response from
   http://test.com/.well-known/acme-challenge/CrmMBKALG8X3ZzRER-qeDdMqw2DNghlupryqq1z6oAo:
   "<!DOCTYPE html>\n<html lang=\"ja\"><head><meta charset=\"utf-8\"
   /><meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\" /><meta
   name="

   To fix these errors, please make sure that your domain name was
   entered correctly and the DNS A/AAAA record(s) for that domain
   contain(s) the right IP address.

ルートディレクトリを「/usr/share/nginx/html」と設定しているのに、リバースプロキシの設定によりTomcatに連携してしまい、ルートディレクトリが「/usr/share/nginx/html」ではなくなってしまうからエラーが発生しているわけです。




今回の対応内容

今回対応する内容としては、仮想のルートディレクトリを作成し、certbotがSSLを発行するためにアクセスした場合にそのルートディレクトリに飛ばすようにします。

まずは仮想のルートディレクトリを作成します。

sudo mkdir -p /var/www/ssl-proof/rancher/.well-known

次に、certbotがアクセスした場合は上記を参照するようにNginxで設定します。

vim /etc/nginx/nginx.conf

で以下の記述を入れるのですが、

location /.well-known {
    root  /var/www/ssl-proof/rancher/;
}

入れる場所はすでにSSLの設定をしている場合は「server { ...」の

listen       443 ssl http2 default_server;

以下に記述してください。

まだSSLの設定をしていない場合は、

listen       80 default_server;

以下に記述してください。

これでNginxを再起動させ、再度certbotのコマンドを発行しますが、この時webrootの値が変わっているので注意が必要です。
最初は「--webroot -w /usr/share/nginx/html」でしたが、ルートディレクトリを切り分けているので、「--webroot -w /var/www/ssl-proof/rancher/」にする必要があります。

sudo /usr/bin/certbot-auto certonly --webroot -w /var/www/ssl-proof/rancher/ --debug -d test.com --email testmail@test.com

以下のようになれば成功です

Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator webroot, Installer None
Cert is due for renewal, auto-renewing...
Renewing an existing certificate
Performing the following challenges:
http-01 challenge for test.com
Using the webroot path /var/www/ssl-proof/rancher for all unmatched domains.
Waiting for verification...
Cleaning up challenges

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/test.com/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/test.com/privkey.pem
   Your cert will expire on 2019-04-30. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot-auto
   again. To non-interactively renew *all* of your certificates, run
   "certbot-auto 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

最後にまたNginxを再起動させてください。

certbot-auto renew --post-hook "service nginx restart"

を実行すれば、次回以降はまた同じコマンドが発行されるのでcronによる自動更新も可能です。