Apache Tomcatは、JavaのWebアプリケーションを受け取ったHTTPリクエストに応じて実行する、オープンソースのサーブレットコンテナです。Jakarta EE(旧Java EE)の仕様群のうち、ServletやJSPなどWebに関わる部分だけを実装しています。この記事では、Catalina・Coyote・Jasperの3部品とserver.xmlの構造、2026年10月時点の11.0・10.1・9.0系とJava要件の対応、Docker公式イメージでサーブレットを1本動かす手順を、公式ドキュメントに沿って整理しました。Apache HTTP Serverやnginxとの役割分担、Spring Bootの組み込みTomcatと外部Tomcatのどちらを選ぶかの判断まで扱います。
まとめ|TomcatはJavaのWebアプリ実行環境で新規構築なら11.0系を選ぶ
Tomcatは、Javaで書いたWebアプリケーションを動かすための土台です。HTTPの受け付け、サーブレットの呼び出し、JSPのコンパイルまでを1つのプロセスで担い、単体でもWebサーバーとして応答できます。EJBやJMSのようなエンタープライズ機能は持たず、その分だけ軽い。
版の選び方は明快です。新規構築なら11.0系(Java 17以降)、Jakarta EE 10前提のフレームワークに合わせるなら10.1系を使います。9.0系はjavax.*のパッケージ名を使う旧来のアプリを動かすための系列で、2027年3月31日以降に終了する見込みです。
Spring Bootで新しく作るなら、Tomcatを別途インストールする必要はありません。実行可能jarに組み込まれたTomcatがそのまま動きます。
Tomcatの定義とJakarta EEの一部だけを実装するサーブレットコンテナの位置づけ
Apache Software Foundation製OSSのWeb実行環境としての役割
TomcatはApache Software Foundationが開発し、Apache License 2.0で配布されています。公式の版一覧ページは、TomcatをJakarta EEの技術の一部を実装したソフトウェアと説明しています。実装している仕様は、Servlet、Pages(旧JSP)、Expression Language、WebSocket、Authentication、Annotationsの各仕様です。
サーブレットは、HTTPリクエストを受け取って応答を返すJavaクラスです。開発者はdoGetやdoPostの中身だけを書き、ソケットの管理やスレッドの割り当て、URLとクラスの対応付けはTomcatが受け持ちます。この「器」の役割を指して、サーブレットコンテナと呼びます。
WildFlyやWebLogicのようなフル機能のアプリケーションサーバーとの違い
Jakarta EEの全仕様を実装した製品は、アプリケーションサーバーと呼ばれます。WildFly、WebLogic、Payara Serverなどがこれに当たり、トランザクション管理(JTA)やメッセージング(JMS)、EJBまで含みます。Tomcatはこれらを持ちません。
実務で違いが出るのは、アプリで使うライブラリを誰が用意するかという点です。アプリケーションサーバーが提供する機能をTomcatで使いたい場合は、アプリ側にライブラリを同梱します。Spring FrameworkのDIとトランザクション管理はアプリ側のライブラリとして動くため、Springで作るアプリならTomcatで足ります。
Catalina・Coyote・Jasperと設定ファイルで見る内部構造
Coyote・Catalina・Jasperによる受付・実行・JSP変換の分担
Tomcatの内部は、役割の異なる3つの部品に分かれています。公式の版一覧によると、Catalinaは4.0で全面的に作り直されたサーブレットコンテナ本体で、Coyoteは4.1で加わったHTTP/1.1とAJPのコネクタ、Jasperは同じく4.1で書き直されたJSPのコンパイラです。
- Coyote:TCPの接続を受け、HTTPを解析してリクエストのオブジェクトを作る
- Catalina:URLから担当のWebアプリとサーブレットを選び、フィルタを通して呼び出す
- Jasper:JSPファイルをJavaのサーブレットに変換してコンパイルする
障害の切り分けで手がかりとなるのは、各部品が担当する処理の区分です。接続数やタイムアウトの問題はCoyote側の設定、404や認証の問題はCatalina側のWebアプリ設定、JSPの初回表示が遅い問題はJasperのコンパイルを疑う、という順で見ていきます。Jasperの解説によると、Tomcat 11.0のJasper 2はJakarta Pages 4.0を実装しています。
server.xmlで見るサーバー全体からWebアプリまでの入れ子と設定例
設定の中心はconf/server.xmlです。公式のアーキテクチャ解説では、Serverがコンテナ全体、Serviceが1つ以上のConnectorと1つのEngineを束ねる単位、Hostがホスト名、Contextが1つのWebアプリを表します。同梱のserver.xmlから主要部分を抜き出すと、次の入れ子になります。
<Server port="8005" shutdown="SHUTDOWN">
<Service name="Catalina">
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
<Engine name="Catalina" defaultHost="localhost">
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true" />
</Engine>
</Service>
</Server>
HostのappBase="webapps"は、webappsディレクトリに置いたWARやディレクトリをWebアプリとして読み込む指定です。webapps/helloを置けば/helloというContextが自動で作られます。Contextをserver.xmlへ直接書く方法もありますが、設定変更のたびにTomcatの再起動が要るため、Webアプリの単位で設定を分けるほうが運用は楽です。
HTTPコネクタの処理スレッド数と接続数を定める既定値の読み方
性能の相談で最初に確認するのが、HTTPコネクタの数値です。処理スレッド数はmaxThreads 200、接続数はmaxConnections 8192を基準に、両者の上限を区別して読みます。HTTPコネクタの設定リファレンスに記載された既定値を整理しました。
| 属性 | 既定値 | 意味 |
|---|---|---|
| maxThreads | 200 | 同時に処理できるリクエスト数の上限 |
| maxConnections | 8192 | 受け付けて保持する接続数の上限 |
| acceptCount | 100 | 上限到達後にOSが待たせる接続の数 |
| connectionTimeout | 60000ミリ秒 | 同梱のserver.xmlでは20000ミリ秒 |
| useVirtualThreads | false | 内部の実行スレッドに仮想スレッドを使うか |
リクエストは、処理スレッドが200本埋まるとmaxConnectionsの枠内で待たされ、それも超えるとOSの待ち行列(acceptCount)に積まれます。その待ち行列があふれた時点で、接続が拒否されるかタイムアウトします。応答が遅いときにmaxThreadsだけを増やすのは逆効果になりがちです。遅い原因がデータベースの待ちなら、スレッドを増やすほど接続プールの取り合いが激しくなります。
Servlet仕様とJava要件で選ぶTomcat 11.0・10.1・9.0
2026年10月時点の現行3系列とServlet仕様・Java要件の対応表
公式の版一覧ページによると、2026年10月22日時点でサポートされている系列は3つです。
| 系列 | 最新版 | Servlet | 対応するプラットフォーム | 必要なJava |
|---|---|---|---|---|
| 11.0.x | 11.0.27 | 6.1 | Jakarta EE 11 | 17以降 |
| 10.1.x | 10.1.61 | 6.0 | Jakarta EE 10 | 11以降 |
| 9.0.x | 9.0.123 | 4.0 | Java EE 8 | 8以降 |
11.0系は現在の開発の中心で、Jakarta Servlet 6.1を実装しています。8.5系は2024年3月31日、10.0系は2022年10月31日にサポートを終えました。これらの系列で動いているシステムは、修正版が出ない状態にあります。系列ごとの終了日と現行の修正版はTomcatのバージョン一覧とサポート期限にまとめています。
javaxからjakartaへのパッケージ名変更で9.0から上げられない典型例
9.0系と10.0系以降の間には、互換性の断層があります。Java EEがEclipse財団へ移管されてJakarta EEになった際、APIのパッケージ名がjavax.servletからjakarta.servletへ変わったためです。9.0系向けにビルドしたWARを11.0系へそのまま置いても、クラスが見つからずに起動しません。
詰まりやすいのは、アプリ本体よりも依存ライブラリです。自社コードのimportを書き換えても、古い帳票ライブラリや認証ライブラリがjavaxのままだと動きません。移行は、依存ライブラリのjakarta対応版の有無を先に棚卸しし、無いものの置き換え先を決めてから着手します。JDKとSpringの版上げを含めた進め方はJavaマイグレーションの手順とJakarta移行で整理しています。
9.0系のサポート終了予定と脆弱性の公表時に修正版を当てる運用
公式の版一覧によると、9.0系はJava EEに対応する最後の系列のため、通常の10年より長く支援される予定です。2026年2月11日の公式告知で、9.0系のサポート終了は2027年3月31日に決まりました。終了後は9.1系が延長サポートを引き継ぎ、2030年12月31日までリリースが続く予定です。
どの系列を使っていても、修正版を当て続ける運用が前提です。11.0系のセキュリティ情報では、2026年10月20日に、AJPの応答が次のリクエストへ混入する問題(CVE-2026-103119)などを11.0.27で修正したと公表されました。系列ごとの影響範囲と対応手順は、Apache Tomcatの脆弱性一覧と影響確認の手順にまとめています。
Docker公式イメージでTomcat 11を起動しサーブレットを1本動かす手順
tomcat:11.0-jdk21イメージの起動とwebappsが空で404が返る理由
手元で動きを確かめる最短の方法は、Docker公式イメージです。Docker Hubには11.0-jdk21や11.0.27-jre21のように、Tomcatの系列とJavaの版を組み合わせたタグが並んでいます。
起動してブラウザで開くと、404が返ります。これは故障ではありません。公式イメージの説明によると、上流のセキュリティ上の推奨に従い、Tomcatに同梱のサンプルアプリは既定で有効にしておらず、webapps.distへ退避しています。本番のイメージでも、管理画面やサンプルをwebappsへ戻さないのが基本です。
アノテーションだけで動くHelloServletのコンパイルと配置の実行例
web.xmlを書かずに、@WebServletのアノテーションだけでURLを割り当てる最小のサーブレットです。src/HelloServlet.javaとして保存します。
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
resp.setContentType("text/plain; charset=UTF-8");
// getServerInfo() はコンテナ名と版を返す
resp.getWriter().println("Hello from " + req.getServletContext().getServerInfo());
}
}
コンパイルには、JDK入りのイメージに同梱されたjavacとservlet-api.jarを使います。ローカルにJDKが無くても試せます。
mkdir -p src app/WEB-INF/classes
# src/HelloServlet.java を置いたうえでコンパイルする
docker run --rm -v "$PWD":/work -w /work tomcat:11.0-jdk21 \
javac -cp /usr/local/tomcat/lib/servlet-api.jar -d app/WEB-INF/classes src/HelloServlet.java
# app ディレクトリを webapps/hello としてマウントし、8888番で公開する
docker run --rm -p 8888:8080 -v "$PWD/app":/usr/local/tomcat/webapps/hello tomcat:11.0-jdk21
# 別の端末から呼ぶ。「Hello from Apache Tomcat/11.0.x」の形で返る
curl http://localhost:8888/hello/hello
URLの1つ目のhelloはContext(ディレクトリ名)、2つ目は@WebServletで指定したパスです。ソースファイルをappの外に置いているのは、Webアプリのディレクトリに入れると静的ファイルとして配信されかねないためです。javax.servletをimportしたコードは、この11.0のイメージではコンパイルに失敗します。前章の名前空間の違いを手元で確かめるには、これが手っ取り早い。
CATALINA_HOMEとCATALINA_BASEを分けて本体と設定を切り離す運用
サーバーへ直接インストールする場合は、公式のRUNNING.txtが勧める2つのディレクトリの分離を最初に決めます。CATALINA_HOMEは配布物そのもの、CATALINA_BASEはconf・webapps・logsなどの稼働中の設定と状態を置く場所です。分けておけば、版上げはCATALINA_HOMEを差し替えるだけで済みます。
# $CATALINA_BASE/bin/setenv.sh(既定では存在しないので新規作成する)
JAVA_HOME=/usr/lib/jvm/temurin-21-jdk
CATALINA_OPTS="-Xms1g -Xmx1g"
CATALINA_PID="$CATALINA_BASE/temp/tomcat.pid"
RUNNING.txtは、メモリの上限をJAVA_OPTSではなくCATALINA_OPTSに書くよう明記しています。JAVA_OPTSは停止用のプロセスにも適用されるためです。ヒープの大きさを決める前提はJVMのメモリ構成で解説しています。JAVA_HOMEのパスは環境に合わせて読み替えてください。
Apache HTTP Serverやnginxとの役割分担とリバースプロキシ構成の組み方
静的配信とTLS終端を前段に置きTomcatは動的処理に絞る構成の判断
Tomcatは単体でもHTTPSで応答できますが、本番では前段にApache HTTP Serverやnginxを置く構成が多数派です。前段がTLSの終端、静的ファイルの配信、アクセス制限、複数台のTomcatへの振り分けを受け持ち、Tomcatはサーブレットの実行に専念します。
前段を省いてよいのは、ロードバランサーがTLSを終端するクラウド構成や、コンテナで1アプリ1プロセスを動かす構成です。そこへ別のWebサーバーを挟むと、ログと設定の置き場所が増えるだけになります。前段にnginxを置く場合の版の確認と更新はnginxの最新バージョンと更新手順を参照してください。
mod_proxy転送時にホスト名とポートを前段に揃える設定例
公式のプロキシ設定ガイドは、Apache HTTP Serverのmod_proxyでTomcatへ転送する設定を示しています。前段側のhttpd.confと、Tomcat側のConnectorを対で設定します。
# httpd.conf(Apache HTTP Server側)
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
ProxyPass /myapp http://localhost:8081/myapp
ProxyPassReverse /myapp http://localhost:8081/myapp
# server.xml(Tomcat側):アプリから見えるホスト名とポートを前段に合わせる
<Connector port="8081" protocol="HTTP/1.1"
proxyName="www.example.com" proxyPort="443" scheme="https" secure="true" />
proxyNameとproxyPortを書かないと、request.getServerName()などがlocalhost:8081を返します。その結果、アプリが組み立てるリダイレクト先のURLが内部のポートを指してしまう。同ガイドによると、この方式では静的ファイルもすべてTomcatが処理するため、静的ファイルは前段のAliasなどで直接配信するよう分けると負荷が下がります。
AJPコネクタで前段サーバーと接続する構成を新規で選ばない理由
Apache HTTP Serverとの接続には、HTTPのほかにAJPという専用のバイナリプロトコルもあります。mod_jkやmod_proxy_ajpで使われてきた方式です。
新規の構成では、HTTPでの転送を選びます。AJPは前段のサーバーからの通信を信用する前提の仕組みです。2026年10月に公表されたCVE-2026-103119もAJPの応答処理の不具合でした。既存環境でAJPを使い続ける場合は、AJPのポートを前段のサーバーからしか届かないようにファイアウォールで閉じ、修正版の適用を優先してください。
Spring Bootの組み込みTomcatと外部Tomcatへのデプロイを選ぶ判断基準
実行可能jarに同梱される組み込み版とWARを置く従来型の運用の差
Spring BootでWebアプリを作ると、Tomcatはライブラリとしてjarの中に同梱されるのが既定の構成です。java -jar app.jarで起動した時点でTomcatも立ち上がり、ポートやスレッド数はapplication.propertiesのserver.*で設定します。最小のWeb APIの作り方はSpring Bootの解説で扱っています。
| 観点 | 組み込みTomcat | 外部Tomcat |
|---|---|---|
| 配布物 | 実行可能jar1つ | WARをwebappsへ配置 |
| Tomcatの版の決まり方 | アプリの依存管理 | サーバー側のインストール |
| 1プロセスのアプリ数 | 1つ | 複数を同居できる |
| 脆弱性の修正 | アプリを再ビルドして配布 | サーバー側で一括更新 |
脆弱性への対応の流れが逆になる点に注意してください。組み込み版はアプリごとにTomcatの版を持つため、修正版が出たら全アプリを再ビルドします。外部Tomcatはサーバーを更新すれば済む一方、同居する全アプリで動作確認が要ります。
外部Tomcatを選ぶべき運用条件と新規Webアプリ開発で採用を見送る場面
判断を言い切ります。新規のWebアプリを1つ作るなら、外部Tomcatは採用しません。コンテナやクラウドへの配置は実行可能jarのほうが単純で、Tomcatの版もアプリと一緒にソース管理できます。外部Tomcatのサーバーを別に保守する手間に見合う利点がありません。
外部Tomcatを選ぶのは、次の条件のどれかに当てはまる場合です。すでに複数のWARを1台のTomcatに載せて運用している。運用部門がTomcatの設定と版上げを一元管理する体制になっている。製品として配布するWARを、顧客の既存Tomcatへ載せる必要がある。どれにも当てはまらないのに外部Tomcatを残すと、アプリの改修とサーバーの版上げの担当が分かれ、修正版の適用が遅れる原因になります。
既存のTomcat資産を保守し移行するときの受託開発での切り分け
9.0系以前のTomcatで動く業務システムの扱いは、3つに分かれます。9.0系の最新版で延命する、11.0系へ上げてjakartaへ移行する、Spring Bootの実行可能jarへ作り直す。
延命は2027年3月以降も9.1系で続けられますが、依存ライブラリのjavax版が保守されなくなる時点で行き詰まります。画面や業務ロジックにも手を入れる予定があるなら、移行と作り直しを同じ計画で見積もるほうが総額は下がる。当社では、既存のJava資産の調査から移行、作り直しまでをフルスクラッチ開発として請けています。
よくある質問
Tomcatの基本と導入でよく寄せられる質問をまとめました。
Tomcatは無料で商用利用できますか?
できます。TomcatはApache License 2.0で配布されており、商用のシステムに組み込んで使っても利用料はかかりません。ライセンスと著作権の表示を残すなどの条件はあります。公式のサポート窓口は無く、問い合わせはメーリングリストが中心になるため、障害対応の体制が必要なら、OSSの保守サービスを提供する事業者との契約を検討します。
TomcatとApache HTTP Serverの違いは何ですか?
Apache HTTP Serverは、HTMLや画像などのファイルを配信し、リバースプロキシとして他のサーバーへ転送するWebサーバーです。TomcatはJavaのサーブレットやJSPを実行するサーブレットコンテナで、HTTPの受け付け機能も持っています。名前は似ていますが別のソフトウェアで、本番では前段にApache HTTP Server、後段にTomcatを置いて役割を分ける構成がよく使われます。
Tomcatのバージョンはどれを選べばよいですか?
2026年10月時点では、新規構築なら11.0系を選びます。Java 17以降が必要で、Jakarta EE 11に対応しています。使うフレームワークがJakarta EE 10までしか対応していない場合は10.1系、javaxのパッケージ名を使う既存アプリを動かす場合は9.0系です。8.5系以前はサポートが終了しているため、使い続けている場合は版上げを計画してください。
Tomcatが起動しているかはどう確認しますか?
既定の設定なら、ブラウザでhttp://localhost:8080/を開いて応答があるかを見ます。Docker公式イメージはサンプルアプリを外しているため、起動していても404になります。この場合はlogs/catalina.outやコンテナのログで「Server startup」の行を確認するほうが確実です。版はbin/version.shで表示できます。
TomcatはJava以外の言語でも使えますか?
Tomcatが実行するのは、JVM上で動くサーブレットです。KotlinやScalaなどJVM向けの言語で書いたサーブレットは動きますが、PHPやPythonのアプリを直接動かす用途には向きません。そうした言語のアプリと共存させたいときは、前段のWebサーバーでURLごとに転送先を分け、TomcatにはSpring FrameworkなどJavaのアプリだけを載せます。
関連記事
- Apache Tomcatの脆弱性一覧【2026年10月】最新版11.0.27・10.1.61・9.0.123とCVE-2026-59083ほかの影響確認・対応手順:系列ごとの影響範囲と修正版の当て方
- Spring Bootとは|4.1系の依存名の変更と最小Web APIの作り方:組み込みTomcatで動くアプリの作り方
- Spring Bootバージョン一覧とサポート期限(EOL)【2026年10月】最新版は4.1、4.0の無償サポートは12月末終了:組み込みTomcatの版を決めるSpring Bootの系列
- Javaマイグレーションの進め方|JDK 8→21/25の手順とSpring Boot・Jakarta移行:Tomcat 9から11へ上げる前のJDKとjakarta移行
- JSF(Jakarta Faces)とは?仕組み・使い方と最新版4.1をTomcat 11で動かす手順:Tomcat 11上でJakarta EEの画面技術を動かす例