# Public TCP and UDP ports

HTTP services have an address and need nothing from this page. A **database**, a message broker, a game server or anything else that doesn't speak HTTP can't go through that address. To reach one from outside its project, open a **public port**, over TCP (databases, most things) or UDP (game servers, DNS, VPNs, media).

Inside the project nothing changes: other services keep reaching it as `name:port` (e.g. `db:5432`), and that stays the right way for your own apps.

## Open a port

**Service → Networking → Public ports → Open a port**:

1. **Port in the container**: the port the app listens on (5432 for Postgres), and **TCP** or **UDP**. Left empty, it's the service's port.
2. **Who may connect**: the IP addresses or ranges that get through, e.g. `203.0.113.7` or `198.51.100.0/24`. **Add my address** fills in yours. Everyone else is cut off before they reach the app.

You get an address like:

```
db-shop-acme.tcp.smartalfred.com:20431
```

Connect with that host and port:

```
psql "postgres://user:password@db-shop-acme.tcp.smartalfred.com:20431/mydb"
```

The port number is picked for you (between 20000 and 29999) and stays the same if the service moves to another server. Private services can have public ports too: they stay without a web address.

## How it reaches the server

HTTP goes through Alf's edge; a public port doesn't. Connections go **straight to the server** the service runs on, so:

- The name points at the IP address of the server the service runs on (visible to anyone who looks it up).
- The server's own firewall is opened for the port automatically.
- The firewall in front of Alf's servers lets the range for public ports through (TCP and UDP `20000-29999`).

**Test** next to a TCP port connects to it from outside and tells you which of the three it is: reachable, refused by the server, or blocked on the way.

```diagram tcp-port
psql on your laptop connects to db-shop-acme.tcp.smartalfred.com:20431. The name is the IP address of the server db runs on, and port 20431 is open in that server's own firewall. Only addresses on the port's allowlist get through; everyone else is turned away, and listed under Turned away lately. Then the connection, TCP or UDP, reaches port 5432 in db's container. HTTP goes through Alf's edge; a public port doesn't, and Alf adds no TLS: switch it on in the database.
```

## Who may connect

Every port has an allowlist, and it can't be empty.

- Change it any time under **Who may connect**. Connections from addresses you remove are cut at once.
- **Anyone on the internet** is a choice you make explicitly. Scanners find open databases within hours: only with a strong password, and switch on TLS in the database.
- The allowlist looks at the address a connection comes from. At home or in an office that's your router's public address, which can change.

### "Why can't I connect?"

Almost always: the address you connect from isn't the one on the list. Your computer can have two public addresses, an IPv4 and an IPv6 one, and the server sees the one of the kind it's reached over (usually IPv4), which may not be the one your browser uses.

So each port shows **Turned away lately**: the addresses that tried it without being on the list. Try to connect once, find your address there, and press **Allow**. Addresses you don't recognize are usually scanners: leave them out.

Traffic is as encrypted as the app makes it. Alf forwards the bytes and doesn't add TLS: enable it in your database (most clients then use it by default) if you connect over the internet.

## UDP

UDP ports work the same way: a port, an allowlist, the same name. What's different:

- UDP has no connections. A client is remembered while it sends or receives, and forgotten after two minutes of silence.
- **Test** can't check a UDP port (silence doesn't mean closed): try your app's own client, and look at **Turned away lately**.
- The address a UDP packet claims to come from can be faked, so the allowlist is weaker than with TCP. Don't rely on it alone for anything sensitive.
- The name contains "tcp" (`...tcp.smartalfred.com`); it's the same name for both.

## Your own domain

Create one DNS record at your domain's provider:

| Type | Name | Value |
| --- | --- | --- |
| CNAME | `db.example.com` | `db-shop-acme.tcp.smartalfred.com` |

DNS only (no proxy), and no certificate is involved. Then connect to `db.example.com:20431`: the port stays part of the address. If the service moves to another server, the name follows by itself.

## Good to know

- **Sleeping services** wake on the first connection and stay awake while one is open. Databases are usually private and always on anyway.
- **Several servers**: the name points at all of them, and each forwards to its own copy. For a database with a volume there's exactly one.
- **Deploys and updates**: connections are cut when the container is replaced, and for a moment when smartalfred-server updates itself. Clients with a connection pool reconnect by themselves.
- **Limits**: 5 public ports per service.
- Servers need an address that can be reached from the internet. One behind NAT without port forwarding can't offer public ports.
