Safeguard
Developer Tools•

nginx, Apache and Caddy: security defaults compared side by side

Documented defaults for version banners, forwarded headers, TLS, body limits and open proxy risk in nginx, Apache and Caddy, and what to set yourself.

Safeguard Security Team
4 min read

None of the three is secure by default in every respect, and none is insecure by nature. The documented defaults differ. Caddy leads on automatic HTTPS and spoof resistant forwarded headers. nginx has tight body and header limits. Apache defaults to a verbose Server header and a 1 GB body limit. Know yours and set what you need.

The table

All values are from each project's own documentation.

TopicnginxApache httpdCaddy
Version in Server headerserver_tokens on by defaultServerTokens Full by defaultNot covered in the pages I read
Client forwarded headersYou choose with realip, trust list requiredProxyAddHeaders On, existing values are appendedIgnores incoming X-Forwarded values by default
Upstream TLS verificationproxy_ssl_verify off by defaultDefined in the mod_ssl docs, not checked hereVerifies https upstreams, insecure skip is a named option
Body size limitclient_max_body_size 1mLimitRequestBody 1 GB (unlimited in 2.4.53 and earlier)request_body max_size, no default stated
TLS versionsTLSv1.2 and TLSv1.3Not checked hereAutomatic HTTPS handles certificates
CertificatesYou provide themYou provide themObtained and renewed automatically
Open proxy riskNone unless you build one with variable proxy_passProxyRequests Off by defaultNot applicable by default
TRACENot in pages readTraceEnable on by defaultNot in pages read

Blank or unchecked cells are a reminder to read the docs for your version, not a statement that nothing exists.

Reading the differences

Banners. nginx and Apache both show the version by default. Trim them, but see server_tokens myth versus fact and the Apache directives post.

Forwarded headers. Caddy ignores client supplied X-Forwarded values unless the sender is a trusted proxy. Apache sends them to the backend and, when the request already had them, comma separates the values, so a backend reading the first entry reads client input. nginx's realip module rewrites the client address only for senders you list.

Upstream TLS. nginx's proxy_ssl_verify default off is the surprise here. See the upstream TLS post.

Limits. nginx rejects large bodies at 1 MB until you raise it. Apache's 1 GB default is only a ceiling. Set your own in both.

Certificates. Caddy's automation removes a common outage cause, described in the Caddy HTTPS post. With nginx and Apache you need renewal automation, see the ACME checklist.

What to set in every case

  1. Short Server header.
  2. One clear forwarded header policy, with trusted proxies listed exactly.
  3. Verified upstream TLS where traffic crosses a shared network.
  4. Body, header and timeout limits that match your app.
  5. A catch-all for unknown hosts.
  6. Security headers on every status code.
  7. A patch routine for the server and its modules.

Choosing

Choose by operations, not by security slogans. A team that struggles with certificate renewal gains a lot from Caddy. A team with deep nginx experience and config management may be safer staying where its reviews are strongest. The weakest setup is the one nobody reviews.

Where Safeguard fits

Safeguard does not replace any of the three. It inventories the software around them through asset discovery, SBOM and dependency scanning, and policy gates. Try the free scan at https://gold.safeguard.sh/scan.

Quick check

Which of the three ignores client X-Forwarded headers by default?

Caddy, per its reverse_proxy documentation, unless the sender is in trusted_proxies.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.