はじめに

私がTomcat上に金融アプリケーションを構築したとき、Tomcatを直接インターネットに公開するのは良くないアイデアだとすぐに気づきました。最初はうまくいきましたが、脆弱で、セキュリティを確保するのが難しく、デプロイ中にスムーズに維持することがほぼ不可能でした。

最終的に、NginxをTomcatの前に配置し、NginxにTomcatが苦手なこと、特にSSLターミネーション、メンテナンスモード、静的ファイルのキャッシング、内部インフラの詳細を隠すことを担当させることに決めました。

この記事では、私が現在本番環境で使用している正確な設定を説明します。これは一般的なガイドではなく、私が展開した金融システムに特化して書かれており、実際の設定と各決定の背後にある理由を含んでいます。

なぜTomcatの前にNginxが必要だったのか

1. Tomcatが再起動中のクリーンなメンテナンスページ

金融システムでは、デプロイやメンテナンス中にTomcatを再起動する必要があることがよくあります。Tomcatがダウンしている場合、ユーザーにはサーバー情報を露出する生のTomcat 503ページを見せるべきではありません。

Nginxを使うことで、ユーザーはTomcatが完全にオフラインであっても、常にフレンドリーなメンテナンスページを見ることができます。Nginxは502または503のレスポンスをキャッチし、私が用意した静的HTMLページを提供します。

2. NginxでのSSLがはるかに簡単

Tomcat内でSSLを設定するのは不必要に複雑です。証明書をJavaキーストアに変換し、コネクタを管理し、複数のフォーマットに対処する必要があります。

Nginxでは、SSLはシンプルです。必要なのは2つのファイル、証明書と秘密鍵だけです。NginxがHTTPSをターミネートし、TomcatはlocalhostからプレーンHTTPだけを受け取ります。証明書の更新やデバッグも簡単です。

3. Tomcatが外部から完全に隠されている

セキュリティ上の理由から、Tomcatがそのポートやサーバー情報を公開ユーザーに露出させたくありません。Tomcatは127.0.0.1:8080でのみリッスンします。

誰かが私のサーバーをスキャンしようとしても、Tomcatが存在することを検出することはできません。

4. 金融承認のための大きなヘッダー

システム内のいくつかの承認操作は、ヘッダーやクエリ文字列に長い金融アプリケーションIDのリストを送信します。

これらの大きなヘッダーをサポートするために、Nginxを設定して大きなヘッダーバッファを許可しました。これがなければ、デフォルトのヘッダーサイズが小さすぎるため、一部のリクエストが失敗することがあります。

5. 大きなファイルのアップロード

ユーザーは契約書、請求書、スキャンした文書をアップロードします。私はNginxでクリーンなアップロードサイズ制限を設定し、大きなファイルはNginxの検証を通過しない限り、Tomcatに到達しないようにしています。

6. 静的コンテンツ(CSS、JS、アイコン)の高速化

Tomcatは静的ファイルを提供できますが、Nginxの方がはるかに速いです。私は静的アセットのキャッシングを有効にし、Nginxがそれらを直接提供するようにしました。

7. 長時間実行される操作のためのカスタムタイムアウト

金融システム内のいくつかのプロセスは、レポート生成やバッチ承認など、時間がかかります。

Nginxはプロキシタイムアウトを完全に制御できるため、ユーザーは予期しない504エラーを受け取ることがありません。

私が使用しているNginx HTTPS設定

このファイルは次の場所に保管しています:

/etc/nginx/sites-available/myapp_https

こちらが実際の設定です。記事用に簡略化されていますが、正確です。

server {
    listen 443 ssl;
    server_name finance.example.com;

    ssl_certificate     /opt/myapp/keystore/app.crt;
    ssl_certificate_key /opt/myapp/keystore/app.key;

    ssl_session_cache shared:SSL:1m;
    ssl_session_timeout 5m;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_protocols TLSv1.2;
    ssl_prefer_server_ciphers on;

    large_client_header_buffers 4 65k;
    client_max_body_size 100m;

    error_page 502 503 = @maintenance;
    error_page 404 = @errors;

    access_log /opt/myapp/nginx/logs/access.log;
    error_log  /opt/myapp/nginx/logs/error.log;

    location / {
        proxy_set_header Host                $host;
        proxy_set_header X-Forwarded-Host    $host;
        proxy_set_header X-Forwarded-Server  $host;
        proxy_set_header X-Forwarded-For     $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto   https;

        proxy_pass http://127.0.0.1:8080;

        proxy_buffering off;
        proxy_buffer_size 128k;
        proxy_buffers 100 128k;

        proxy_connect_timeout 180;
        proxy_send_timeout    180;
        proxy_read_timeout    180;
        send_timeout          180;

        location ~* \.(css|js|jpg|gif|ico)$ {
            proxy_cache cache;
            proxy_cache_key   $host$uri$is_args$args;
            proxy_cache_valid 200 301 302 30m;
            expires 30m;
            proxy_pass http://127.0.0.1:8080;
        }
    }

    location = / {
        return 301 /myapp/;
    }

    location @maintenance {
        root /opt/myapp/nginx/www;
        rewrite ^ /maintenance.html break;
    }

    location @errors {
        root /opt/myapp/nginx/www;
        rewrite ^ /404.html break;
    }
}

これがシステムのコアです。NginxはSSLを処理し、トラフィックをTomcatに転送し、Tomcatがオフラインのときにメンテナンスページを提供し、静的コンテンツをキャッシュし、内部ネットワークのレイアウトを保護します。

HTTPリダイレクト(ポート80)

すべてのHTTPトラフィックをHTTPSにリダイレクトするシンプルな設定を追加しました。

/etc/nginx/sites-available/myapp_http
server {
    listen 80;
    server_name finance.example.com;
    return 301 https://$host$request_uri;
}

フォルダ構造

Nginx関連のファイルは専用のアプリケーションフォルダ内に保管しています:

/opt/myapp/
    keystore/
    nginx/
        logs/
        www/

これにより、証明書、ログ、静的ページを簡単に管理できます。

セットアップを完了するためのTomcat設定

Tomcatのserver.xml内で、Tomcatをlocalhostにバインドして外部からアクセスできないようにしています。

<Connector port="8080"
           address="127.0.0.1"
           maxHttpHeaderSize="65536"
           protocol="HTTP/1.1"
           connectionTimeout="20000"
           maxThreads="150"/>

また、Tomcatが実際のクライアントIPとプロトコルを理解できるようにしています:

<Valve className="org.apache.catalina.valves.RemoteIpValve"
       remoteIpHeader="X-Forwarded-For"
       protocolHeader="X-Forwarded-Proto"
       protocolHeaderHttpsValue="https"/>

これにより、システムは正しいクライアントIPをログに記録し、HTTPSに対して正しく動作します。

このセットアップが金融システムにうまく機能する理由

NginxをTomcatの前に置くことで、システム全体がはるかにプロフェッショナルで安定した印象を与えています。デプロイや再起動中でも、ユーザーは典型的なTomcat 503ページに遭遇することはありません。その代わり、常にクリーンなメンテナンス画面が表示され、システムが裏で作業を行っているときでも信頼性があるように見えます。

NginxでのSSLの処理もすべてを簡素化します。証明書の管理、更新、デバッグが簡単になり、TomcatはもはやHTTPSを直接扱う必要がありません。もう一つの利点はセキュリティです。Tomcatはlocalhostでのみリッスンするため、外部トラフィックから完全に隠され、スキャンやプロービングの試みを排除します。

パフォーマンスも向上します。CSSやJavaScriptなどの静的ファイルは、Nginxがキャッシュできるため、より早く読み込まれ、アップロードはTomcatに到達する前にチェックされ、制限されます。私たちの金融操作の中には、大きなヘッダーや長時間実行されるアクションが含まれており、Nginxはバッファサイズやタイムアウトを完全に制御できるため、これらの操作がランダムなエラーなしにスムーズに実行されます。

Tomcatが一瞬オフラインになる場合でも、メンテナンスページのおかげでサイトは予測可能に応答します。これまでの数年間、このセットアップは非常に堅牢であることが証明されてきました。多くのリリースやインフラの変更を通じて、金融アプリケーションはほぼゼロダウンタイムを達成し、驚きのない本番トラフィックを処理し続けています。