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

webのエンジニアをやっており、日頃の開発で詰まったことや書き残しておきたいことを載せています。育児のイロハという育児サイト(https://ikujip.jp)の開発も行っているため、その開発で使用されている技術についても掲載しています。

Nginx+TomcatでLet's EncryptのSSL設定

Let's Encryptとは

Let’s Encrypt(レッツ・エンクリプト)は、アメリカの非営利団体であるISRG(Internet Security Research Group)が、すべてのWebサーバへの接続を暗号化することを目指したプロジェクトの一貫でサービスを提供しています。
SSLの設定に関わる面倒な手続き(料金の支払いやメールによる確認等)は省略され、無料で使用することができます。

無料なのに安全なの?と思われる方もいるかもしれませんが、無償だからといって安全性が低いわけではありません。
クライアント案件では使いづらいかもしれませんが、個人利用であれば十分問題ないと思います。

Nginx+TomcatSSL設定

今回はNginxとTomcatをリバースプロキシで連携させた構成のサーバを想定しています。
この構成の設定例を見たい方は、以下に記載してあるので参考にしてください。

ti-tomo-knowledge.hatenablog.com

Let's Encryptで証明書を作ったあとその証明書を使えるように、クライアントからのアクセスを受けるNginx側と連携先のTomcat側の両方で証明書と秘密鍵の設定が必要になります。

Let's Encryptのインストール

以下のようにcurlでインストールし、certbot-autoで証明書を作成できるように権限の付与もしてください。

sudo curl https://dl.eff.org/certbot-auto -o /usr/bin/certbot-auto
sudo chmod 700 /usr/bin/certbot-auto

certbot-autoでSSL証明書の取得と秘密鍵の生成

証明書の取得前に注意してほしいのが、すでにTomcatへのリバースプロキシを設定している場合、nginx.confのproxy_passの記述箇所をコメントアウトしておいてください。
(環境によって記述されている箇所は異なるかもしれないので、それぞれの環境に応じてproxy_passの記述箇所をコメントアウトしてください。)

リバースプロキシを設定している場合、おそらく

proxy_pass https://localhost:8080;

proxy_pass https://localhost:8443;

と記述があると思うので、この箇所だけ以下のようにコメントアウトしてください。

# proxy_pass https://localhost:8080;

# proxy_pass https://localhost:8443;

理由としては、以下手順で証明書を取得するのですが、ルートディレクトリを「/usr/share/nginx/html」と設定しているので、リバースプロキシを設定したままだとTomcatに連携してしまい、ルートディレクトリが「/usr/share/nginx/html」ではなくなってしまうからです。

では以下のcertbot-autoコマンドを実行してSSL証明書を取得しましょう。
前述の通り、ルートディレクトリは「--webroot -w /usr/share/nginx/html」を指定しています。

※例として、今回はtestdomain.comというドメイン名でSSLを取得し、メールアドレスtest@testdomain.comを使うものとします。
メールアドレスは、SSLの登録や回復などに使用することになりますが、SSLを取得するドメインと同一ドメインである必要はなく、受信できるものであれば何でも構いません。

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

この手順によって、「/etc/letsencrypt/live/testdomain.com/」直下に取得した証明書と秘密鍵が配置されます。
※testdomain.comは指定したドメインになるため、環境によって変わってきます。

まずはこの証明書と秘密鍵をNginxに設定しましょう。

NginxのSSL設定

前手順で取得したSSL証明書(cert.pem)と秘密鍵(privkey.pem)をnginx.confで設定します。
証明書と秘密鍵の設定箇所は443でlistenしている箇所になります。
以下、設定例になります。

変更前

{
#    server {
#        listen       443 ssl http2 default_server;
#        listen       [::]:443 ssl http2 default_server;
#        server_name  localhost;
#        root         /usr/share/nginx/html;

#        ssl_certificate "/etc/pki/nginx/server.crt";
#        ssl_certificate_key "/etc/pki/nginx/private/server.key";
}
#        # It is *strongly* recommended to generate unique DH parameters
#        # Generate them with: openssl dhparam -out /etc/pki/nginx/dhparams.pem 2048
#        #ssl_dhparam "/etc/pki/nginx/dhparams.pem";
#        ssl_session_cache shared:SSL:1m;
#        ssl_session_timeout  10m;
#        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
#        ssl_ciphers HIGH:SEED:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!RSAPSK:!aDH:!aECDH:!EDH-DSS-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA:!SRP;
#        ssl_prefer_server_ciphers on;
#
#        # Load configuration files for the default server block.
#        include /etc/nginx/default.d/*.conf; # コメントアウト外した

#        location / {
#        }

#        error_page 404 /404.html;
#            location = /40x.html {
#        }

#        error_page 500 502 503 504 /50x.html;
#            location = /50x.html {
#        }
#    }
}

変更後

{
    server {
        listen       443 ssl http2 default_server;
        listen       [::]:443 ssl http2 default_server;
        server_name  testdomain.com; # 変更した箇所
        root         /usr/share/nginx/html;

        ssl_certificate "/etc/letsencrypt/live/testdomain.com/cert.pem"; # 変更した箇所
        ssl_certificate_key "/etc/letsencrypt/live/testdomain.com/privkey.pem"; # 変更した箇所
}
#        # It is *strongly* recommended to generate unique DH parameters
#        # Generate them with: openssl dhparam -out /etc/pki/nginx/dhparams.pem 2048
#        #ssl_dhparam "/etc/pki/nginx/dhparams.pem";
#        ssl_session_cache shared:SSL:1m;
#        ssl_session_timeout  10m;
#        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
#        ssl_ciphers HIGH:SEED:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!RSAPSK:!aDH:!aECDH:!EDH-DSS-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA:!SRP;
#        ssl_prefer_server_ciphers on;
#
#        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf; # コメントアウト外した

        location / {
        }

        error_page 404 /404.html;
            location = /40x.html {
        }

        error_page 500 502 503 504 /50x.html;
            location = /50x.html {
        }
    }
}

設定内容を反映させるため、Nginxを再起動してください。
※リバースプロキシの設定をコメントアウトした場合は、ここでコメントアウトを外して戻しておくことを忘れないでください。

service nginx restart

これでNginx側の設定は完了です。

サーバ証明書秘密鍵をpkcs12形式に変換

次はTomcat側の設定になりますが、Tomcatでは証明書と秘密鍵を合わせたpkcs12形式のキーストアファイルで設定する必要があるのです。
まずはopensslによって、証明書と秘密鍵Tomcatで読み込めるようにpkcs12形式に変換し、その後キーストアファイルに保存します。

ではまずpkcs12形式に変換するコマンドです。
※この時パスワードを設定するはずなので、控えておいてください。

cd /etc/letsencrypt/live/testdomain.com/ # 環境によって異なる可能性があるので注意してください。
openssl pkcs12 -export -in fullchain.pem -inkey privkey.pem -out fullchain_and_key.p12 -name tomcat

上記はfullchain.pemという証明書とprivkey.pemという秘密鍵を合わせてfullchain_and_key.p12に変換しています。-nameの箇所は例としてtomcatにしていますが、tomcatではなくても何でも構いません。

続いてkeytoolコマンドを使用してキーストアファイルに保存します。
※「パスワード」の箇所は前手順で設定したパスワードを入力してください。

keytool -importkeystore -deststorepass パスワード -destkeypass パスワード -destkeystore MyDSKeyStore.jks -srckeystore fullchain_and_key.p12 -srcstoretype PKCS12 -srcstorepass パスワード -alias tomcat

これでTomcatで設定するためのキーストアファイルが完成しました。

ただ、このままではTomcatで読み込もうとするとパーミッションエラーになってしまうので、tomcatディレクトリ配下にコピーして権限も変更してください。
※今回の手順ではTomcat8を使用しているたまに「/etc/tomcat8」配下にコピーしていますが、こちらは環境によって変わってきます。

cp -p /etc/letsencrypt/live/testdomain.com/MyDSKeyStore.jks /etc/tomcat8/MyDSKeyStore.jks
chmod 755 /etc/tomcat8/MyDSKeyStore.jks
chown root:tomcat /etc/tomcat8/MyDSKeyStore.jks

これでTomcatでキーストアを読み込む準備ができました。

TomcatSSL設定

それでは前手順で取得したキーストアファイルを読み込みますが、設定するファイルは「server.xml」になります。
Connector port="8443"の記述箇所を変更してください。

※今回の手順ではTomcat8を使用しているために「/etc/tomcat8」配下のserver.xmlファイルを変更していますが、こちらは環境によって変わってきます。

vim /etc/tomcat8/server.xml

※「パスワード」の箇所はopensslコマンド実行時に設定したパスワードを入力してください。また、「keyAlias="tomcat"」は、先ほどkeytoolコマンド実行時に-nameで入力した値を設定する必要があります。

<Connector port="8443" protocol="org.apache.coyote.http11.Http11Protocol"
    maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
    clientAuth="false" sslProtocol="TLS"      keystoreFile="/etc/tomcat8/MyDSKeyStore.jks"  keystorePass="パスワード"
    keyAlias="tomcat" keyPass="パスワード"/>

最後に再起動させれば設定完了です。

service tomcat8 restart

まとめ

以上で手順としては完了です。
説明を追記しながらの手順なので、長い印象を受けてしまうかもしれませんが、実行しているコマンドはそれほど多くありません。
慣れれば5分くらいで設定できるようなものなので、是非試していただきたいです。

スッキリわかる サーブレット&JSP入門 (スッキリシリーズ)

スッキリわかる サーブレット&JSP入門 (スッキリシリーズ)

Java+MySQL+Tomcatで始めるWebアプリケーション構築入門

Java+MySQL+Tomcatで始めるWebアプリケーション構築入門