Private networks and public endpoints
Connect selected services privately and publish only the endpoints you intend to expose.
Services in one application share a private network by default. A service named api listening on port 8080 can be reached by a peer as http://api:8080. This name is for server-to-server traffic inside the cluster. Browser code needs a public endpoint or a public service that proxies the request.
Separate local service groups#
Declare named networks and attach each service explicitly. Membership replaces the default network list. The following excerpts belong inside an application with complete service definitions:
[networks.frontend]
[networks.backend]
internal = true
[services.web]
networks = ["frontend", "backend"]
[services.api]
networks = ["backend"]
[services.api.network_access]
from = ["web"]
The web service can call the API because both share backend membership and the API permits that peer. The API has only internal membership, so ordinary external egress is denied while required DNS remains available. The web service still has external egress through frontend.
An omitted peer rule allows declared ports from shared-network members. from = [] denies local peers. Explicit public HTTP exposure is a separate path; a peer restriction does not remove that route.
Extra private ports#
[[services.api.ports]]
name = "metrics"
port = 9090
target_port = 9091
protocol = "TCP"
Peers connect to api:9090; the container must listen on 9091. Protocol can be TCP or UDP, and target_port defaults to port. These extra ports are private. They do not open host ports or cloud firewalls.
Connect separate applications#
Create a virtual network under Networks in the intended project and environment. A project administrator can import this complete network definition:
schema_version = 1
name = "commerce"
description = "Private commerce data services"
[segments.data]
applications = ["catalog", "database"]
The grant permits those applications to join the data segment. It does not connect every service automatically. Use Connect service, or add an internal application network with virtual_network = "commerce" and segment = "data", then attach only the intended services.
To restrict a database to one remote service, use an explicit peer block on its complete service configuration:
[services.postgres.network_access]
from = []
from_applications = ["catalog/api"]
Both peers must join the approved segment. Copy the actual private address from the network inspector. Names shared by development and production do not create a connection between them. Detach services and successfully deploy before removing a grant or deleting the network.
Custom domains and HTTPS#
Create the application first, then open Custom domains to verify ownership. Add verified names to the application configuration:
[domains]
"shop.example.com" = "web"
The destination service must expose HTTP. Names are lowercase DNS hostnames without a scheme, path or port. Wildcard application-domain mappings are not supported. DNS routing and certificate coverage are separate checks; a verified name is not evidence that its TLS certificate is ready.
Public TCP is an operator choice#
Self-hosted Free and licensed installations can expose additional TCP services using public_tcp. The administrator must first provision the ingress port and allow it on the server. The application cannot open arbitrary host ports. Source CIDRs and port reservations apply independently of HTTP domains.
Managed-cloud mode rejects public TCP regardless of team role or license. A hostname cannot route arbitrary TCP the way an HTTP Host header does. SMTP, SFTP and similar public protocols belong on dedicated self-hosted infrastructure.
These networks use Kubernetes NetworkPolicy on the documented IPv4 K3s model. They do not create encrypted tunnels, VPC peering or cross-cluster routing, and they are not a hostile-tenant security guarantee. See the complete network guide and public TCP policy.