ssl_stapling is on and silently doing nothing

ssl_stapling on; without a resolver is one of the quietest failures in nginx. The directive is accepted, the config test passes, and no OCSP response is ever stapled.

MEDIUM ssl_stapling_without_resolver 5 min read Updated: August 2026

What Gixy reports

[ssl_stapling_without_resolver] ssl_stapling is enabled but no resolver is configured
  Severity: MEDIUM
  Reason: ssl_stapling is enabled for this SSL server, but no `resolver`
          directive is reachable in its scope - OCSP stapling will
          silently fail.

Why a resolver is required

OCSP stapling means nginx fetches the certificate's revocation status from the issuing CA itself, caches it, and attaches it to the TLS handshake. The client gets a signed freshness proof without contacting the CA, which is both faster and better for privacy.

To do that, nginx has to make an outbound HTTP request to the OCSP responder URL embedded in your certificate -- a hostname. nginx does not use the system resolver for runtime lookups; it has its own, and it only exists if you configure it. With no resolver in scope the hostname cannot be resolved, the fetch never happens, and stapling is skipped.

server {
    listen 443 ssl;
    server_name example.com;

    ssl_certificate     /etc/ssl/example.com.pem;
    ssl_certificate_key /etc/ssl/example.com.key;

    ssl_stapling on;
    ssl_stapling_verify on;
    # no resolver anywhere in scope
}

nginx -t passes

The syntax is valid, so the config test succeeds and the server starts. At most you get a warning in the error log at the first handshake. Everything looks configured, and clients are quietly doing their own OCSP lookups -- exactly what you enabled stapling to avoid.

The fix

Add a resolver in the server or http block:

server {
    listen 443 ssl;
    server_name example.com;

    ssl_certificate     /etc/ssl/example.com.pem;
    ssl_certificate_key /etc/ssl/example.com.key;

    ssl_stapling on;
    ssl_stapling_verify on;

    resolver 127.0.0.1 valid=300s ipv6=off;
    resolver_timeout 5s;
}
Use a local resolver, not a public one. 127.0.0.1 assumes a local caching resolver such as unbound or systemd-resolved; your cloud provider's internal DNS works equally well. Pointing this at 8.8.8.8 or 1.1.1.1 sends every internal lookup off your network in cleartext and is itself a HIGH finding -- resolver_external.

ssl_stapling_verify on; makes nginx validate the OCSP response signature before stapling it. It needs the issuer chain available, which is normally satisfied by a full-chain ssl_certificate file. resolver_timeout 5s; keeps a slow DNS server from stalling handshakes.

Verify the fix

gixy /etc/nginx/nginx.conf
nginx -t && nginx -s reload

# Ask for a stapled response:
echo | openssl s_client -connect example.com:443 \
        -servername example.com -status 2>/dev/null \
    | grep -A 17 'OCSP response'

Working stapling prints OCSP Response Status: successful followed by the validity window. Broken stapling prints OCSP response: no response sent.

Give it a moment. nginx fetches the OCSP response lazily -- the very first handshake after a reload usually goes out unstapled while the fetch happens in the background. Run the command twice.

When this is a false positive

Let's Encrypt certificates. Let's Encrypt stopped serving OCSP on 2025-08-06. If your certificate comes from them, stapling has nothing to fetch and the right change is to remove ssl_stapling rather than to add a resolver. Gixy has a separate check for precisely this -- ssl_stapling_letsencrypt -- so if you see both findings on the same server, act on that one.

Otherwise this finding is reliable. A resolver is either reachable in scope or it is not, and Gixy resolves inheritance from http down to server the same way nginx does.

Reference