# Certificates

> Hot-swap the gateway's TLS material without dropping connections.

The QUIC and WebTransport listeners terminate TLS using a cert/key pair on
disk. `ReloadCertificates` reloads them in place — useful for ACME/Let's
Encrypt renewals or rotating compromised material without a restart.

> **WARNING:**
> No SDK wrapper. Issue this method via the [raw RPC envelope](/rpc/envelope-format).

## `ReloadCertificates`

Request (`ReloadCertificatesRequest`):

| Field        | Type     | Notes                                                        |
| ------------ | -------- | ------------------------------------------------------------ |
| `cert_path`  | `string` | Absolute path on the gateway host to the new PEM cert chain. |
| `key_path`   | `string` | Absolute path to the matching PEM private key.               |

Both files must already exist on the gateway's filesystem at the supplied
paths. The admin RPC does not transport file bytes — it only triggers an
in-process reload.

Response (`ReloadCertificatesResponse`):

| Field           | Type     | Notes                                          |
| --------------- | -------- | ---------------------------------------------- |
| `status`        | `string` | `"ok"` on success; `"error"` otherwise.        |
| `error_message` | `string` | Populated when `status="error"` (e.g. parse failure, mismatched key). |

## What changes when

- **Existing QUIC connections** keep their session tickets; they continue
  using the certificate they handshook with. No drop.
- **New QUIC handshakes** (and the next 0-RTT resumption that crosses a
  TLS context refresh) use the freshly loaded cert.
- **Self-signed dev certs**: browsers cache `serverCertificateHashes`. If
  you rotate a self-signed cert, every browser tab needs the new
  fingerprint passed through the SDK constructor.

## ACME loop

A typical operator setup runs `certbot renew` on a cron and follows up
with `ReloadCertificates`:

```
certbot renew --quiet --post-hook \
  '<your-rpc-client> ReloadCertificates \
     --cert /etc/letsencrypt/live/engine.clutchcall.dev/fullchain.pem \
     --key  /etc/letsencrypt/live/engine.clutchcall.dev/privkey.pem'
```

`<your-rpc-client>` is whatever raw QUIC client you build to drive the
admin RPC; nothing in the SDK helps here, by design.

## Failure mode

If the new cert/key pair fails validation, the gateway leaves the old
material in place and returns `status="error"`. There is no half-loaded
state.
