Amazon Linux 2023 にcertbotを入れてWEBサーバーのTLS化をしてみた。

Amazon Linux 2023 で稼働しているWEBサイトをTLS化します。サーバー証明書が必要なので無料で取得が出来る Let's Encrypt のサーバー証明書を取得します。Let's Encrypt でサーバー証明書を取得するにはcertbotアプリをインストールする必要があります。

Amazon Linux 2023 のリポジトリ(/etc/yum.repos.d/amazonlinux.repo)にはcertbotが含まれているので、すぐにインストールができます。インストールはrootユーザーで行います。

# dnf install certbot

インストールが完了したらバージョンを確認してみます。

# certbot --version
certbot 2.6.0

2024年6月時点で ver.2.6.0 のようです。

事前準備としてポート80と443を開けておきます。以下はLightsailのファイアウォールの設定画面の例です。

certbotを使ってサーバー証明書を取得します。以下のコマンドを入力します。

# certbot certonly --webroot -w /var/www/html/example -d www.example.com

引数の意味ですが、以下です。

certonly
サーバー証明書を取得する。ApacheやNginxなどのWEBサーバーの設定ファイルの書き換えはしない。

--webroot -w パス指定
認証のために Let's Encrypt 側からアクセスをしてきて、ここに一時的に作成されたファイルを(Let's Encrypt 側が)確認する。トップページ(index.htmlを配置する場所)にすると良いと思われる。

-d ドメイン名
サーバー証明書を取得するドメイン名を指定する。

コマンドを実行したときのログのイメージです。途中で質問をされます。

① 連絡先のEメールアドレスを入力します。証明書の期限切れが近づくとメールが届きます。

② 同意するかどうかの確認です。ここは同意(Y)を入力します。

③ Electronic Frontier Foundation にEメールアドレスを公開するかどうか確認をされます。公開したくなければ(N)を入力します。

Successfully received certificate.と表示されていればサーバー証明書が発行されました。④の fullchain.pem がサーバー証明書です。⑤の privkey.pem が秘密鍵です。なお秘密鍵はrootでしかアクセスできません。④、⑤のファイルはWEBサーバーのTLS化の設定に必要なものです。

WEBサーバー側の設定をします。Nginxの例です。NginxでTLS化に必要な設定は以下です。

① listen ディレクティブで443ポートを指定して、sslパラメータを付与してTLSを有効にします。

② server_name ディレクティブでドメイン名を指定します。

③ ssl_certificate ディレクティブでサーバー証明書を指定します。

④ ssl_certificate_key ディレクティブで秘密鍵を指定します。

nginx -t コマンドでコンフィグの確認をします。

# nginx -t

問題がなければnginxを再起動します。

# systemctl restart nginx

「https://www.example.com」でウェブサイトにアクセスしてブラウザに鍵のマークがついていればTLSで保護されています。

TomcatのServletでクライアントIPを取得すると 127.0.0.1 になる現象

TomcatのServletでクライアントIPを取得するために HttpServletRequest の getRemoteAddr() メソッドを使っているのですが、取得するIPがいつも 127.0.0.1 となってしまうので調べてみました。環境は以下の構成です。NginxとTomcatは相乗りです。

ServletでのクライアントIP取得のソースコードです。


//IPアドレスの取得
String ip = request.getHeader("X-FORWARDED-FOR");
if ( ip == null || "".equals(ip) )
	ip = request.getRemoteAddr();
if ( ip == null )
	ip = "0.0.0.0";

このロジックだと request.getRemoteAddr(); がいつも 127.0.0.1 になってしまいます。ループバックアドレスなので自身のIPアドレスとなっているようです。つまり、TomcatからみたクライアントはNginxとなっています。

これを解消するにはNginx側の設定ファイルに proxy_set_header ディレクティブの追加が必要だとわかりました。以下のようにします。


location / {
	 :
	proxy_set_header X-Forwarded-for $remote_addr;
	proxy_pass http://localhost:8080/test/;
	 :
}

Nginxはデフォルトでは X-Forwarded-For ヘッダを付けてくれないので、付加する設定がいるようです。Servlet側でも request.getHeader("X-FORWARDED-FOR"); の処理を入れておく必要があります。こうするとクライアントIPの取得ができました。

X-Forwarded-For ヘッダはプロキシサーバーを通過した際に、送信元IPアドレスを特定するために使われます。HTTPヘッダには以下のような形で付与されます。

X-Forwarded-For: <client>, <proxy1>, <proxy2>

リクエストが複数のプロキシサーバーを通過する場合、それぞれの通過するプロキシサーバーのIPアドレスが右側に付け足されていきます。つまり、左端のIPアドレスが元のクライアントのIPアドレスになります。

なお、1つ手前のプロキシサーバー(一番最後に経由したプロキシサーバー)のIPアドレスは X-Forwarded-For ヘッダには記載されないので そのIPアドレスを取得するには request.getRemoteAddr() メソッドで取得します。