docs/public-tcp.md
Rama main · réplica de lectura del repositorio original.
# Public TCP services
Self-hosted installations can forward public TCP connections unchanged through
the existing HAProxy ingress. An administrator must provision each external port
before an application can use it. Managed-cloud installations do not expose
public TCP; private TCP communication between services remains available.
An SMTP application owns its STARTTLS handshake and certificate. Hakopod's
`public = true` and `tls` fields still configure HTTP ingress; extra `ports`
remain private unless referenced by an explicit `public_tcp` listener.
```toml
schema_version = 1
name = "mail"
[services.smtp]
image = "registry.example.com/smtp@sha256:YOUR_VERIFIED_IMAGE_DIGEST"
port = 2525
public = false
size = "small"
replicas = 1
termination_grace_seconds = 60
[[services.smtp.public_tcp]]
port = 587
target_port = 2525
source_cidrs = ["0.0.0.0/0"]
```
`target_port` must match exactly one declared TCP container port (`port` or an
entry in `ports`). A primary `port` is required for workload readiness. If a
separate HTTP port provides the readiness check, configure `readiness` to require
the SMTP listener as well; HTTP health alone can miss a failed listener. See
[listener readiness](readiness.md) for TCP, SMTP and verified STARTTLS checks.
Hakopod resolves the target to the
corresponding private Kubernetes Service port. Public HTTP and TCP cannot target
the same backend port because HAProxy requires different backend modes. Use
distinct container ports. For restricted submission, replace `0.0.0.0/0` with
your allowed IPv4 CIDRs. Omission is rejected. Each service may declare sixteen
listeners, and an application may declare sixty-four; each listener accepts at
most sixteen CIDRs.
Source filtering uses the source observed by HAProxy. Upstream NAT or a proxy
can change that address. PROXY protocol and IPv6 exposure are not supported by
this initial profile.
## Operator setup
The server's `HAKOPOD_DEPLOYMENT_MODE` selects `self-hosted` (the default) or
`managed-cloud`. Its operator TOML equivalent is `[server] deployment_mode`.
This is an installation setting, not an application TOML field, dashboard
permission or license feature. A paid license does not enable public TCP in
managed-cloud mode. Self-hosted Hakopod can run on an AWS, GCP or Azure VM when
its administrator controls the ingress ports; the hosting provider's name does
not select the mode. This includes customer-owned BYOC installations. See
[product modes](product-modes.md) for the distinction from Hakopod Cloud.
In self-hosted mode, administrators may provision any available TCP port from
1 through 65535 except reserved platform ports. The installation allowlist holds
at most 256 ports. Enable only those needed with `HAKOPOD_PUBLIC_TCP_PORTS` (for
example, `587,12345`), or `[server] public_tcp_ports = [587, 12345]`. New installs
accept the JSON keys `deployment_mode` and `public_tcp_ports`; the interactive
installer asks for the mode and skips public TCP inputs in managed-cloud mode.
The installation must also provision matching TCP container and
Service ports on its owned HAProxy controller. A host installation uses matching
host ports. A NodePort or LoadBalancer service must use `externalTrafficPolicy:
Local` to preserve source addresses. NodePort exposes its assigned node port,
not necessarily the listener's port; the external load balancer or NAT must map
587 to it explicitly. Environment configuration alone never opens a port.
### Changing ports after installation
From the installer kit of the installed release, give the complete new list:
```sh
sudo python3 ./installer/modules.py public-tcp --ports 587,465
```
An empty `--ports ''` removes them all. The command checks the same limits as
the installer, refuses to remove a port an application still claims (its
`hakopod-tcp-port-PORT` reservation) and refuses a new port something on the
host already listens on. It then upgrades the `hakopod-ingress` release with the
new host ports, updates `HAKOPOD_PUBLIC_TCP_PORTS` in `/etc/hakopod/api.env` and
`/etc/hakopod/config.json`, and restarts the API. The HAProxy controller uses
the `Recreate` strategy, so HTTP ingress pauses briefly while it restarts.
Because `config.json` changes, installer `--resume` no longer applies to that
host; upgrades use maintenance as usual.
Allow the same port in the cloud security group, host firewall and any external
load balancer. Configure the DNS record to the public ingress address. Hakopod
does not change cloud firewalls automatically. Platforms without the HAProxy v3
TCP CRD, the owned ready deployment, source-preserving exposure, or the required
provisioned port fail preflight rather than silently creating a private listener.
Management ports and HTTP/HTTPS are reserved.
Managed-cloud mode rejects public TCP specifications and a nonempty public-port
allowlist. Before changing an existing server to that mode, remove its public
TCP listeners while it is still self-hosted and wait for successful removal.
Then clear the allowlist, change the mode and restart. Startup rejects remaining
managed TCP listeners or unacknowledged removals. Changing an environment
variable does not close host ports, alter cloud firewalls or retire an external
SMTP deployment.
The supported controller is HAProxy Technologies Kubernetes Ingress 3.2.15,
installed as `hakopod-ingress` in `haproxy-controller`, with one to eight ready
replicas. Larger deployments are rejected during preflight because runtime
reload inspection is bounded to eight ingress pods. TCP-services ConfigMaps and
custom namespace filters are incompatible with this owned ingress profile. Existing
v1 and v3 TCP resources are checked for port conflicts. Resource inventories are
bounded; excessive counts require operator review rather than a partial scan.
## Changes, failures and rollback
A port is reserved atomically to one application before its first deployment.
Reservations are durable ConfigMaps in the ingress namespace and survive failed
deployments, listener removal and application rollback. They prevent another
application from taking a port while a rollback is pending. To deliberately reuse
a port for another application, an operator must first retire the old revisions,
verify no matching TCP frontend remains, and remove that port's
`hakopod-tcp-port-PORT` ConfigMap. This is an explicit transfer, not an automatic
side effect of deleting a service.
Unchanged listeners stay available during readiness-gated rolling updates.
Changing a port's target or source CIDRs closes that listener before workloads
change; the new listener opens only after every desired workload is ready. These
changes can interrupt SMTP sessions. Runtime acknowledgement checks each owned
HAProxy pod's active process, generated bind, source restriction, backend and
active frontend. A failed or unacknowledged reload fails the operation. The
controller needs permission to execute a bounded read-only inspection inside
its owned ingress pods; no application receives that capability.
Connections use HAProxy's shared process and connection budget, with a per
frontend cap of 256 and a five-minute client inactivity timeout. Existing
installation backend timeouts and reload drain settings still apply. Long
sessions can be interrupted by those limits or application termination. Review
HAProxy timeouts and the application's termination grace period for your mail
server. No per-service proxy sidecar or extra ingress controller is started.
Observation reports `configured` only after the exact desired TCP resource has a
durable reload acknowledgement. Accepted resources awaiting a worker reload are
`pending`. An empty TCP resource records listener removal until it is
acknowledged, so a retry cannot reopen an old route accidentally. This status
is not a claim of internet reachability or SMTP correctness. Before cutting over
production, test from outside the cloud network: SMTP greeting, EHLO, STARTTLS,
certificate hostname and chain, authenticated delivery, disallowed sources,
rollback, and long-session behavior. Keep the existing SMTP deployment until
certificate mounts and AWS permissions have also passed their acceptance checks.
Public SMTP servers, SFTP and other custom public protocols belong on
self-hosted installations. Hakopod Cloud does not offer a shared SMTP gateway
or public TCP mappings. The raw TCP proxy assigns each public port to one
application; it does not route by hostname or SMTP recipient.