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

# Listeners

> Configure PostgreSQL listener ports and database credential injection.

For database connections, cordon can inject credentials at the wire protocol level. PostgreSQL listeners are configured as `[[listeners]]` entries, separate from HTTP [routes](/configuration/routes), with `port` for the local listener and `upstream` for the real database host and port.

Prefer [`cordon listener add`](/cli/listener#cordon-listener-add) and [`cordon listener edit`](/cli/listener#cordon-listener-edit) over hand-editing listener entries in `cordon.toml`. The CLI validates listener names, ports, TLS mode, and secret-source fields, and is meant as the safer way to produce this configuration. `upstream` is taken as-is and not format-checked at `add`/`edit` time — a malformed address (e.g. missing port) is only caught when `cordon start` tries to parse it. The TOML below is the reference format when you need to inspect, review, or automate outside the CLI.

## Listener structure

```toml theme={null}
[[listeners]]
name = "prod-db"
port = 15432
upstream = "db.prod.example.com:5432"
client_tls = "accept"

[listeners.auth]
type = "password"
username = "app_user"

[listeners.auth.secret]
source = "1password"
account = "my-team"
vault = "Engineering"
item = "Postgres Prod"
field = "password"
```

| Field           | Type    | Required | Description                                                                                   |
| --------------- | ------- | -------- | --------------------------------------------------------------------------------------------- |
| `name`          | string  | Yes      | Identifier for the listener. Route and listener names share one namespace and must be unique. |
| `port`          | integer | Yes      | Local port to listen on.                                                                      |
| `upstream`      | string  | Yes      | Upstream database host and port, such as `db.example.com:5432`.                               |
| `client_tls`    | string  | No       | Client-to-Cordon TLS mode: `accept` (default), `require`, or `disable`.                       |
| `auth.type`     | string  | Yes      | Auth type. Currently `password`.                                                              |
| `auth.username` | string  | Yes      | Username to authenticate as.                                                                  |
| `auth.secret`   | object  | Yes      | Secret source reference. See [Secret Sources](/configuration/secret-sources).                 |

Connect your application to `localhost:15432` instead of the upstream database. Cordon injects the password during the PostgreSQL authentication handshake.

Listener ports must be unique and cannot equal the HTTP proxy `listen` port.

## TLS behavior

`client_tls = "accept"` accepts PostgreSQL SSL requests when valid `tls.ca_cert_path` and `tls.ca_key_path` are configured, while still allowing plaintext clients. `client_tls = "require"` rejects plaintext startup packets and requires those CA paths. `client_tls = "disable"` declines SSL requests and keeps plaintext-only behavior. Omitted `client_tls` behaves as `accept`.

PostgreSQL client TLS uses the configured Cordon CA. Clients using `sslmode=verify-ca` or `sslmode=verify-full` must trust that CA. Cordon presents a loopback certificate for `localhost`, `127.0.0.1`, and `::1`; for `sslmode=verify-full`, connect to the local listener with one of those host identities.

Cordon always requires TLS on the Cordon-to-upstream PostgreSQL leg. It sends a PostgreSQL `SSLRequest` to the upstream server and completes TLS before sending startup or authentication data. If the upstream declines TLS or certificate verification fails, Cordon fails closed and does not send credentials.

## Upstream policy

PostgreSQL listener upstreams are configured trust decisions in v1, matching configured HTTP credential routes. Cordon resolves the upstream through the central resolver and connects to the selected `SocketAddr`, so DNS is pinned before the listener starts forwarding connections. Private, loopback, and link-local upstream policy will be revisited post-v1 in [#531](https://github.com/codezero-io/cordon/issues/531).
