Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Caddy Reverse Proxy

This page documents the self-hosted ingress path for Detritus on canix hosts.

Topology

Caddy terminates public TLS and forwards cleartext loopback traffic to detritusd.

client
  |
  | HTTPS
  v
Caddy :443
  |
  | plain HTTP / h2c on loopback
  v
detritusd 127.0.0.1:4317

The same upstream listener carries both OTLP/gRPC logs and multipart crash uploads.

Receiver Bind

The correct bind address behind Caddy is:

detritusd --bind 127.0.0.1:4317 --tokens-config /etc/detritus/tokens.toml

Do not bind 0.0.0.0:4317 just to make the proxy work.

canix Route Shape

The canix Caddy preset uses canix.presets.services.caddy.mkReverseProxyRoute. A Detritus host configuration looks like this:

{
  config,
  inputs,
  lib,
  ...
}: let
  hostname = "detritus.example.com";
  bindAddr = "127.0.0.1";
  bindPort = 4317;
in {
  imports = [
    inputs.detritus.nixosModules.default
  ];

  services.detritus = {
    enable = true;
    bind = "${bindAddr}:${toString bindPort}";
    tokensConfig = config.age.secrets.detritus-tokens.path;
  };

  canix.presets.services.caddy.routes = [
    (lib.recursiveUpdate
      (config.canix.presets.services.caddy.mkReverseProxyRoute {
        inherit hostname;
        port = bindPort;
        host = bindAddr;
      })
      {
        handle = [
          {
            handler = "reverse_proxy";
            transport = {
              protocol = "http";
              versions = ["h2c" "2"];
            };
            upstreams = [
              { dial = "${bindAddr}:${toString bindPort}"; }
            ];
          }
        ];
      })
  ];
}

The important part is the h2c upstream transport, which lets tonic keep serving gRPC over cleartext loopback.

Body Size And Timeouts

The server accepts up to 100 * 1024 * 1024 bytes for each dump or attachment part and applies a request-wide 150 MiB body limit.

If you add a Caddy-side request-body limit, keep it aligned with the server request limit:

request_body {
  max_size 150MiB
}

Client Configuration

Clients should point at the public HTTPS origin, not the loopback listener.

detritus-client calls detritus::install_default_crypto_provider() before it builds its HTTPS crash shipper. Applications that construct their own reqwest clients earlier in process startup need to call that function themselves before the first TLS handshake.

Health Check

The receiver exposes GET /healthz, not /health.

Through Caddy:

curl -i https://detritus.example.com/healthz