Technical deep dive
JBoss / WildFly DDoS Hardening: Undertow Listener Limits and IO Threads
Last updated: August 2026 · Undertow listener limits, IO threads and the front layer · Reading time ~16 min

On JBoss EAP and WildFly the DDoS surface is Undertow, not a Tomcat connector. The load-bearing attributes are max-connections, the request timeouts and the IO/worker thread split, set through the management CLI. Undertow is non-blocking, so a slow connection costs a buffer, not a worker — but like Tomcat, the application server belongs behind a hardened front layer, not on the open internet.
This guide hardens JBoss EAP and WildFly themselves against the connection- and thread-exhausting part of a DDoS attack. The important first distinction: on a modern EAP or WildFly, the web server is Undertow, not the old JBossWeb connector, and everything is configured on the Undertow subsystem through the management CLI. If you are still on JBoss AS 5/6 with JBossWeb, the Tomcat guide is closer to your configuration — and the larger point is that an end-of-life server is its own exposure.
As with Tomcat, JBoss is an application server and belongs behind a hardened front layer. The
Undertow limits below are the second line, applied behind that layer. Every attribute comes
with its jboss-cli.sh command and the counter that shows it working.
| Appliance | Attack shape | Undertow attribute | CLI path |
|---|---|---|---|
| Slow-header / slow-body | no-request-timeout, request-parse-timeout | /subsystem=undertow/server=*/http-listener=* | |
| Connection flood | max-connections; tcp-backlog | http-listener + socket-binding | |
| Thread / IO exhaustion | io-threads, task-max-threads (worker) | /subsystem=io/worker=default | |
| Large-request abuse | max-header-size, max-parameters, max-post-size | /subsystem=undertow/server=*/http-listener=* | |
| Direct exposure | Bind the listener internally; front layer terminates | socket-binding interface |
Like Tomcat, JBoss is an application server: the standard design puts a hardened front layer in front, and these Undertow limits are the second line behind it. None of it helps once the attack fills the circuit.
0. Baseline first: read the listener and worker metrics
Undertow and the IO subsystem expose runtime metrics through the CLI. Enable statistics and read them over a normal week:
# Turn on Undertow statistics
/subsystem=undertow:write-attribute(name=statistics-enabled,value=true)
# Active connections and processing on the HTTP listener
/subsystem=undertow/server=default-server/http-listener=default:read-resource(include-runtime=true)
# Worker pool: busy vs core/max task threads
/subsystem=io/worker=default:read-resource(include-runtime=true)
The listener’s active connection count and the worker’s busy-thread count are the baselines every value below is set against.
1. The front layer comes first
Confirm Undertow is not directly exposed on a public interface:
# The http socket-binding should be on an internal interface, not a public one
/socket-binding-group=standard-sockets/socket-binding=http:read-resource(include-runtime=true)
ss -ltnp | grep 8080
If it is public, bind it internally and let a hardened front layer terminate the internet connection — the nginx or Apache guides cover that layer. The front layer carries TLS, rate limiting and slow-connection eviction better than an application server should have to.
2. Listener connection and timeout limits
The http-listener carries the connection ceiling and the two timeouts that answer slow-request attacks. Set them through the CLI:
# Cap concurrent connections on the listener
/subsystem=undertow/server=default-server/http-listener=default:write-attribute(name=max-connections,value=8192)
# Slowloris: time allowed to parse request headers
/subsystem=undertow/server=default-server/http-listener=default:write-attribute(name=request-parse-timeout,value=30000)
# Idle connection with no request sent
/subsystem=undertow/server=default-server/http-listener=default:write-attribute(name=no-request-timeout,value=30000)
# Apply with a reload, not a restart
reload
Neither timeout is set by default, so on any exposed listener both must be configured explicitly.
request-parse-timeout catches the client dribbling headers; no-request-timeout catches the one
that opens a connection and sends nothing.
3. The IO / worker thread split
Undertow separates the non-blocking IO threads from the blocking worker pool. Size them independently and do not confuse them:
# IO threads run the event loop — size to cores (a common rule is cores, or cores*2)
/subsystem=io/worker=default:write-attribute(name=io-threads,value=8)
# Worker pool handles blocking work (servlets) — size to what heap/app support
/subsystem=io/worker=default:write-attribute(name=task-max-threads,value=128)
reload
Inflating io-threads does nothing for a bottleneck in blocking work, and inflating
task-max-threads beyond what the heap supports trades one failure for an out-of-memory failure. A
slow connection is handled by the IO threads as a buffer, which is why Undertow resists Slowloris by
design — the timeouts above turn that near-immunity into eviction.
4. Request-size limits
Close the oversized-request surface on the listener:
/subsystem=undertow/server=default-server/http-listener=default:write-attribute(name=max-header-size,value=8192)
/subsystem=undertow/server=default-server/http-listener=default:write-attribute(name=max-parameters,value=1000)
/subsystem=undertow/server=default-server/http-listener=default:write-attribute(name=max-headers,value=100)
/subsystem=undertow/server=default-server/http-listener=default:write-attribute(name=max-cookies,value=50)
/subsystem=undertow/server=default-server/http-listener=default:write-attribute(name=max-post-size,value=10485760)
reload
max-parameters and max-headers matter beyond memory: an unbounded count is a cheap way to burn
CPU in parsing and, historically, to trigger hash-collision attacks. The defaults are generous;
tightening them on an exposed listener costs nothing legitimate.
5. The TCP backlog
The socket-binding backlog is the OS-level queue of connections waiting to be accepted — the Undertow equivalent of Tomcat’s acceptCount:
/socket-binding-group=standard-sockets/socket-binding=http:write-attribute(name=backlog,value=200)
reload
Keep it a short backlog, not a large one; a large backlog only delays the refusal that protects the worker pool.
6. Client IP behind the front layer
With a front layer, the proxy-address-handler must be enabled or every log entry and address rule records the front layer, not the client:
# Enable the forwarded-for handling on the listener
/subsystem=undertow/server=default-server/http-listener=default:write-attribute(name=proxy-address-forwarding,value=true)
reload
Without it, every request is attributed to the front layer — the recurring proxy-IP failure across this series.
The signals to wire into monitoring
# 1. Active connections on the listener (read-resource include-runtime) vs max-connections
# 2. Worker busy threads vs task-max-threads (/subsystem=io/worker=default)
# 3. Request-parse-timeout and no-request-timeout counts (listener runtime stats)
# 4. Error/processing counts from the listener statistics
/subsystem=undertow/server=default-server/http-listener=default:read-resource(include-runtime=true,recursive=true)
Active connections at max-connections with the worker pool busy is the signature that the request
rate has outgrown what Undertow can absorb — the point where the front layer or an upstream tier has
to take the excess.
The honest limit of JBoss hardening
Everything here defends the application tier, behind a front layer that should catch most of it first. Two cases sit outside it.
The first is circuit saturation: volume that fills the pipe reaches neither the front layer nor Undertow.
The second is the OS layer beneath the servers, covered in the Linux and Windows guides. JBoss hardening assumes both the front layer and the OS layer are in place. Above the circuit, the answer is the network tier.
Order of application
- Confirm the listener is bound internally; put a hardened front layer in front.
- Enable Undertow statistics; record the baseline.
- Set max-connections and both request timeouts through the CLI.
- Size io-threads to cores and task-max-threads to the heap.
- Enable proxy-address-forwarding so logs and rules see the real client.
- Set the request-size limits and a short backlog.
- Wire the runtime metrics into monitoring.
Step 1 is, again, the one that most changes the outcome. The Undertow limits are the second line, and a second line is only as useful as the first line it stands behind.
Frequently asked questions
- Is JBoss AS's old connector the same as WildFly's Undertow?
- No, and the distinction decides which settings apply. Old JBoss AS (5/6) used JBossWeb, a Tomcat derivative with a connector; JBoss EAP 7+ and WildFly replaced it with Undertow, a non-blocking web server built on XNIO. If you are on a modern EAP or WildFly, everything is configured on the Undertow subsystem through the management CLI, not on a Tomcat-style connector. If you are still on JBossWeb, the Tomcat hardening guide is closer to your reality, and the more valuable move is upgrading off an end-of-life server.
- How is Undertow's threading different from Tomcat's, for DDoS?
- Undertow separates IO threads from worker threads. A small pool of IO threads runs the non-blocking event loop and never blocks; the worker pool handles requests that block, such as servlet calls. A slow connection is handled by the IO threads as a buffer, not by tying up a worker, which is why Undertow resists slow-connection attacks by design. The practical tuning is to size io-threads to the cores and task-max-threads (the worker pool) to what the application and heap support, and not to confuse the two — inflating IO threads does nothing for a blocking-work bottleneck and vice versa.
- Which timeout stops a slow-request attack on Undertow?
- Two work together: request-parse-timeout caps how long Undertow will spend parsing the request headers, and no-request-timeout caps how long an idle connection stays open without sending a request. A Slowloris client that opens a connection and dribbles headers is caught by request-parse-timeout; one that opens and sends nothing is caught by no-request-timeout. Neither is set by default, so on an exposed listener both should be configured explicitly, in the low tens of seconds.
- Do I set these in standalone.xml or through the CLI?
- Through the CLI, and let it write the configuration. Editing standalone.xml by hand works but is error-prone and is lost if the server is managed by a domain controller or an operator like on OpenShift. The jboss-cli.sh commands in this guide are idempotent, validate the attribute names, and apply to a running server with a reload rather than a restart. Hand-editing XML is the JBoss equivalent of setting a Windows tunable in the registry when a supported cmdlet exists.
- Does JBoss still need a front layer if Undertow is hardened?
- Yes, for the same reasons Tomcat does. Undertow is capable and can face the internet more safely than a blocking connector, but the standard production design still terminates TLS, rate-limits and evicts slow connections at a dedicated front layer, and forwards clean requests to Undertow over a private network. The Undertow limits here are the second line behind that front layer — valuable because a front layer can be bypassed on the internal network or forward an attack it did not catch, but not a replacement for it.
- Do these settings stop a volumetric attack?
- No. If the attack fills the circuit in front of the servers, neither the front layer nor Undertow receives the requests and no attribute applies. Everything here defends against connection and thread exhaustion at the application tier. Volume above the circuit is a network-tier problem and is not solved in the Undertow subsystem.
Published: August 2026
This guide is updated as vendors release new models and pricing. How we compare vendors