Skip to content

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

An inner keep with its own bounded gate, standing behind an outer wall; even where the outer wall is breached, the keep meters its own admissions and holds a small calm core.

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.

Attack shapes and the Undertow attributes that answer them
ApplianceAttack shapeUndertow attributeCLI path
Slow-header / slow-bodyno-request-timeout, request-parse-timeout/subsystem=undertow/server=*/http-listener=*
Connection floodmax-connections; tcp-backloghttp-listener + socket-binding
Thread / IO exhaustionio-threads, task-max-threads (worker)/subsystem=io/worker=default
Large-request abusemax-header-size, max-parameters, max-post-size/subsystem=undertow/server=*/http-listener=*
Direct exposureBind the listener internally; front layer terminatessocket-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.

Where the on-premise layer stops being able to help Your 10 Gbps access circuit Circuit already saturated — upstream only On-premise appliance mitigates 2 Gbps 8 Gbps 25 Gbps 120 Gbps 1 Tbps+ Attack volume (log scale)
Below the circuit, the Undertow limits have a share; above it, no attribute means anything.

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

  1. Confirm the listener is bound internally; put a hardened front layer in front.
  2. Enable Undertow statistics; record the baseline.
  3. Set max-connections and both request timeouts through the CLI.
  4. Size io-threads to cores and task-max-threads to the heap.
  5. Enable proxy-address-forwarding so logs and rules see the real client.
  6. Set the request-size limits and a short backlog.
  7. 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