> ## Documentation Index
> Fetch the complete documentation index at: https://www.towbar.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Domains and TLS

> Expose an HTTP service through Caddy with direct DNS or Cloudflare DNS validation.

Towbar uses Caddy on the target server to route public HTTP traffic. Domain settings live with the app or resource in the manifest; provider credentials come from the Towbar API environment.

## Choose a TLS mode

| Mode             | DNS setup                                                                         | Credentials                                                      |
| ---------------- | --------------------------------------------------------------------------------- | ---------------------------------------------------------------- |
| `direct`         | Point public DNS at the target and allow ACME validation to reach Caddy           | No Cloudflare token                                              |
| `cloudflare-dns` | Use a Cloudflare zone; Towbar manages its owned records and validates through DNS | Cloudflare enabled on the server with a scoped Account API token |

Set the primary hostname without a scheme or path. A TLS declaration requires a primary domain. A publicly routed resource also needs a container port and an HTTP health check.

## Direct TLS

Add the following fields to an app, replacing the example domain:

```yaml theme={"system"}
domains:
  primary: app.example.com
  redirects:
    - host: www.app.example.com
      status: 301
tls:
  mode: direct
```

Point the hostname at the target server. Allow inbound HTTP and HTTPS traffic required by Caddy and certificate validation. Deploy and verify both the primary URL and each redirect.

## Cloudflare TLS

Set `TOWBAR_CLOUDFLARE_ENABLED=true`, `TOWBAR_CLOUDFLARE_ACCOUNT_ID`, and `TOWBAR_CLOUDFLARE_API_TOKEN` on the API process, then restart Towbar. The Cloudflare integration and the per-server **Cloudflare TLS** toggle appear only after the complete environment configuration passes startup validation.

Create the token under **Manage Account → Account API Tokens** in Cloudflare. Grant **Zone → Zone → Read**, **Zone → DNS → Edit**, and **Zone → Zone Settings → Read**, restricted to the zones Towbar should manage. Zone Settings Read lets Towbar verify that SSL/TLS mode is Full (strict). Creating account tokens requires the Super Administrator role. See [Cloudflare's account-token guide](https://developers.cloudflare.com/fundamentals/api/get-started/account-owned-tokens/).

Use a scoped account token rather than a personal or global API key. `TOWBAR_CLOUDFLARE_ZONE_ID` is optional when the token can discover the required zones. The prepared Caddy build must contain the Cloudflare DNS module.

```yaml theme={"system"}
domains:
  primary: app.example.com
tls:
  mode: cloudflare-dns
```

Towbar manages records it owns and completes certificate validation before promotion. Keep unrelated records and services outside that ownership boundary.

## Preview hostnames

Previews use a generated hostname beneath `preview.domain`. Direct mode needs DNS routing for those generated names, typically a wildcard. Cloudflare DNS mode manages the exact preview records and removes them during cleanup.

For proxied nested hostnames, check Cloudflare's certificate coverage as well as DNS. A resolving wildcard does not guarantee that the edge certificate covers every nested hostname.

## Cloudflare Tunnel ingress

Use `ingress.type: cloudflare-tunnel` when the workload server should not expose a public inbound application port. Create a named Cloudflare integration with a scoped account API token, account ID, optional zone ID, and Towbar's reviewed cloudflared image digest. Reference its slug and optionally a dedicated tunnel name in the app or Compose service manifest.

Towbar creates or attaches only resources carrying its ownership identity, writes generated tunnel credentials to root-owned transient storage, starts cloudflared without a Docker socket or published administration port, and verifies the route before promotion. DNS and tunnel routes are reconciled on redeploy. Preview and removed routes are cleaned only when ownership matches; an uncertain provider response leaves a visible cleanup warning for later reconciliation.

Enabling Tunnel does not expose SSH, the Docker API, Towbar's control plane, or another service on the host. Cloudflare Access is an explicit manifest choice. Credential rotation replaces the runtime configuration on the next reconciliation.

<div className="towbar-doc-screenshot">
  <div className="towbar-product-light">
    <img src="https://mintcdn.com/avgeek/7IKQY5hBmeQaVMw0/assets/release-v2/previews-light.jpg?fit=max&auto=format&n=7IKQY5hBmeQaVMw0&q=85&s=ed26b3a3f5f76e8e638d619336b40bde" alt="Preview environments show their URL, commit, expiry, and cleanup status." width="1280" height="720" loading="lazy" data-path="assets/release-v2/previews-light.jpg" />
  </div>

  <div className="towbar-product-dark">
    <img src="https://mintcdn.com/avgeek/7IKQY5hBmeQaVMw0/assets/release-v2/previews-dark.jpg?fit=max&auto=format&n=7IKQY5hBmeQaVMw0&q=85&s=bdfce93fc6ef88e804b2eda81b13336c" alt="Preview environments show their URL, commit, expiry, and cleanup status." width="1280" height="720" loading="lazy" data-path="assets/release-v2/previews-dark.jpg" />
  </div>

  <p>
    Preview environments show their URL, commit, expiry, and cleanup status.
  </p>
</div>

## Diagnose a failed route

Check these in order: domain spelling, DNS resolution, network access to the host, Caddy preparation, TLS mode and credentials, then the workload's health endpoint. A successful Repository sync or image build does not prove that the HTTPS route works.

See [Troubleshooting](/docs/troubleshooting) for common failure paths.
