サーバー設定#
server {
host = "" # 待ち受けるアドレス。空なら全部
port = 9000
max_request_size = 10485760 # リクエスト本文の上限(10MB)
max_header_size = 16384 # ヘッダ全体の上限(16KB)
idle_timeout_seconds = 60
trust_proxy = false # X-Forwarded-* を信じるか
compression = true # 応答を gzip で返すか
access_log = true # アクセスログを出すか([ログ](./log))
bot_access_log = true # ボットのアクセスログを分けるか
strict_routes = false # 一生呼ばれないルートを例外にするか(CI では true に)
shutdown_grace_seconds = 0 # 止め始めてから新規を断つまで(秒)
shutdown_timeout_seconds = 15 # 処理中を待つ上限(秒)
}
**書かなければ上の既定で動きます。**いま何が効いているかは起動ログに出ます。
jimble を起動しました: http://localhost:9000
サーバー設定: 待受=全部 / 本文上限=10485760byte / ヘッダ上限=16384byte / アイドル=60秒 / 圧縮=true / プロキシ信頼=false
ポート#
**ポートだけはシステムプロパティでも指定できます。**コンテナで「設定ファイルは触らずポートだけ変える」ためです。
java -Djimble.server.port=8080 -jar app.jar
優先順は -Djimble.server.port > server.port > 9000 です。
こつ
JimbleServer.start(app, 0) にすると空いているポートを自動で取ります。
テストはこれを使ってください(固定にすると、並べて走らせたときだけ落ちます)。
実際のポートは server.port() で取れます。
待ち受けるアドレス#
**空なら全部のアドレスで待ちます。**外から見えてはいけないものは絞ってください。
server { host = "127.0.0.1" }
こつ
手元で動かす MCP サーバーはこれが要ります(MCP)。 ファイアウォールに頼ると、設定を忘れたときに黙って公開されます。
上限#
| 上限 | 超えたら | |
|---|---|---|
| リクエスト本文 | server.max_request_size(10MB) |
413 |
| ヘッダ全体 | server.max_header_size(16KB) |
接続ごと切られる |
| 何もしない接続 | server.idle_timeout_seconds(60秒) |
閉じる |
アップロードにはこれとは別の上限があります(ファイルアップロード)。
注意
アップロードの合計上限(既定 50MB)より本文の上限(既定 10MB)のほうが小さいので、 大きいものを受けるなら両方を上げてください。
読み取り/書き込みのタイムアウトはありません。
プロキシの後ろに置く#
**既定では X-Forwarded-* を信じません。**信じるのは、前段のプロキシを必ず通ると分かってからです。
server { trust_proxy = true }
true にすると proxyAddress() が次の順で送信元を返します。
CF-Connecting-IPX-Real-IPX-Forwarded-Forの先頭- どれも無ければ接続元
落とし穴
trust_proxy を true にしても address() は変わりません。
address() は常にTCP の接続元(=ロードバランサ)です。
送信元で判断するところは proxyAddress() を使ってください。
落とし穴
ボット判定(isBotAccess())は address() を見ます。
プロキシの後ろでは、判定に使う IP がロードバランサのものになります。
落とし穴
scheme() も X-Forwarded-Proto を見ません。
TLS を前段で終端していると、アプリからは http に見えます。
リダイレクト先を組み立てるときに気をつけてください。
注意
直接叩ける状態で true にしないでください。
ヘッダは誰でも付けられるので、送信元をいくらでも偽れます。
信頼する upstream を IP で絞る仕組みはありません(真偽値1つです)。
圧縮#
server.compression(既定 true)で on / off します。
何を圧縮するかはサーバー(Helidon)が Accept-Encoding を見て決めます。
補足
**圧縮レベルや、種類ごとの除外はありません。**細かく制御したいときは前段でやってください。
ボットを弾く#
判定だけならアクセスログの分離で足ります(ログ)。弾くなら宣言します。
before(BotBlocker.forbidden()); // 403 を返す
before(BotBlocker.of(context -> context.response().redirect("/"))); // 好きに返す
補足
**既定の「弾く」動作は用意していません。**検索エンジンまで弾くと困るので、 何を返すかはアプリが決める形にしてあります。
無いもの#
| TLS / HTTPS | 前段(ロードバランサ・nginx)で終端してください |
| HTTP/2 | 依存に入れていません |
| ヘルスチェックのルート | jimble は用意しません(下の「止める」を参照) |
止める#
いきなり止めません。stop() はこの順に進みます。
- 「止め始めた」ことにする —
Shutdown.isStopping()が true になる。普通のリクエストはまだ受ける server.shutdown_grace_seconds待つ(既定 0)- 新しいリクエストを断つ(503)
- 処理中のものが終わるのを
server.shutdown_timeout_seconds(既定 15 秒)まで待つ - サーバーを止める
SIGTERM を受けたら自動で走ります(コンテナはこれを送って待ちます)。
ヘルスチェックを先に落とす#
jimble はヘルスチェックのルートを用意しません。こう書いてください。
get("/health_check", context ->
context.response().send(Shutdown.isStopping() ? 503 : 200));
こつ
ロードバランサがこの台を外すまでには時間がかかります。
その間に来たリクエストを 503 にすると、外から見たらエラーです。
だから 1 と 3 の間に猶予を置けるようにしてあります。
ヘルスチェックの間隔 × 失敗回数ぶん(例:2秒 × 3回 → shutdown_grace_seconds = 10)を入れてください。
注意
待ちきれなかったら、残ったまま止めます。
そのときは 処理中のリクエストが N 件残ったまま停止します が warn に出ます。
止まらないほうが困る(コンテナに強制終了される)ためです。
補足
自分で立てたスレッドも一緒に止めたいなら Shutdown.add(...) に預けてください
(実行モデル)。
jimble をプロキシにする#
逆に、jimble から別のサーバーへ流すこともできます。
install(() -> ReverseProxy.mount("/api", "http://backend:8080"));
X-Forwarded-For は既存の値に足します(上書きしません)。
タイムアウトは proxy.connect_timeout_ms(5秒)と proxy.request_timeout_ms(30秒)で、
転送に失敗したら 502 を返します。