# ๐Ÿ›ก๏ธ TLS: what you can tune ๐Ÿ“Œ TLS examples below use `./certs/` in the working directory. Supply your own certificate, matching private key, or client CA file there; validation reads these files too. Pingclair obtains certificates for site names automatically. This page covers certificate sources, HTTP/3, and client certificate authentication. Unsupported TLS options are rejected when the configuration loads. ๐Ÿ“Œ This page describes **v0.2.2**. ## ๐Ÿงพ Before you start - Pingclair installed and running ([Install](/start/install/)). - For the certificate-authority parts, a name that resolves to the host, or the internal authority for a lab machine ([HTTPS](/start/https/)). ## ๐ŸŒ Which protocols are served Configure protocols in the global `servers` block: ```caddyfile { servers { protocols h1 h2 h3 } } ``` Measured with `sudo ss -lun | grep ':443 '`: | Configuration | UDP 443 listener | | --- | --- | | `protocols h1 h2` | 0 โ€” no HTTP/3 | | `protocols h1 h2 h3` | 1 โ€” HTTP/3 enabled | โš ๏ธ The list controls **HTTP/3** only. Listing `h1` alone does not turn HTTP/2 off: with `protocols h1`, a client that offered `h2` still negotiated HTTP/2. The only thing the server reads from the list is whether `h3` is in it, so no setting disables HTTP/2. Without a `protocols` line, HTTP/3 is on. The per-site `http3 off` option disables HTTP/3 for that site while the QUIC listener continues serving other sites: ```caddyfile https://internal.test { tls { internal http3 off } file_server /srv/site } ``` `http3 off` refuses this site's QUIC handshake and removes its HTTP/3 advertisement from `Alt-Svc`. Other sites on the port may continue to use QUIC. ## ๐Ÿ›๏ธ Certificate sources Three sources, all shown on the [HTTPS page](/start/https/): | Source | Configuration | What it is for | | --- | --- | --- | | Let's Encrypt | a bare public name | Public names, renewed in the background. | | Internal authority | `tls internal` | Lab names, private origins, tunnels. | | Your own files | `tls { cert โ€ฆ key โ€ฆ }` | Certificates issued elsewhere. | Renewal runs in the background. The global `renewal_window_ratio` option sets how early it starts, as a fraction of each certificate's lifetime. ## ๐Ÿ” Client certificates `client_auth` configures the server to request a client certificate. Create a small authority and a client certificate with `openssl`, then point the site at the authority's certificate **file**: ```caddyfile https://internal.test { tls { internal client_auth { mode require_and_verify trusted_ca_cert_file ./certs/client-ca.crt } } file_server /srv/site } ``` Measured: a request without a client certificate fails the handshake, and the same request with `--cert client.crt --key client.key` answers `200`. The modes are `request`, `require`, `verify_if_given`, and `require_and_verify`. A misspelled mode is refused with the whole list `(expected request, require, verify_if_given or require_and_verify)`. โš ๏ธ `trusted_ca_cert` takes the certificate itself, base64-encoded on one line, and `trusted_ca_cert_file` takes a path. Giving a path to the first compiles, then fails at startup with `trusted_ca_cert is not a certificate: not valid base64: Invalid symbol 45` โ€” the `-` of `-----BEGIN`. The file also has to be readable by the `pingclair` user. An exact site's `client_auth` policy takes precedence over a wildcard on the same port. An exact site with no block requires no client certificate; add its own block if it must require one. Certificates whose usage extensions exclude client authentication are refused. ## ๐Ÿ“ฆ Moving the certificate store The store contains the issued certificates, the ACME account, and the internal authority. For a package install it is `/var/lib/pingclair/.local/share/pingclair`, the data directory under the service account's home. A command run as another user looks in that user's own data directory, so the examples set `PINGCLAIR_TLS_STORE`; without it, root would use `/root/.local/share/pingclair`. `storage-export` and `storage-import` move the store: ```bash sudo PINGCLAIR_TLS_STORE=/var/lib/pingclair/.local/share/pingclair pingclair storage-export -o /tmp/store.tar sudo systemctl stop pingclair sudo rm -rf /var/lib/pingclair/.local/share/pingclair sudo mkdir -p /var/lib/pingclair/.local/share/pingclair && sudo chown pingclair:pingclair /var/lib/pingclair/.local/share/pingclair sudo PINGCLAIR_TLS_STORE=/var/lib/pingclair/.local/share/pingclair pingclair storage-import -i /tmp/store.tar sudo systemctl start pingclair ``` ```text โœ… Store exported to /tmp/store.tar โœ… Store imported into /var/lib/pingclair/.local/share/pingclair ``` The archive is an **uncompressed tar**, regardless of its filename, written with mode `600`, so reading it back needs root. The import restores the ownership recorded in the archive. The store also contains `autosave.json`, the configuration the Admin API last applied, so an import restores that too. ๐Ÿ“Œ **0.2.0:** the internal authority uses Caddy's directory layout, under `pki/authorities/local/`. The old `internal/` directory is not migrated: the server creates a new authority, and every client must trust the new root again (`pingclair trust`). A global `storage file_system ` option can also name the store in the configuration. If the service refuses to start afterwards with `Internal CA I/O error: Permission denied`, the store's files are not writable by the service account; `sudo chown -R pingclair:pingclair /var/lib/pingclair/.local/share/pingclair` restores the required ownership. ## ๐Ÿšซ Unsupported TLS options The following Caddy TLS options are recognized but rejected during configuration loading: ```text Caddy-compatible directive 'tls ciphers' is not supported by Pingclair yet: Pingclair does not implement this TLS option yet Caddy-compatible directive 'tls curves' is not supported by Pingclair yet: Pingclair does not implement this TLS option yet Caddy-compatible directive 'tls alpn' is not supported by Pingclair yet: Pingclair does not implement this TLS option yet Caddy-compatible directive 'tls on_demand' is not supported by Pingclair yet: Pingclair does not implement this TLS option yet ``` Cipher suites, curves, the ALPN list, and on-demand issuance are therefore fixed by the build, not by the configuration. OCSP stapling is not performed either. These settings cannot be enabled through configuration. ## โš ๏ธ Troubleshooting - **`client_auth` refuses to start with `not valid base64`.** A path was given to `trusted_ca_cert`; the file spelling is `trusted_ca_cert_file`. - **A client with a valid certificate is rejected.** Check the CA that signed it is the one in `trusted_ca_cert_file`, and that the certificate has not expired. - **`tls ciphers` / `tls curves` / `tls alpn` / `tls on_demand` refuse the file.** They are not implemented; see the section above. - **HTTP/3 still runs after `protocols h1 h2`.** It should not, because that list controls it. If UDP 443 is still listening, the file that is running is not the file you edited ([what a reload means](/start/service/#-what-a-reload-means)). - **The service will not start after moving a store.** Ownership, as above. ## ๐Ÿงญ Next steps - [HTTPS](/start/https/): the four certificate sources, with their exact log lines. - [HTTP/3](/guides/http3/): configuration and client-side protocol verification. - [`tls`](/reference/directives/#tls): the directive reference.