# Authenticated origin pulls (mTLS)

> Make the edge present a client certificate so your origin accepts only connections that come through OpenWAF.

With **Require the edge certificate** on, the edge presents a TLS client certificate when your origin asks for one. Your server then requires a client certificate signed by the **OpenWAF Edge Client CA** and refuses every other connection, including attackers who found your origin's IP address.

## How it works

- Each edge node has its own client certificate (ECDSA P-256, valid for 30 days), issued by the OpenWAF Edge Client CA and renewed automatically well before it expires.
- The edge presents it only for sites with `origin.client_cert` set to `true`, and only when the origin requests a client certificate.
- The Edge Client CA is **shared by the whole platform**. A valid client certificate proves "this connection comes from the OpenWAF edge", not "it comes for my zone". Combine it with the `Host` header and SNI checks on your server and, if you need more, your own authentication.

> **Caution: Order matters**
>
> Turn the option on in OpenWAF **before** requiring client certificates on your server; otherwise your sites answer `525` until the change reaches every edge node. To turn it off, first stop requiring it on the server.


## Set it up

1. **Turn the option on and wait for it to propagate.**

**Dashboard**

   In **SSL/TLS › Origin › Require the edge certificate**, turn on **Present the edge client certificate** and **Save changes**. Check **Changes › Propagation** until every node applied the new version.

**CLI**

   ```sh
   openwaf-cloud ctl zones set example.com origin.client_cert:=true --reason "mTLS to the origin" --wait
   ```

   `--wait` returns when every node has applied the new version.

**API**

   ```sh
   curl -s -X PATCH https://dash.openwaf.dev/v1/orgs/$ORG/zones/$ZONE/edge \
     -H "Authorization: Bearer $OPENWAF_TOKEN" \
     -H "Content-Type: application/json" \
     -H "X-Change-Reason: mTLS to the origin" \
     -d '{"origin": {"client_cert": true}}'
   ```

**MCP**

   `update_settings` with `{"zone": "example.com", "settings": {"origin": {"client_cert": true}}, "reason": "mTLS to the origin"}`, first with `confirm=false`, then `confirm=true`. Check `zone_propagation` afterwards.


2. **Download the Edge Client CA** to your server:

   ```sh
   curl -fsS https://dash.openwaf.dev/v1/origin-tls/edge-client-ca.pem -o openwaf-edge-client-ca.pem
   # or: openwaf-cloud ctl origin-tls ca --client > openwaf-edge-client-ca.pem
   ```

   The dashboard offers the same file under **Download the Edge Client CA (PEM)**.

3. **Require client certificates on the server** (examples below) and reload it.

4. **Check.** In the origin status, the name shows **mTLS** and no `525` errors appear. From outside the edge, a connection without a client certificate must fail:

   ```sh
   curl -sv https://203.0.113.10/ -H 'Host: www.example.com' -k -o /dev/null
   ```


## Server examples

**nginx**

```nginx
server {
    listen 443 ssl;
    ssl_certificate        /etc/nginx/tls/origin.pem;
    ssl_certificate_key    /etc/nginx/tls/origin.key;
    # Only connections from the OpenWAF edge
    ssl_client_certificate /etc/nginx/tls/openwaf-edge-client-ca.pem;
    ssl_verify_client      on;
    ssl_verify_depth       1;
}
```

**Caddy**

```text
example.com {
    tls /etc/caddy/tls/origin.pem /etc/caddy/tls/origin.key {
        client_auth {
            mode require_and_verify
            trust_pool file /etc/caddy/tls/openwaf-edge-client-ca.pem
        }
    }
    reverse_proxy 127.0.0.1:8080
}
```

Before Caddy 2.8, use `trusted_ca_cert_file /etc/caddy/tls/openwaf-edge-client-ca.pem` instead of `trust_pool`.

**Apache**

```text
<VirtualHost *:443>
    ServerName example.com
    SSLEngine on
    SSLCertificateFile    /etc/ssl/openwaf/origin.pem
    SSLCertificateKeyFile /etc/ssl/openwaf/origin.key
    SSLCACertificateFile  /etc/ssl/openwaf/openwaf-edge-client-ca.pem
    SSLVerifyClient require
    SSLVerifyDepth  1
</VirtualHost>
```

**Traefik**

```yaml
tls:
  options:
    openwaf-edge:
      clientAuth:
        caFiles:
          - /certs/openwaf-edge-client-ca.pem
        clientAuthType: RequireAndVerifyClientCert
http:
  routers:
    example:
      rule: Host(`example.com`)
      tls:
        options: openwaf-edge@file
      service: example
```

With Docker labels: `traefik.http.routers.example.tls.options=openwaf-edge@file`.


## Keep the CA up to date

When the Edge Client CA rotates, the download URL returns both the old and the new CA while both are valid. Download it again regularly; a daily scheduled `curl` is enough.

## Related

- [Origin TLS modes](https://developers.openwaf.dev/ssl/origin-tls/)
- [Troubleshooting 525](https://developers.openwaf.dev/ssl/troubleshooting/#error-525)
