+
+ Upgrading the caddy package replaces your custom binary with the standard build,
+ which does not include the plugin.
+ Run caddy add-package again after each upgrade,
+ or sudo apt-mark hold caddy to hold the package at its current version.
+
+
+
+## Configure Caddy
+
+Caddy will use the Accounts root certificate to verify client certificates.
+
+First, copy the `accounts_root_ca.crt` file to your Caddy server as `/etc/caddy/accounts_root_ca.crt`
+
+Then, replace `/etc/caddy/Caddyfile` with the following,
+substituting your proxy's DNS name and your collector's address:
+
+```
+{
+ servers {
+ strict_sni_host insecure_off
+ }
+}
+
+proxy.example.com, :443 {
+ tls {
+ client_auth {
+ mode require_and_verify
+ trust_pool file /etc/caddy/accounts_root_ca.crt
+ }
+ }
+
+ log
+
+ route {
+ forward_proxy {
+ ports 4318
+ acl {
+ allow otel.internal.example.com
+ deny all
+ }
+ }
+ }
+}
+```
+
+Here's what this configuration does:
+
+- **`client_auth`** rejects any TLS connection that doesn't present a valid certificate from your Accounts authority.
+ Unauthenticated clients never reach the proxy.
+- **`proxy.example.com, :443`** gets a Web PKI certificate for your proxy's name,
+ and answers requests for any host. This matters because a `CONNECT` request names its *destination* (here, `otel.internal.example.com:4318`), not the proxy.
+- **`strict_sni_host insecure_off`** lets the proxy accept requests whose destination differs from the TLS server name.
+ It's safe to disable strict SNI host checking because this server will have a single forward proxy route, and every connection must present a client certificate.
+- **`ports 4318`** and **`acl`** allow tunnels to your collector's OTLP/HTTP port only.
+ The plugin blocks private addresses by default, so you must allow your collector explicitly,
+ by hostname, IP address, or subnet.
+- **`log`** writes an access log entry for every tunnel, including the client certificate's common name.
+
+Validate the configuration and reload Caddy:
+
+```bash
+caddy validate --config /etc/caddy/Caddyfile
+sudo systemctl reload caddy
+```
+
+# Step 3: Configure clients
+
+On each device, the Smallstep Agent forwards a local port through Caddy to your collector,
+and Claude Code sends telemetry to that local port.
+
+## Forward a local port to the collector
+
+The agent's `proxy` command with the `--forward` flag listens on a local address
+and tunnels every connection it accepts to a fixed destination, similar to `ssh -L`.
+
+Test it in a terminal:
+
+```bash
+/Applications/SmallstepAgent.app/Contents/MacOS/SmallstepAgent proxy \
+ --workload-name claude-otel \
+ --relay https://proxy.example.com \
+ --system-roots \
+ --forward 4318:otel.internal.example.com:4318
+```
+
+The flags are:
+
+- **`--workload-name claude-otel`** uses the credential you created in Step 1.
+- **`--relay https://proxy.example.com`** is the URL of your Caddy proxy.
+- **`--system-roots`** verifies the proxy's server certificate against the operating system's Web PKI trust store. Otherwise, the agent only trusts your Accounts authority.
+- **`--forward 4318:otel.internal.example.com:4318`** is the destination, as resolved by the proxy.
+
+In another terminal, send an empty batch of events:
+
+```bash
+curl -X POST http://127.0.0.1:4318/v1/logs \
+ -H 'Content-Type: application/json' \
+ --data '{"resourceLogs":[]}'
+```
+
+The collector replies with `{"partialSuccess":{}}`.
+Press `Ctrl+C` to stop the forwarder.
+
+## Run the forwarder in the background
+
+To keep the forwarder running, install it as a launchd agent for each user.
+Save the following as `~/Library/LaunchAgents/com.example.otel-forward.plist`:
+
+```xml
+
+
+