【保護されていない通信http://】NginxとCertbotで無料SSL証明書(Lets Encrypt)を取得 エラー&成功例


投稿日 2019年5月23日 >> 更新日 2023年3月3日

よくブラウザなどで見かけるURLの左側に「保護されていない通信」というのがある。

Webサービスを開発し運用している身としては見栄えが悪すぎるし、訪れて下さっているユーザーも不安に感じてしまう。

なので、思い立ったらすぐ行動ということでSSLを一秒でも早く取り入れ、安全に保護されたWebサイトに生まれ変わらそうと思います。

※独自ドメイン&名前確定済み

実行環境

実行環境
CentOS7
Nginx

SSLについて調べた結果

簡単に言ってしまうと暗号化された通信を行ってくれるシステムです。

外部に情報を漏らさないよう安全に通信を行う。個人情報などを取り扱う際に必須となります。ネットバンクやECサイト、老舗サイトなどはセキュリティを強固にするため有料のSSL証明書を発行しているみたいです。

昨今Web界隈ではセキュリティ対策がしっかり行われたサイトが基準化されているといった記事もよく見かけます。

とはいえWebサービス開発者としてセキュリティ強化は必須ですので一刻も早くSSLを導入していきましょう!

Let's EncryptとCertbot

  • Let's Encrypt(レッツ エンクリプト)とは、無料でSSL証明書を発行しているサービスです。レンタルサーバー会社の無料SSLもLet's Encryptが使われています。
  • Certbotとは、Let's Encryptが発行するSSL証明書を簡単なコマンドで取得できるパッケージです.。

私も色々なサイトを参考にさせてもらいましたが、証明書を取得するパッケージのインストールだけでも色々なやり方があります。

その中でもシンプルだと思われるやり方です。

Certbotを取得するためにEPEL というLinux拡張用のレポジトリをインストールします。

※CentOS7ではレポジトリは標準で導入されているらしい。


# OSの確認
$ cat /etc/redhat-release
CentOS Linux release 7.6.1810 (Core)

# SSLの確認
$ openssl version
OpenSSL 1.0.2k-fips  26 Jan 2017

# 私の環境では既にepelは導入されていました
$ yum install epel-release

$ yum install certbot
# ※最新版はcertbot-autoですが、ここではcertbotで進めて行きます。

前半:エラー編

さっそく証明書の発行をするために以下のコマンドを打ちました。


$ sudo certbot certonly --webroot -w /var/www/example -d example.com

# ※それぞれの意味は他のサイトを参考にしています

certonly : 証明書発行

--webroot : 起動中のWebサーバーを用いてSSL発行の手続きを行う

-w : ドキュメントルートを指定
(/var/www/exampleでも/var/.../...でも自分が分かるディレクトリでよい)

-d : SSL化対象のドメインを指定(独自ドメイン: example.com)

上記のコマンドを実行した結果

1、メールアドレスが求められます。私はGmailを添えました。

2、規約についての同意が求められます。私は同意しました。(A)gree

3、先ほど登録したメールアドレス宛にLets Encryptの更新情報を受け取るか問われます。Y/N

正常に進めば

Congratulations!   Your...........

失敗例

The following errors were reported by the server:

私は失敗していたことに気づかず最終設定までしてしまったので、根本的な問題に気づくまでかなり遠回りな事をしていました。

以下は失敗例ですが再度SSL証明書を発行するコマンドを試した例


$ sudo certbot certonly --webroot -w /var/www/example -d example.com
デバッグログを/var/log/letsencrypt/letsencrypt.logに保存する
選択したプラグイン:オーセンティケーターWebルート、インストーラーなし
新しいHTTPS接続を開始する(1):acme-v02.api.letsencrypt.org
新しい証明書を入手する
以下の課題を実行します。
example.comのhttp-01チャレンジ
すべての不一致ドメインに対してWebルートパス/var/www/exampleを使用します。
確認を待っています...
課題を片付ける
認証手順が失敗しました。 example.com(http-01):urn:ietf:params:acme:エラー:未承認::クライアントに十分な承認がありません:: http://example.com/.well-known/acme-challenge/1sT6Oq5V7_MtjqX_Wdv7Rからの無効な応答 -  C2fbb0xxDH0PCmMRF-ryo [000.000.00.000]:404 ←サーバーのIPアドレス

重要な注意:
  - サーバーから以下のエラーが報告されました。

   ドメイン:example.com
   タイプ:無許可
   詳細:からの無効な応答
   http://example.com/.well-known/acme-challenge/1sT6Oq5V7_MtjqX_Wdv7R-C2fbb0xxDH0PCmMRF-ryo
   [000.000.00.000]:404 ←サーバーのIPアドレス

   これらのエラーを修正するには、ドメイン名が
   正しく入力され、そのドメインのDNS A / AAAAレコード
   正しいIPアドレスを含む。

私はこのようなエラーを見てドメインに問題があると思いました。契約しているネームサーバー(DNS)での名前解決ができていないと。

しかしこの作業をするに当たってある程度の事は調べてあったので、もちろん名前確定を済ませているわけであります。

指摘された通りDNSを洗い直し、正引き(ドメインからIPアドレス)はされてあったので逆引き(IPアドレスからドメイン)を設定しインターネットに反映されるであろう数時間程度間を置き実行してみましたがダメでした。

ちなみにドメインとIPアドレスの確認は、nslookupコマンドで取得できます。


$ nslookup example.com
ネーム=
アドレス=

$ nslookup 000.000.00.000
ネーム=
アドレス=

それから二日間が経過...

(後に気づいた事ですが、webrootで証明書を発行するにはnginxの設定が必要との事でした。)

後半:成功編 standalone

色々なサイトを拝見させてもらったわけですが、Webサーバー(nginx)を停止中もしくわインストール前でもSSL証明書を発行できるという情報に辿り着いたのです。

nginxが「起動中」での作業に気を取られ過ぎていて迷走状態だったので、nginxを停止状態にしてから導入する方法を試すことにしました。

certbotのstandaloneオプションを使う事によってWebサーバーが停止中でもSSL証明書を発行してもらう事ができます。


$ sudo certbot certonly --standalone -d example.com

# 私の場合は一度失敗した際に、email・規約・通知に関する対話は終えていたのですぐ下記のようになりました

# 成功例
Congratulations! Your.....

取得できた証明書一式は/etc/letsencrypt/ディレクトリ内に納められます。

/etc/letsencrypt/live/層をnginx(Webサーバー)に記述します。

# /etc/letsencrypt/

├── accounts/ 
├── archive/
│   └── example.com/
├── csr
├── keys
├── live/
│   └── example.com
│       ├── cert.pem -> ../../archive/example.com/cert2.pem
│       ├── chain.pem -> ../../archive/example.com/chain2.pem
│       ├── fullchain.pem -> ../../archive/example.com/fullchain2.pem ←読み込ませる
│       └── privkey.pem -> ../../archive/example.com/privkey2.pem  ←読み込ませる
└── renewal/
    └── example.com.conf

それでは取得できたSSL証明書をnginxに記述していきますが、nginx.confの設定ファイルに直接書き込まないように注意してください。

おそらくアプリを制作している人であれば、/etc/nginx/conf.d/辺りのディレクトリにアプリをnginxに読み込ませるファイルを作成していると思われます。

仮に/etc/nginx/conf.d/example.confというファイルを書き換えてみます。


server {
    listen 80;
    listen [::]:80;
    server_name example.com;
    return 301 https://$host$request_uri;
}

server {   # ←このディレクティブはwww.exampleで検索されたドメインをexample.comにリダイレクトする
    listen 80;
    listen 443 ssl;
    server_name www.example.com;
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;  # ←証明書
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;  # ←証明書
    return 301 https://example.com$request_uri;  # ←www付きここにリダイレクトする
}

server {
    listen 443 ssl default_server;
    server_name example.com;
    ssl on;
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;  # ←証明書
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;  # ←証明書
    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

残りは

  • nginxの起動&起動に失敗した時の対処法
  • 「https」にて確認
  • certbotの更新コマンド(無料SSL証明書の有効期限は90日)

ではnginxを起動してみましょう。


$ sudo systemctl start nginx

# Webアプリがあれば一応
$ sudo systemctl restart example.app

ログが表れなけば成功していると思うので、「https」としてアクセスしてみてください。

エラーが起こった場合は先ほど設定したexample.confなどの記述ミスが無いか確かめるなどの処置をしてください。ログで確認する方法は以下です。


$ sudo journalctl -xe
#エラーログ一覧が表れるので1つ1つ確認して原因を見つけてください。

上手くURLに鍵マークが表示されたら、更新コマンドと有効期限の確認です。LetsEncryptのSSL証明書は発行から90日間が有効です。30日前の更新が推奨されているみたいです。

certbotのrenewコマンドで更新手続きが行えます。


# 更新コマンド
$ sudo certbot renew
Saving debug log to /var/log/letsencrypt/letsencrypt.log
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/example.com.conf
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cert not yet due for renewal
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
The following certs are not due for renewal yet:
  /etc/letsencrypt/live/example.com/fullchain.pem expires on 2019-××-××(skipped)
No renewals were attempted.

# 有効期限の確認
$ sudo certbot certificates
Saving debug log to /var/log/letsencrypt/letsencrypt.log

Found the following certs:
  Certificate Name: example.com
    Domains: example.com
    Expiry Date: 2019-08-20 21:10:02+00:00 (VALID: 12 days)
    Certificate Path: /etc/letsencrypt/live/example.com/fullchain.pem
    Private Key Path: /etc/letsencrypt/live/example.com/privkey.pem

これで一通り終わったかのように思いますが、CertbotのwebrootオプションでのSSL証明書を再取得するためにnginx(Webサーバー)に読み込ませるための設定ファイル(/etc/nginx/conf.d/example.conf)を書き直し、cronでのSSL証明書を自動取得させる作業を行ってください。

webrootオプションは私が最初に行った失敗例の作業です。ここにきてwebrootを使う事でnginxが起動中でもSSL証明書を取得することができます。 が、/etc/nginx/conf.d/example.confファイルに新たな記述を追加しなければなりません。

次回、SSL証明書を自動取得するでお話します。

この作業をしている過程で数々のサイトを参考にさせていただきました。

技術者の皆さん、ありがとうございます。