DNAbyD3Docs
Middleware

Caddy

Put DNA in front of every request Caddy serves, with one imported file and no plugin.

Import one file and Caddy asks DNA about every request before your site sees it. Caddy then does what your rules ask for, Charge and Require a human included. Stock Caddy 2.8 or later, no plugin, no custom build.

Install

  1. Download dna.caddy and put it beside your Caddyfile.

  2. Import it once, below your global options block if you have one, and add invoke dna to each site:

    import dna.caddy
    
    example.com {
    	invoke dna
    	reverse_proxy localhost:3000
    }

    Put invoke dna directly in the site block, anywhere in it, with no matcher. DNA then checks every request against the URL the visitor asked for, whatever your rewrite or try_files turn it into. With a matcher, the requests it skips reach your site unchecked, priced pages included.

  3. Set your API key in Caddy's environment as DNA_API_KEY.

  4. Restart Caddy so it reads the new variable, for example sudo systemctl restart caddy. A reload doesn't give a running Caddy a new environment variable.

  5. Verify the install.

dna.caddy uses ports 8113 and 8114 on 127.0.0.1. If something else already does, replace every 8113 and 8114 in the file. To upgrade, replace dna.caddy and reload Caddy; your Caddyfile stays as it is.

Installed the earlier forward_auth block? It serves Charge and Require a human pages as ordinary pages. Remove it and its proxy on port 8113, then install dna.caddy. Rename D3_EDGE_ADAPTER_KEY in Caddy's environment to DNA_API_KEY and restart Caddy: under the old name the key never reaches DNA, and nothing is enforced.

An MCP server rule that charges asks for payment on every request here, connecting and listing tools included. To charge per tool call, serve the MCP route through Vercel.

Leave headers out of your rules

DNA reads every header and cookie for your rules. Authorization and Proxy-Authorization never reach DNA. To have DNA ignore others, list them by name, comma-separated, in Caddy's environment, then restart Caddy:

VariableIgnores
DNA_EXCLUDE_HEADERSHeaders, by name
DNA_EXCLUDE_COOKIESCookies, by name

Caddy still sends a listed value, and DNA drops it on arrival. To keep a header on your server, add header_up -Name to the reverse_proxy {vars.d3_gateway} block in dna.caddy, and again each time you replace the file.

On this page