> ## 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.

# HTTP, WebSockets, and gRPC

> How Brimble handles public HTTP traffic, upgraded connections, and HTTP/2 services.

Brimble exposes web services over HTTPS and forwards requests to the port your service listens on. Your service does not manage public certificates. It reads `PORT`, listens for HTTP traffic, and Brimble handles the public edge.

## Public HTTPS

Every public Brimble URL serves over HTTPS:

* Default project URLs, such as `<project>.brimble.app`.
* Preview URLs.
* Custom domains after DNS and certificate provisioning finish.

TLS terminates before the request reaches your container. Inside Brimble, your service receives plain HTTP on its assigned port. Use `X-Forwarded-Proto` if your framework needs to know the original request was HTTPS.

## What your service should listen on

Your web service must listen on the port in the `PORT` environment variable:

```javascript theme={null}
const port = Number(process.env.PORT);

app.listen(port, "0.0.0.0", () => {
  console.log(`listening on ${port}`);
});
```

Do not hardcode a port. Brimble assigns one at runtime, and the gateway routes traffic to that port.

Bind to `0.0.0.0`, not `localhost`, so the gateway can reach your process from outside the container.

## Supported public protocols

| Protocol           | Support                               | Notes                                                                            |
| ------------------ | ------------------------------------- | -------------------------------------------------------------------------------- |
| HTTP/1.1           | Supported by default                  | Use this for normal websites, APIs, and webhooks.                                |
| HTTPS              | Supported at the public edge          | Your container still listens with plain HTTP.                                    |
| WebSockets         | Supported by default                  | Any request with a valid `Upgrade: websocket` header is proxied bidirectionally. |
| Server-Sent Events | Supported                             | Keep the response open and flush events from your framework.                     |
| HTTP/2 and gRPC    | Available for HTTP/2-enabled projects | Your service must serve HTTP and gRPC on the same `PORT`.                        |

## HTTP/2 and gRPC services

Most projects should keep the default HTTP/1.1 behavior. Enable HTTP/2 only when your service needs gRPC or another HTTP/2-only protocol.

For HTTP/2-enabled projects, Brimble expects your service to:

* Listen on the same `PORT` as the rest of your web traffic.
* Serve normal HTTP routes and gRPC routes from the same process.
* Accept cleartext HTTP/2, also called h2c, behind the Brimble gateway.
* Keep a lightweight HTTP health check route available, such as `GET /healthz`.

This single-port model lets one project handle both browser traffic and gRPC clients without exposing a second public port.

<Warning>
  Do not configure your container to terminate public TLS for Brimble traffic. Brimble terminates public TLS at the edge. Your service should listen for HTTP on `PORT`, including h2c when HTTP/2 is enabled.
</Warning>

## gRPC client behavior

External gRPC clients connect to your public Brimble hostname over TLS. Include `:443` in the address:

```text theme={null}
api.example.com:443
```

For example, in Go:

```go theme={null}
conn, err := grpc.Dial(
  "api.example.com:443",
  grpc.WithTransportCredentials(credentials.NewTLS(nil)),
)
```

Use the hostname and port as the dial target, not a path. The client should use normal gRPC over TLS. Inside Brimble, the gateway forwards the request to your service over the project transport selected for that deployment.

If you test from inside the same Brimble workspace, use the internal service hostname and the protocol your service exposes internally. Internal hostnames are not public and do not use public TLS. See [Internal networking](/networking/internal-services).

## Health checks

Brimble health checks for web services are HTTP GET requests. Even if your main API is gRPC, expose a simple HTTP endpoint for liveness:

```http theme={null}
GET /healthz HTTP/1.1
```

Return any 2xx or 3xx status when the service is ready to receive traffic. Keep this endpoint fast and independent of slow downstream services.

## Common issues

**The service works locally but returns 502 on Brimble.**

Check that it listens on `process.env.PORT` and binds to `0.0.0.0`.

**The app redirects to `http://` URLs.**

Your framework may not trust proxy headers. Configure it to respect `X-Forwarded-Proto: https`.

**gRPC requests fail but normal HTTP works.**

Confirm the project has HTTP/2 enabled, the client is dialing `your-domain.com:443` over TLS, and the service accepts h2c on the same port as the HTTP server. A separate gRPC-only port is not exposed publicly.

## Next steps

* [Request lifecycle](/networking/request-lifecycle), what happens before a request reaches your service.
* [Internal networking](/networking/internal-services), private service-to-service calls.
* [502 errors](/troubleshooting/502-errors), what to check when the gateway cannot reach your service.
