# Networking and ports

## Public services

A public service answers at `https://{service}-{project}-{organization}.smartalfred.com`, with HTTPS. Add [your own domains](/docs/domains) too. Visitors reach the nearest server running it.

Other organizations' apps are on smartalfred.com too, so cookies aren't shared across it: a cookie your app sets with `Domain=smartalfred.com` is kept to its own address. To share cookies between your services, give them [your own domain](/docs/domains).

```diagram request
A visitor's request goes over HTTPS to Alf's edge, which holds your address, your domains and their certificates. From there it travels over the connection the nearest server running the service keeps open to Alf, so nothing on the internet connects in to the server. The server wakes the app if it's asleep, holding the request meanwhile, and passes it to the app's port in its own virtual machine. A public TCP or UDP port is the other way in: it skips the edge and goes straight to the server.
```

## Private services

Choose **Private** under the service's settings (or when creating it): it gets no address on the internet. The project's other services reach it as `name:port`, e.g. `db:5432`. Use this for databases, caches, queues and workers. A private service always runs, unless you let it [sleep](/docs/sleeping#private-services): then a call from the project's other services wakes it.

To reach a database from outside the project (from your laptop, or another platform), open a [public port](/docs/tcp-ports) for it (TCP or UDP): an address like `db-shop-acme.tcp.smartalfred.com:20431`, open only to the IP addresses you list.

## WebSockets

A public service's address takes WebSockets as it takes anything else: connect to
`wss://{service}-{project}-{organization}.smartalfred.com` and your app sees an ordinary upgrade.
Your own domains work the same way. Nothing has to be switched on.

A service with an open socket counts as in use, so it won't fall asleep underneath one. It can
sleep again once the last socket closes.

Two things worth knowing:

- The app has to accept the upgrade. If it answers with plain HTTP, the visitor gets a `502`
  instead of a socket that opens and shuts.
- Messages are passed whole, and very large ones (over about a megabyte) are refused. Send big
  things over HTTP and keep the socket for messages.

For a protocol that isn't HTTP or WebSocket — a database, a game server — open a
[public port](/docs/tcp-ports) instead.

## The project network

All services of a project share a private network:

- They reach each other by name (the service's short name, shown in the service's **Networking** tab), on whichever servers they run.
- Between servers, traffic goes through an encrypted WireGuard tunnel, set up by itself between any two servers that run the same project. The server program opens UDP port 51820 in the machine's own firewall for it. A firewall in front of the machine — a cloud provider's security group or security list — has to allow UDP 51820 too, on at least one of the two servers and ideally on both. If a server can't run WireGuard, or isn't connected to the others, the Servers page says so.
- Services in other projects, and the rest of the internet, can't reach them.
- A call to an app (any service that isn't a [database](/docs/databases)) goes through its server's front: a stable address the name resolves to. Its requests are kept with the ones from the internet (`alf requests api --from inside`), and an app that sleeps [wakes for it](/docs/sleeping#calls-from-inside-the-project). HTTP and gRPC are read request by request; anything else (TLS, a protocol of your own) passes through as it is. UDP goes straight to the container.
- The app sees the call coming from its server's address. For HTTP, `X-Forwarded-For` says which container called. Databases are reached at their containers directly, so they see their clients' own addresses.

```diagram project-network
Project shop runs on two servers, fsn-1 in Falkenstein and nbg-1 in Nuremberg. On fsn-1, web calls db:5432; on nbg-1, api calls db:5432 too, and a private worker runs. The two servers' parts of shop's network are joined by an encrypted WireGuard tunnel over UDP 51820, set up by itself, so the names work on whichever server a service runs. Another project's app on fsn-1 can't reach shop's services. A call to an app goes through its server's front, which keeps it with the app's requests and wakes the app if it sleeps; db, a database, is reached at its container directly.
```

## Ports

Your app listens on one port inside its container:

- Set **Port** on the service, or leave it empty: then the image's `EXPOSE` is used, or 8080.
- The app also gets the port as `PORT`, so apps that read it work anywhere.

If a deploy ends with "didn't open its port in time", the app listens on a different port than the service says. See [Troubleshooting](/docs/troubleshooting).
