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

# Networking and the edge

> Every request to a Brimble-hosted project hits the edge first.

Every request to a Brimble-hosted project hits the **edge** first. The edge terminates TLS, routes to the right service, and adds a few headers your app can use. This page covers what happens between your users' browsers and your code.

## Request lifecycle

```text theme={null}
User
 │
 │  1. DNS resolves your-domain.com → Brimble edge
 ▼
Edge
 │  2. TLS handshake (Let's Encrypt cert)
 │  3. Hostname lookup → match to project
 │  4. Header injection
 ▼
Service
 │  5. Container handles request, returns response
 ▼
Edge
 │  6. Response sent back over the same TLS connection
 ▼
User
```

The edge is the only public entry point. Your service container has no public IP, all traffic must go through the edge.

## Routing

Routing is hostname-based. Brimble looks at the `Host` header and matches it against:

* **`<project-name>.brimble.app`**, the default URL for every project.
* **`<project-name>-<environment>.brimble.app`**, Preview and other non-production environments.
* **Your custom domains**, once verified.

If a hostname doesn't match a known project, the edge returns a generic 404. Reserved hostnames (`localhost`, internal addresses) return a "not connected" page.

## TLS

Every Brimble URL serves over HTTPS. The edge handles TLS termination, so your service speaks plain HTTP internally, you never need to configure certificates on your container.

For default URLs (`*.brimble.app`), Brimble uses a wildcard certificate. For custom domains, Brimble issues a free certificate from Let's Encrypt as soon as the domain points at the edge. Certificates renew automatically before expiry.

If a custom domain's certificate fails to issue, the most common cause is a `CAA` DNS record that doesn't authorize Let's Encrypt, see [TLS troubleshooting](../troubleshooting/tls).

## Headers Brimble injects

The edge adds a small set of headers before forwarding the request:

| Header                      | Value                                                            |
| --------------------------- | ---------------------------------------------------------------- |
| `X-Forwarded-Proto`         | `https` (always, even if the original request hit `http://`)     |
| `X-Forwarded-For`           | The client's real IP                                             |
| `X-Real-IP`                 | The client's real IP                                             |
| `X-Brimble-Host`            | The hostname the request came in on                              |
| `X-Brimble-Id`              | A unique ID for this request, useful for log correlation         |
| `X-Brimble-Project-Version` | An ISO timestamp identifying the deployment serving this request |

If your app is behind a framework that respects `X-Forwarded-Proto` (Express's `trust proxy`, Django's `SECURE_PROXY_SSL_HEADER`, Rails's `force_ssl`), enable it so the framework knows requests are arriving over HTTPS.

## Headers Brimble strips

A few headers used by frameworks for internal-only signaling are stripped at the edge so they can't be set by an attacker:

* `X-Middleware-Subrequest`
* `X-React-Router-Prerender-Data`
* `X-React-Router-SPA-Mode`

Your code can set these on responses; they just won't be honored if a client sends them.

## WebSockets

WebSockets work without configuration. Any path with an `Upgrade: websocket` request header is upgraded transparently. Brimble keeps the connection open as long as both ends do.

Common patterns it recognizes: `/ws/*`, `/socket.io/*`, anything that sends a proper upgrade.

## HTTP/2 and gRPC

The edge speaks HTTP/2 to clients by default. Inside, it forwards using whatever transport the service expects:

* **HTTP/1.1** for normal services.
* **HTTP/2 cleartext (h2c)** for gRPC services. Detected automatically when the request's `Content-Type` starts with `application/grpc`.

gRPC and gRPC-Web both work. Bidirectional streaming, server streaming, and client streaming are all supported.

## Rate limits

Public traffic to your project goes through **Cloudflare**, which rate-limits abusive single-source traffic at the edge before it reaches Brimble's gateway. Throttled requests get `429 Too Many Requests` from Cloudflare; normal user traffic is unaffected.

Service-to-service calls inside Brimble's network don't go through Cloudflare and aren't rate-limited.

For workloads that need custom rules (high-traffic public APIs, large file ingest), contact support. See [Rate limits](/networking/rate-limits) for the full breakdown.

## Body size

Request bodies are capped at **5 MB** by default. JSON, form, URL-encoded, and binary uploads above 5 MB are rejected with `413 Payload Too Large`.

For larger uploads (file uploads, large data ingest), upload directly to object storage from the client and have your service handle the resulting key, rather than streaming through the edge.

## Health checks

Brimble probes your service after deployment to decide whether traffic should flow to the new version:

* **Web services.** A GET request to `healthCheckPath` (default `/`). Anything in the 2xx or 3xx range counts as healthy.
* **Workers.** Process liveness only, if the process is alive, the worker is healthy.
* **Static sites.** No probe; the artifact is served directly.

You can change the health check path under **Settings → Configuration**. Use a lightweight endpoint that doesn't depend on slow downstream services, `GET /healthz` is a common pattern.

If a deployment fails its health check repeatedly, it's marked **degraded**. Traffic continues to flow to the previous active deployment.

## Connection retries

By default a project runs as a single container, and the edge sends all of its traffic to that one. A single connection-level retry happens automatically if the container is briefly unavailable (between health-check passes during a deploy, for example). Application-level errors, a 5xx response your code returned, go straight to the client; the edge doesn't retry those.

If you've configured an [autoscaling group](../scaling/overview) and the project is running multiple containers, the edge distributes traffic across them and retries connection-level failures against another container before failing the request.

## Outbound traffic

Your service can make outbound HTTP(S) requests freely. There's no egress whitelist for normal traffic.

Outbound traffic from a Brimble service appears to come from a region-specific IP range. If you're whitelisting Brimble at a third-party API, get the current ranges from support, they aren't fixed forever.

## Next steps

* [Custom domains](../domains/custom-domains), pointing your own domain at a project.
* [502 errors](../troubleshooting/502-errors), what to check when the edge can't reach your service.
* [Rate limits](/networking/rate-limits), full set of edge limits.
