Web and application server standards — the piece you operate, not the one that distributes
Criteria verified as of August 2026. Re-verify on the web before committing to anything (§8).
Hard premise: the origin server is not "where the code gets copied". It is a process with a
concurrency model, limits and an attack surface of its own, and almost every
incident people attribute to the application is a badly set limit at this layer.
1. Scope and triggers
Applies to installing, sizing, hardening, patching and operating the server that serves the
request: Apache httpd, nginx and IIS as web servers; Tomcat, Jetty, WildFly/JBoss EAP,
WebLogic and WebSphere as application servers; PHP-FPM and the WSGI/ASGI servers as the
process that runs the code; and their limits, origin TLS, headers, static files and
logging.
Triggers: httpd.conf, apache2.conf, .htaccess, nginx.conf (server block),
applicationHost.config, web.config, appcmd, server.xml, context.xml, standalone.xml,
jboss-cli, config.xml/WLST, Liberty's server.xml, PHP-FPM's www.conf, mpm_event,
worker_connections, MaxRequestWorkers, pm.max_children, LimitNOFILE, "502 Bad Gateway",
"504 Gateway Timeout", "application pool", "recycling", javax → jakarta.
Not applicable: distribution already has an owner — load-balancing-standards owns the balancer and the
reverse proxy, its health checks, draining and edge TLS termination (here the
origin server serving behind it and the checks it exposes), caching-cdn-standards
the cache policy, the CDN and the headers that govern it, networking-standards and
firewall-policy-standards connectivity and filtering, dns-standards the records, and
cryptography-pki-standards the choice of algorithm, suite and the issuance of the certificate (here
only its installation, renewal and reload). The code running on top belongs to php-standards,
python-standards, jvm-spring-standards and dotnet-framework-legacy-standards — IIS is the
dependency of Microsoft legacy, which delegates to this skill for the server —, while
kubernetes-standards owns the deployment if the service runs in a container, cicd-standards and
iac-standards how the configuration reaches the machine, observability-standards metrics and
dashboards, sre-practice-standards the SLO, vulnerability-management-standards CVE triage,
appsec-standards the application vulnerability, identity-access-management-standards the
OIDC, privacy-engineering-standards personal data in the log and grc-compliance-standards
the evidence. The operating system underneath belongs to linux-administration-standards,
rhel-fedora-standards, linux-hardening-standards and windows-server-ad-standards; backups to
backup-recovery-standards, and onprem-standards is the umbrella (with homelab-standards as a test
bench). Its batch siblings: mail-servers-standards and file-servers-standards are another
service, not another configuration of the same one.
2. Default decisions
Verify the latest version on the web before pinning it in a real project (§8).
| Decision |
Recommended |
Justifiable alternative |
| Generic web server |
nginx stable branch (1.30.x; 1.30.0 opened on 14 Apr 2026, 1.30.4 with CVE-2026-42533 and CVE-2026-60005) for per-connection footprint |
Apache httpd 2.4.x (2.4.68, 8 Jun 2026) if you need per-tenant .htaccess, third-party modules or integration with the distribution's package |
| nginx branch |
stable in production; mainline (1.31.x, 1.31.3 of 15 Jul 2026) only if you need a specific feature |
mainline in environments where patch cadence matters more than interface stability |
| httpd 2.6 |
No: there is no GA; the development trunk runs as 2.5.x |
— |
| httpd 2.2 |
FORBIDDEN: EOL, last release 2.2.34 (Jul 2017) |
— |
| Apache MPM |
event with PHP-FPM or a proxy to the application |
prefork only if a module is not thread-safe (classic mod_php) — and that is the signal that you need to get off it |
| The nginx ecosystem after the forks (F5, freenginx, Angie) |
Already verified in load-balancing-standards: consult it there, it is not duplicated |
— |
| Server on Windows |
IIS 10.0 (the version shipped with Windows Server 2025, supported until 10 Oct 2034). There is no "Windows Server 2026": what ships in 2026 are cumulative updates |
nginx/httpd on Windows for development only |
| Servlet container |
Tomcat 11.0.x (Jakarta EE 11) for new code; 10.1.x (EE 10) if the stack is not there yet |
Jetty 12.1 when embedding or when you need the EE8/EE9/EE10/EE11 model in one binary |
| Tomcat 9.0.x |
Migrate: supported until 31 Mar 2027. There will be a 9.1.x branch (until 31 Dec 2030) but without APR/native connectors for HTTP, HTTPS and AJP: it is an extension, not a destination |
— |
| Jetty 9/10/11 |
FORBIDDEN: since 1 Jan 2026 they are no longer published to Maven Central; paid support only (Webtide, HeroDevs, TuxCare) |
— |
| Full Jakarta EE server |
WildFly 41.0.0.Final (16 Jul 2026, EE 11 since WildFly 40, 21 May 2026) if there is no contract |
JBoss EAP 8.1 with commercial support; WildFly EE 10 as a bridging variant if you cannot manage EE 11 yet |
| JBoss EAP 7.x |
Migrate to 8.1: EAP 7 maintenance ended on 30 Jun 2025; from then on only ELS (requires being on 7.4, renewable until Oct 2027) |
— |
| WebLogic |
14.1.2 (14c), certified with JDK 17 and 21. There is no "15c" |
Migrate to WildFly/EAP or to Liberty if the licence cost is not justified |
| WebSphere |
Liberty (single-stream SSCD model, delivery roughly every 4 weeks, with no end-of-support date; 26.0.0.5 added Jakarta EE 11 and Spring Boot 4.0) |
WAS traditional 9.0.5: IBM announces no end date, but the real pressure is the currency of the fix pack, of the Java and of the OS underneath |
| Running PHP |
PHP-FPM over a Unix socket, one pool and one user per application |
FrankenPHP/embedded server only with an explicit rationale |
| Running Python |
WSGI/ASGI behind the web server (gunicorn+uvicorn workers, or uvicorn/hypercorn) — never directly exposed |
— |
Jakarta EE and the namespace change: Jakarta EE 11 was released on 26 Jun 2025 (Core
Dec 2024, Web Profile Mar 2025), requires Java 17+, removes Managed Beans, the references to the
SecurityManager (JEP 411), SOAP with Attachments and XML Binding, and the optional
specifications. Jakarta EE 12 is not released and its dates contradict each other across sources (§8).
The javax.* → jakarta.* jump is binary and non-negotiable: it is the real cut between Tomcat 9 and
10+, and between EAP 7 and 8. It is not a sed: it affects transitive dependencies, descriptor
files and third-party bytecode; it is planned with the project's migration tool and
verified by running, not by compiling.
3. The process model: why the default sizing is almost always wrong
The default value is set by whoever packages it, without knowing your memory or your request
profile. A single rule: the number of workers is dictated by the resident memory of the worst
process and by the nature of the waiting, not by the number of cores.
- Apache:
prefork (one process per connection, expensive memory, safe with non-reentrant modules),
worker (a process/thread hybrid) and event (threads + asynchronous handling of idle and
keep-alive connections). With event, MaxRequestWorkers and ServerLimit × ThreadsPerChild must be
coherent or start-up silently trims them. With mod_php you are tied to prefork: that is
the technical reason to move to PHP-FPM, not a fashion.
- nginx:
worker_processes auto (one per core) and worker_connections as a ceiling per
worker that includes connections towards the upstream, not only the client's: the effective
limit is roughly half when proxying. worker_rlimit_nofile must be greater than
worker_connections, or the real limit will be file descriptors.
- IIS: the application pool is the failure and identity boundary (
ApplicationPoolIdentity
= a virtual account per pool). One pool per application, never shared between tenants. Periodic
clock-based recycling and idleTimeout are on by default: in an application
with an expensive start-up they are surprise latency and lost in-memory state — disable hourly
recycling, keep memory/request-based recycling, and use pre-warming (AlwaysRunning +
preloadEnabled). A web garden (maxProcesses > 1) breaks in-memory sessions: it is not a
performance button.
- PHP-FPM:
pm = dynamic with pm.max_children computed as memory available to the
pool / RSS of the worst process, and pm.max_requests to bound leaks. pm = static when the load
is stable and start-up latency matters; ondemand only in sparse multi-tenancy. A
short pm.max_children is the number one cause of intermittent 502s with nginx in front.
4. Validation and gates
- Nothing is reloaded without validation:
apachectl configtest / httpd -t, nginx -t,
appcmd list config or the web.config schema. In CI, validation runs against the
rendered configuration, not against the template.
- Reload, do not restart:
nginx -s reload, apachectl graceful, overlapped recycling in IIS.
A hard restart cuts in-flight requests; combined with balancer draining
(load-balancing-standards) the deployment should not lose a single one.
- Gates in order of cost: (1) syntax validation; (2) a configuration linter and diffs
against the reference; (3) an HTTP smoke test against the origin without going through the balancer;
(4) TLS and header verification (
testssl.sh, a header check) against the deployed
environment; (5) a load test that confirms the chosen sizing, not the default.
- The configuration is code: outside
iac-standards there are no manual changes in production. A
.htaccess edited hot is by definition an unversioned change.
5. Stack security
- An unprivileged user: the master process may need root for the low port (or
CAP_NET_BIND_SERVICE/AmbientCapabilities), the workers never. A Java application
server running as root is a design failure, not a pending adjustment.
- Directory listing disabled:
Options -Indexes, autoindex off, directory browsing
off in IIS. And the document root outside the code tree and .git.
- The version out of the headers:
ServerTokens Prod + ServerSignature Off,
server_tokens off, and in IIS remove Server, X-Powered-By and X-AspNet-Version. It is not
real security, but it is free reconnaissance for the attacker and a guaranteed audit finding.
- Unnecessary modules out: every loaded module is surface and is a CVE that forces you to
patch. Review
mod_status, mod_info, mod_userdir, mod_autoindex, WebDAV, CGI and third-party
modules. In IIS, remove the role features you do not use and enable request
filtering. In Tomcat/WildFly, delete the sample and documentation applications.
.htaccess is surface: AllowOverride None by default. Enabling it delegates configuration
to whoever can write in the directory — including a compromised file upload — and penalises
every request with filesystem lookups. It is enabled per directory and with an explicit list
of directives, never globally.
- The commercial products' admin console: Tomcat Manager/Host Manager, the WildFly console,
WebLogic's
/console and T3/IIOP, the WebSphere administrative console. Never on the Internet:
they listen on the management network or on loopback behind a tunnel, with their own credential and MFA
where it exists. Exposed T3/IIOP has a history of deserialisation RCE: if you do not use it,
disable it; if you do, filter it by network and apply the allowed class list.
- TLS: TLS 1.2 as the absolute minimum, 1.3 preferred; SSLv3/TLS 1.0/1.1 disabled. OCSP
stapling on, HSTS only once the whole domain is already on HTTPS (and
preload only with a
conscious decision: it is hard to reverse). The choice of suite and curve belongs to
cryptography-pki-standards.
- Automatic certificate renewal: ACME with an automatic reload afterwards, and expiry
monitoring independent of the agent that renews — the real failure is not that it expires, it is that the
agent renewed and nobody reloaded the service.
- Response headers that genuinely belong to the server:
Strict-Transport-Security,
X-Content-Type-Options: nosniff, Referrer-Policy, Content-Security-Policy and
Permissions-Policy. The CSP policy is defined by the application (appsec-standards); the
server emits it consistently and does not duplicate it — a header repeated by server and
application is undefined behaviour in practice. X-XSS-Protection is obsolete: do not
set it.
- Static files: served from the web server, not from the interpreter. Deny by
pattern whatever must never leave (
.git, .env, ~ copies, .bak, configuration files) and
disable interpreter execution in upload directories — an upload served as
code is RCE, and it is the most repeated mistake in the domain.
6. Limits, 502/504 and logging
- A 502/504 is, almost always, a badly set limit here, not an application failure. Before
touching code, check: backend worker exhaustion (
pm.max_children,
maxThreads, the accept queue), an upstream read timeout shorter than the request's real
duration, a header or body size above the buffer (proxy_buffer_size,
client_max_body_size, LimitRequestBody, maxAllowedContentLength), and exhausted descriptors.
- Four limits that are always set, with a justified number: maximum request and
header size; client and upstream timeouts coherent across layers (the balancer's
must be larger than the origin's, or you will see cuts with no trace); file descriptors
(
LimitNOFILE in the systemd unit, not in a script's ulimit); and a listen backlog
matching somaxconn.
- Logging: access and error separated, structured format (JSON) if it goes to a collector, and
rotation by the system tool with descriptor reopening — a rotation that only
renames leaves the process writing to an orphaned inode and fills the disk without anybody seeing it.
Reserve space: a disk full of logs takes the service down.
- What is not logged:
Authorization, Cookie, POST bodies, tokens in the query
string and passwords in the URL. The IP is personal data: bounded retention and anonymisation or
pseudonymisation as set by privacy-engineering-standards.
- Compression and static content:
gzip/brotli only over compressible types (compressing a JPEG or a
ZIP burns CPU for nothing), pre-compressed variants when the content is static, sendfile and
tcp_nopush on. Be careful compressing responses that mix a secret with user input
over TLS (the BREACH class). The cache policy and the CDN belong to caching-cdn-standards; here
only that the server knows how to emit ETag/Last-Modified and answer 304.
- Minimum metrics: requests per second and per status code, latency per percentile, busy workers
against the limit, active connections, the accept queue and upstream errors. Without
"busy workers / limit" you cannot tell saturation from slowness.
7. Sustainability and prohibitions
Cadence: a server security patch outside the window if the CVE is remotely exploitable;
a minor branch jump planned quarterly; a major branch jump (Tomcat 9→11, EAP 7→8) treated
as a project with a budget, because it drags the namespace change along. Every server
has an end-of-support date recorded in the inventory: without it, the migration always arrives
late.
- ❌ Serving with an out-of-support server or branch (httpd 2.2, Tomcat 8.5/10.0, Jetty 9/10/11,
EAP 7 without ELS) because "it works".
- ❌ Running workers as root, or the application server under the administrator's account.
- ❌ Leaving the default sizing in production without having computed memory per process.
- ❌ Exposing the admin console,
mod_status, /manager, /console or T3/IIOP to the Internet.
- ❌ Enabling
.htaccess globally, or letting the application's user write to the server's
configuration.
- ❌ Allowing interpreter execution in directories where users upload files.
- ❌ Terminating TLS with obsolete versions or suites, or with a manually renewed certificate.
- ❌ Renewing with ACME without an automatic reload and without independent expiry monitoring.
- ❌ Logging authentication headers, POST bodies or tokens in the query string.
- ❌ Rotating logs by renaming without a reopen signal, or leaving the log disk with no quota and no alert.
- ❌ Treating a 502/504 as an application bug without first reviewing workers, timeouts and buffers.
- ❌ Setting an origin timeout larger than the balancer's (or the other way round unknowingly): it produces
cuts with no trace in either of them.
- ❌ Changing configuration by hand in production and not returning it to the repository.
- ❌ Migrating
javax → jakarta with search and replace, without running the integration tests.
- ❌ Duplicating security headers between server and application expecting "the stricter one to win".
8. Mandatory web verification
- The stable version and open CVEs of httpd, nginx (stable branch versus mainline) and IIS/base
OS. Check the project's advisory, not the distribution's package.
- The support calendar for Tomcat (9.0.x/9.1.x dates), Jetty, WildFly, JBoss EAP,
WebLogic and WebSphere. They change and they are the fact that decides the migration.
- The status of Jakarta EE 12: not released as of Aug 2026. Declared discrepancy: InfoQ reported
a plan with GA in Jul 2026 while the project's page at
jakarta.ee marks it "Under
Development" targeting a final release in Q2-2027. Do not pin a date without rereading the project's
own source.
- Declared gap — WebLogic: the exact Premier/Extended Support date for 14.1.2 lives in
the Fusion Middleware Lifetime Support Policy document and in article KB65053 of My
Oracle Support, which requires a login and is not publicly verifiable. The public policy
confirms that Fusion Middleware 12c ends Premier in Dec 2026 and Extended in Dec 2027;
for 14c you have to consult MOS with an account. It is not filled in here.
- Declared gap — JBoss EAP 8.1: Red Hat publishes the policy (7 years: 4 of Full Support +
3 of Maintenance, plus optional ELS) but the concrete dates for 8.1 have to be taken from the
Product Life Cycles table on the portal at decision time.
- The state of the nginx ecosystem after the forks: not re-verified here, it is owned by
load-balancing-standards; if that skill is out of date, update it there.
- Security headers: check on MDN which are still current and which became obsolete
before copying a template from years ago.
- The OS version that pins the server's (IIS tied to Windows Server; httpd/nginx to the
distribution's branch) and its end-of-support date.
If the web contradicts this document, the web wins — flag the discrepancy.
1---2name: web-app-servers-standards3description: The web server and application server as a host you operate, harden and patch — not as the proxy that decides routing. Use when working with Apache httpd (httpd.conf, apache2.conf, sites-available, a2enmod, .htaccess, AllowOverride, mpm_prefork/mpm_worker/mpm_event, MaxRequestWorkers, ServerLimit, ThreadsPerChild, ServerTokens, mod_ssl, mod_status, mod_security, apachectl configtest), nginx as an origin server (nginx.conf server blocks, worker_processes, worker_connections, worker_rlimit_nofile, client_max_body_size, sendfile, gzip, autoindex, server_tokens, nginx -t), IIS (applicationHost.config, web.config, appcmd, IISAdministration and WebAdministration PowerShell modules, application pools, ApplicationPoolIdentity, recycling and idleTimeout, request filtering, http.sys, ASP.NET Core Module), a Java application server (Tomcat server.xml, context.xml, catalina.sh, CATALINA_OPTS, Manager and Host Manager apps, Jetty jetty.xml and start.d, WildFly standalone.xml and jboss-cli, WebLogic config.xml, WLST, T3/II4---56# Web and application server standards — the piece you operate, not the one that distributes78Criteria verified as of **August 2026**. Re-verify on the web before committing to anything (§8).910> **Hard premise**: the origin server is not "where the code gets copied". It is a process with a11> concurrency model, limits and an attack surface of its own, and **almost every12> incident people attribute to the application is a badly set limit at this layer**.1314## 1. Scope and triggers1516Applies to **installing, sizing, hardening, patching and operating** the server that serves the17request: Apache httpd, nginx and IIS as web servers; Tomcat, Jetty, WildFly/JBoss EAP,18WebLogic and WebSphere as application servers; PHP-FPM and the WSGI/ASGI servers as the19process that runs the code; and their limits, origin TLS, headers, static files and20logging.2122Triggers: `httpd.conf`, `apache2.conf`, `.htaccess`, `nginx.conf` (`server` block),23`applicationHost.config`, `web.config`, `appcmd`, `server.xml`, `context.xml`, `standalone.xml`,24`jboss-cli`, `config.xml`/WLST, Liberty's `server.xml`, PHP-FPM's `www.conf`, `mpm_event`,25`worker_connections`, `MaxRequestWorkers`, `pm.max_children`, `LimitNOFILE`, "502 Bad Gateway",26"504 Gateway Timeout", "application pool", "recycling", `javax` → `jakarta`.2728**Not applicable**: distribution already has an owner — **`load-balancing-standards` owns the balancer and the29reverse proxy, its health checks, draining and edge TLS termination** (here the30**origin server** serving behind it and the checks it *exposes*), **`caching-cdn-standards`31the cache policy, the CDN and the headers that govern it**, `networking-standards` and32`firewall-policy-standards` connectivity and filtering, `dns-standards` the records, and33`cryptography-pki-standards` **the choice of algorithm, suite and the issuance of the certificate** (here34only its installation, renewal and reload). The **code running on top** belongs to `php-standards`,35`python-standards`, `jvm-spring-standards` and `dotnet-framework-legacy-standards` — **IIS is the36dependency of Microsoft legacy, which delegates to this skill** for the server —, while37`kubernetes-standards` owns the deployment if the service runs in a container, `cicd-standards` and38`iac-standards` how the configuration reaches the machine, `observability-standards` metrics and39dashboards, `sre-practice-standards` the SLO, `vulnerability-management-standards` CVE triage,40`appsec-standards` the application vulnerability, `identity-access-management-standards` the41OIDC, `privacy-engineering-standards` personal data in the log and `grc-compliance-standards`42the evidence. The operating system underneath belongs to `linux-administration-standards`,43`rhel-fedora-standards`, `linux-hardening-standards` and `windows-server-ad-standards`; backups to44`backup-recovery-standards`, and `onprem-standards` is the umbrella (with `homelab-standards` as a test45bench). Its batch siblings: `mail-servers-standards` and `file-servers-standards` are **another46service, not another configuration of the same one**.4748## 2. Default decisions4950> Verify the latest version on the web before pinning it in a real project (§8).5152| Decision | Recommended | Justifiable alternative |53|---|---|---|54| Generic web server | **nginx** stable branch (`1.30.x`; `1.30.0` opened on 14 Apr 2026, `1.30.4` with CVE-2026-42533 and CVE-2026-60005) for per-connection footprint | **Apache httpd 2.4.x** (`2.4.68`, 8 Jun 2026) if you need per-tenant `.htaccess`, third-party modules or integration with the distribution's package |55| nginx branch | **stable** in production; *mainline* (`1.31.x`, `1.31.3` of 15 Jul 2026) only if you need a specific feature | *mainline* in environments where patch cadence matters more than interface stability |56| httpd 2.6 | **No**: there is no GA; the development trunk runs as 2.5.x | — |57| httpd 2.2 | **FORBIDDEN**: EOL, last release `2.2.34` (Jul 2017) | — |58| Apache MPM | **`event`** with PHP-FPM or a proxy to the application | `prefork` **only** if a module is not thread-safe (classic `mod_php`) — and that is the signal that you need to get off it |59| The nginx ecosystem after the forks (F5, freenginx, Angie) | **Already verified in `load-balancing-standards`**: consult it there, it is not duplicated | — |60| Server on Windows | **IIS 10.0** (the version shipped with Windows Server 2025, supported until 10 Oct 2034). **There is no "Windows Server 2026"**: what ships in 2026 are cumulative updates | nginx/httpd on Windows for development only |61| Servlet container | **Tomcat 11.0.x** (Jakarta EE 11) for new code; **10.1.x** (EE 10) if the stack is not there yet | **Jetty 12.1** when embedding or when you need the `EE8/EE9/EE10/EE11` model in one binary |62| Tomcat 9.0.x | **Migrate**: supported until **31 Mar 2027**. There will be a `9.1.x` branch (until **31 Dec 2030**) but **without APR/native connectors** for HTTP, HTTPS and AJP: it is an extension, not a destination | — |63| Jetty 9/10/11 | **FORBIDDEN**: since **1 Jan 2026 they are no longer published to Maven Central**; paid support only (Webtide, HeroDevs, TuxCare) | — |64| Full Jakarta EE server | **WildFly 41.0.0.Final** (16 Jul 2026, EE 11 since WildFly 40, 21 May 2026) if there is no contract | **JBoss EAP 8.1** with commercial support; **WildFly EE 10** as a bridging variant if you cannot manage EE 11 yet |65| JBoss EAP 7.x | **Migrate to 8.1**: EAP 7 maintenance ended on **30 Jun 2025**; from then on only **ELS** (requires being on 7.4, renewable until **Oct 2027**) | — |66| WebLogic | **14.1.2 (14c)**, certified with JDK 17 and 21. **There is no "15c"** | Migrate to WildFly/EAP or to Liberty if the licence cost is not justified |67| WebSphere | **Liberty** (single-stream SSCD model, delivery roughly every 4 weeks, **with no end-of-support date**; `26.0.0.5` added Jakarta EE 11 and Spring Boot 4.0) | **WAS traditional 9.0.5**: IBM **announces no end date**, but the real pressure is the currency of the fix pack, of the Java and of the OS underneath |68| Running PHP | **PHP-FPM** over a Unix socket, one pool and one user per application | FrankenPHP/embedded server only with an explicit rationale |69| Running Python | **WSGI/ASGI behind the web server** (gunicorn+uvicorn workers, or uvicorn/hypercorn) — never directly exposed | — |7071**Jakarta EE and the namespace change**: Jakarta EE 11 was released on **26 Jun 2025** (Core72Dec 2024, Web Profile Mar 2025), requires **Java 17+**, removes *Managed Beans*, the references to the73`SecurityManager` (JEP 411), SOAP with Attachments and XML Binding, and the optional74specifications. **Jakarta EE 12 is not released** and its dates contradict each other across sources (§8).75The `javax.*` → `jakarta.*` jump is **binary and non-negotiable**: it is the real cut between Tomcat 9 and7610+, and between EAP 7 and 8. **It is not a `sed`**: it affects transitive dependencies, descriptor77files and third-party bytecode; it is planned with the project's migration tool and78verified by running, not by compiling.7980## 3. The process model: why the default sizing is almost always wrong8182The default value is set by whoever packages it, **without knowing your memory or your request83profile**. A single rule: **the number of workers is dictated by the resident memory of the worst84process and by the nature of the waiting**, not by the number of cores.8586- **Apache**: `prefork` (one process per connection, expensive memory, safe with non-reentrant modules),87 `worker` (a process/thread hybrid) and `event` (threads + asynchronous handling of idle and88 *keep-alive* connections). With `event`, `MaxRequestWorkers` and `ServerLimit` × `ThreadsPerChild` must be89 coherent or start-up silently trims them. **With `mod_php` you are tied to `prefork`**: that is90 the technical reason to move to PHP-FPM, not a fashion.91- **nginx**: `worker_processes auto` (one per core) and `worker_connections` as a **ceiling per92 worker that includes connections towards the *upstream***, not only the client's: the effective93 limit is roughly half when proxying. `worker_rlimit_nofile` must be greater than94 `worker_connections`, or the real limit will be file descriptors.95- **IIS**: the application pool is the **failure and identity boundary** (`ApplicationPoolIdentity`96 = a virtual account per pool). One pool per application, never shared between tenants. **Periodic97 clock-based recycling and `idleTimeout` are on by default**: in an application98 with an expensive start-up they are surprise latency and lost in-memory state — disable hourly99 recycling, keep memory/request-based recycling, and use pre-warming (`AlwaysRunning` +100 `preloadEnabled`). A *web garden* (`maxProcesses` > 1) **breaks in-memory sessions**: it is not a101 performance button.102- **PHP-FPM**: `pm = dynamic` with `pm.max_children` computed as *memory available to the103 pool / RSS of the worst process*, and `pm.max_requests` to bound leaks. `pm = static` when the load104 is stable and start-up latency matters; `ondemand` only in sparse multi-tenancy. A105 short `pm.max_children` is **the number one cause of intermittent 502s** with nginx in front.106107## 4. Validation and gates108109- **Nothing is reloaded without validation**: `apachectl configtest` / `httpd -t`, `nginx -t`,110 `appcmd list config` or the `web.config` schema. In CI, validation runs against the111 rendered configuration, not against the template.112- **Reload, do not restart**: `nginx -s reload`, `apachectl graceful`, overlapped recycling in IIS.113 A hard restart cuts in-flight requests; combined with balancer draining114 (`load-balancing-standards`) the deployment should not lose a single one.115- **Gates in order of cost**: (1) syntax validation; (2) a configuration linter and diffs116 against the reference; (3) an HTTP smoke test against the origin **without going through the balancer**;117 (4) TLS and header verification (`testssl.sh`, a header check) against the deployed118 environment; (5) a load test that confirms the chosen sizing, not the default.119- **The configuration is code**: outside `iac-standards` there are no manual changes in production. A120 `.htaccess` edited hot is by definition an unversioned change.121122## 5. Stack security123124- **An unprivileged user**: the master process may need root for the low port (or125 `CAP_NET_BIND_SERVICE`/`AmbientCapabilities`), the workers **never**. A Java application126 server running as root is a design failure, not a pending adjustment.127- **Directory listing disabled**: `Options -Indexes`, `autoindex off`, directory browsing128 off in IIS. And the document root **outside** the code tree and `.git`.129- **The version out of the headers**: `ServerTokens Prod` + `ServerSignature Off`,130 `server_tokens off`, and in IIS remove `Server`, `X-Powered-By` and `X-AspNet-Version`. It is not131 real security, but it is free reconnaissance for the attacker and a guaranteed audit finding.132- **Unnecessary modules out**: every loaded module is surface and is a CVE that forces you to133 patch. Review `mod_status`, `mod_info`, `mod_userdir`, `mod_autoindex`, WebDAV, CGI and third-party134 modules. In IIS, remove the role features you do not use and enable request135 filtering. In Tomcat/WildFly, delete the sample and documentation applications.136- **`.htaccess` is surface**: `AllowOverride None` by default. Enabling it delegates configuration137 to whoever can write in the directory — including a compromised file upload — and penalises138 every request with filesystem lookups. It is enabled per directory and with an explicit list139 of directives, never globally.140- **The commercial products' admin console**: Tomcat Manager/Host Manager, the WildFly console,141 WebLogic's `/console` and **T3/IIOP**, the WebSphere administrative console. **Never on the Internet**:142 they listen on the management network or on loopback behind a tunnel, with their own credential and MFA143 where it exists. **Exposed T3/IIOP has a history of deserialisation RCE**: if you do not use it,144 disable it; if you do, filter it by network and apply the allowed class list.145- **TLS**: TLS 1.2 as the absolute minimum, 1.3 preferred; SSLv3/TLS 1.0/1.1 disabled. OCSP146 stapling on, HSTS only once the whole domain is already on HTTPS (and `preload` only with a147 conscious decision: it is hard to reverse). **The choice of suite and curve belongs to148 `cryptography-pki-standards`.**149- **Automatic certificate renewal**: ACME with an automatic reload afterwards, and **expiry150 monitoring independent of the agent that renews** — the real failure is not that it expires, it is that the151 agent renewed and nobody reloaded the service.152- **Response headers that genuinely belong to the server**: `Strict-Transport-Security`,153 `X-Content-Type-Options: nosniff`, `Referrer-Policy`, `Content-Security-Policy` and154 `Permissions-Policy`. The CSP **policy** is defined by the application (`appsec-standards`); the155 server emits it consistently and **does not duplicate it** — a header repeated by server and156 application is undefined behaviour in practice. `X-XSS-Protection` is obsolete: do not157 set it.158- **Static files**: served from the web server, not from the interpreter. Deny by159 pattern whatever must never leave (`.git`, `.env`, `~` copies, `.bak`, configuration files) and160 disable interpreter execution in upload directories — **an upload served as161 code is RCE**, and it is the most repeated mistake in the domain.162163## 6. Limits, 502/504 and logging164165- **A 502/504 is, almost always, a badly set limit here, not an application failure.** Before166 touching code, check: backend worker exhaustion (`pm.max_children`,167 `maxThreads`, the accept queue), an upstream read timeout shorter than the request's real168 duration, a header or body size above the buffer (`proxy_buffer_size`,169 `client_max_body_size`, `LimitRequestBody`, `maxAllowedContentLength`), and exhausted descriptors.170- **Four limits that are always set, with a justified number**: maximum request and171 header size; client and upstream timeouts **coherent across layers** (the balancer's172 must be larger than the origin's, or you will see cuts with no trace); file descriptors173 (`LimitNOFILE` in the systemd unit, not in a script's `ulimit`); and a listen backlog174 matching `somaxconn`.175- **Logging**: access and error separated, structured format (JSON) if it goes to a collector, and176 **rotation by the system tool with descriptor reopening** — a rotation that only177 renames leaves the process writing to an orphaned inode and fills the disk without anybody seeing it.178 Reserve space: **a disk full of logs takes the service down**.179- **What is not logged**: `Authorization`, `Cookie`, POST bodies, tokens in the query180 string and passwords in the URL. The **IP is personal data**: bounded retention and anonymisation or181 pseudonymisation as set by `privacy-engineering-standards`.182- **Compression and static content**: `gzip`/`brotli` only over compressible types (compressing a JPEG or a183 ZIP burns CPU for nothing), pre-compressed variants when the content is static, `sendfile` and184 `tcp_nopush` on. Be careful compressing responses that mix a secret with user input185 over TLS (the BREACH class). **The cache policy and the CDN belong to `caching-cdn-standards`**; here186 only that the server knows how to emit `ETag`/`Last-Modified` and answer `304`.187- **Minimum metrics**: requests per second and per status code, latency per percentile, busy workers188 against the limit, active connections, the accept queue and upstream errors. Without189 "busy workers / limit" **you cannot tell saturation from slowness**.190191## 7. Sustainability and prohibitions192193Cadence: a server security patch **outside the window** if the CVE is remotely exploitable;194a minor branch jump planned quarterly; a major branch jump (Tomcat 9→11, EAP 7→8) treated195as a **project with a budget**, because it drags the namespace change along. Every server196has an **end-of-support date recorded in the inventory**: without it, the migration always arrives197late.198199- ❌ Serving with an out-of-support server or branch (httpd 2.2, Tomcat 8.5/10.0, Jetty 9/10/11,200 EAP 7 without ELS) because "it works".201- ❌ Running workers as root, or the application server under the administrator's account.202- ❌ Leaving the default sizing in production without having computed memory per process.203- ❌ Exposing the admin console, `mod_status`, `/manager`, `/console` or T3/IIOP to the Internet.204- ❌ Enabling `.htaccess` globally, or letting the application's user write to the server's205 configuration.206- ❌ Allowing interpreter execution in directories where users upload files.207- ❌ Terminating TLS with obsolete versions or suites, or with a manually renewed certificate.208- ❌ Renewing with ACME without an automatic reload and without independent expiry monitoring.209- ❌ Logging authentication headers, POST bodies or tokens in the query string.210- ❌ Rotating logs by renaming without a reopen signal, or leaving the log disk with no quota and no alert.211- ❌ Treating a 502/504 as an application bug without first reviewing workers, timeouts and buffers.212- ❌ Setting an origin timeout larger than the balancer's (or the other way round unknowingly): it produces213 cuts with no trace in either of them.214- ❌ Changing configuration by hand in production and not returning it to the repository.215- ❌ Migrating `javax` → `jakarta` with search and replace, without running the integration tests.216- ❌ Duplicating security headers between server and application expecting "the stricter one to win".217218## 8. Mandatory web verification2192201. **The stable version and open CVEs** of httpd, nginx (stable branch versus *mainline*) and IIS/base221 OS. Check the project's advisory, not the distribution's package.2222. **The support calendar** for Tomcat (9.0.x/9.1.x dates), Jetty, WildFly, JBoss EAP,223 WebLogic and WebSphere. They change and they are the fact that decides the migration.2243. **The status of Jakarta EE 12**: not released as of Aug 2026. **Declared discrepancy**: InfoQ reported225 a plan with GA in Jul 2026 while the project's page at `jakarta.ee` marks it "Under226 Development" targeting a final release in **Q2-2027**. Do not pin a date without rereading the project's227 own source.2284. **Declared gap — WebLogic**: the exact Premier/Extended Support date for 14.1.2 lives in229 the Fusion Middleware *Lifetime Support Policy* document and in article **KB65053 of My230 Oracle Support**, which **requires a login and is not publicly verifiable**. The public policy231 confirms that Fusion Middleware 12c ends Premier in **Dec 2026** and Extended in **Dec 2027**;232 for 14c **you have to consult MOS with an account**. It is not filled in here.2335. **Declared gap — JBoss EAP 8.1**: Red Hat publishes the policy (7 years: 4 of Full Support +234 3 of Maintenance, plus optional ELS) but the concrete dates for 8.1 have to be taken from the235 *Product Life Cycles* table on the portal at decision time.2366. **The state of the nginx ecosystem after the forks**: **not re-verified here**, it is owned by237 `load-balancing-standards`; if that skill is out of date, update it there.2387. **Security headers**: check on MDN which are still current and which became obsolete239 before copying a template from years ago.2408. **The OS version that pins the server's** (IIS tied to Windows Server; httpd/nginx to the241 distribution's branch) and its end-of-support date.242243If the web contradicts this document, **the web wins** — flag the discrepancy.