Skip to content

Private Networking

Not every service should be on the public internet. Watasu lets one app expose private TCP services and another app reach them — without DNS, certificates, or VPC plumbing.

Any process whose name ends in -tcp is a private TCP service:

web: bundle exec puma
grpc-tcp: bundle exec grpc_server

grpc-tcp is reachable from inside your team’s runtime, but not from the public internet. There’s no public DNS name and no TLS certificate — it’s a raw TCP endpoint exposed to other apps that you explicitly trust.

The process listens on $PORT like any other, and trusted apps reach it at the internal hostname <app>-<process> — for the example above, my-app-grpc-tcp.

Common uses:

  • internal gRPC service consumed by a public API
  • private job intake for a worker fleet
  • admin-only RPC between control and data planes
  • microservice-to-microservice calls within a team

The app that exposes a *-tcp service decides who can reach it. It keeps a trust list of sibling apps; only the apps on that list can connect.

To let api-app (and billing-app) reach the *-tcp services of grpc-app:

Terminal window
watasu apps:trust api-app,billing-app --app grpc-app

Run it without arguments to see the current list, or with --clear to revoke everyone:

Terminal window
watasu apps:trust --app grpc-app
watasu apps:trust --clear --app grpc-app

Trust is directional — being on grpc-app’s list lets you call grpc-app; it gives grpc-app no access in return.

Use this rule:

What you’re doingProcess name
Public HTTP/WebSocket trafficweb or *-web
Internal service-to-service traffic*-tcp (with explicit trust)
WebRTC / UDP / real-time*-rtc (see Real-Time and WebRTC)
Background work nothing calls intoany other name (typically worker)

The temptation to “just expose it on the public web with a hard-to-guess path” is real, but it’s a worse default. *-tcp is the same effort, narrower blast radius, and easier to reason about when an audit happens.

Watasu’s process model gives you most of what microservice deployments need without a service mesh:

  • Service discovery — apps in the same team find each other by app name
  • Network isolation*-tcp is private by default; trust opens the door explicitly
  • Independent scaling — each app scales its own pods, sizes, and replica counts
  • Independent deploys — each app has its own Git push, release, and rollback timeline

For most teams that’s enough. If you outgrow it, your container images are still standard containers — nothing here locks you into Watasu.

Watasu doesn’t run an open network. Every team gets its own isolated namespace with a default-deny posture:

DirectionDefaultAllowed by default
Inbound from other teamsDeniedNothing
Inbound from same teamDeniedOnly between apps with explicit trust grants
Outbound to the public internetAllowedDNS, HTTPS, and standard outbound traffic
Outbound to public Watasu hostnamesAllowedRe-enters via the platform’s public ingress

This means:

  • Your app can call external APIs (Stripe, OpenAI, etc.) without configuration.
  • Two apps in your own team can’t reach each other unless you explicitly grant trust.
  • Two apps in different teams can never reach each other directly.

If app A needs to call app B’s *-tcp service: add A to B’s trust list with watasu apps:trust A --app B.

If app A needs to call app B’s public HTTPS URL (e.g. a webhook): just use the public hostname (app-b.watasuhost.com or your custom domain). The request leaves the cluster via the public egress, then re-enters via the platform’s ingress — same as if it came from outside. No trust grant needed.

It doesn’t replace authentication. Trust controls reachability; your app still needs to authorize callers (e.g. mTLS, signed tokens, shared secrets) for anything sensitive.