# Certificates

How Ceryx picks a certificate for each HTTPS connection, gets them from Let's Encrypt, and serves your own.

## How Ceryx picks a certificate

When a client opens an HTTPS connection, it names the hostname it wants (Server Name Indication, or SNI). Ceryx serves the first certificate it finds for that hostname:

1. **A certificate stored for exactly that hostname**, through the [certificates API](/docs/api/certificates).
2. **A stored wildcard certificate** for its parent domain. `*.example.com` covers `app.example.com`, but not `example.com` or `a.b.example.com`.
3. **Certificate files from the route's settings**, `certificate_path` and `key_path`. Hostnames served by the catch-all route use the catch-all route's files.
4. **A Let's Encrypt certificate**, if Let's Encrypt is on and the hostname has a route, or there's a catch-all route.
5. **The default certificate**, a self-signed certificate that clients don't trust.

## Let's Encrypt

Ceryx gets a certificate from Let's Encrypt the first time a hostname is visited over HTTPS. That first connection waits a few seconds while Let's Encrypt checks the domain. After that, Ceryx stores the certificate in its database and renews it automatically before it expires.

For Let's Encrypt to issue a certificate:

- The hostname needs a route, or there must be a catch-all route.
- The hostname's DNS records must point at your server.
- Port 80 must be reachable from the internet. Let's Encrypt checks the domain over plain HTTP, and Ceryx answers the check itself, even for routes that enforce HTTPS.

Let's Encrypt [limits](https://letsencrypt.org/docs/rate-limits/) how many certificates it issues. While you test, use its staging environment, whose certificates browsers don't trust but whose limits are much higher:

```bash
CERYX_LETS_ENCRYPT_CA=https://acme-staging-v02.api.letsencrypt.org/directory
```

To turn Let's Encrypt off, for example on an internal network, set `CERYX_DISABLE_LETS_ENCRYPT=true`.

## Bring your own certificates

Store certificates with the [certificates API](/docs/api/certificates) when you:

- Want one wildcard certificate for many hostnames, such as preview deployments.
- Run on a network Let's Encrypt can't reach.
- Need certificates from a specific certificate authority.

Stored certificates apply to new connections right away, and take priority over Let's Encrypt. Renew them by storing the new certificate for the same domain.

You can also keep certificates as files inside the container, and point a route at them with its `certificate_path` and `key_path` [settings](/docs/route-settings). Ceryx reads the files when clients connect, so replacing them takes effect without a restart.

## The default certificate

Ceryx falls back to a self-signed certificate for hostnames it has no other certificate for, and for clients that don't send SNI. Browsers show a warning for it. To serve your own instead, for example a wildcard certificate for your main domain, mount it into the container and set `CERYX_TLS_DEFAULT_CERTIFICATE` and `CERYX_TLS_DEFAULT_KEY` to its paths.
