Private Networking
Services in the same project communicate over a private cluster network using stable internal hostnames, no public internet exposure required.
How it works
Every service and database you deploy gets a private hostname in the .internal DNS zone. This hostname resolves to a stable ClusterIP address that is only accessible within the same project's network. Traffic between services never leaves the cluster.
Internal hostname format
[service-name].internal
The service name is the name you gave the service when creating it in the dashboard. Spaces are replaced with hyphens and the name is lowercased.
# Web API service named "api" http://api.internal:8080 # PostgreSQL database named "postgres" postgresql://user:pass@postgres.internal:5432/dbname # Redis cache named "cache" redis://:password@cache.internal:6379 # Worker service named "background-worker" http://background-worker.internal:3000
Ports
The internal hostname resolves to whatever port(s) your service or database listens on:
- •Web services: the port defined in your service settings (default
8080) - •PostgreSQL:
5432 - •MySQL:
3306 - •Redis:
6379 - •MongoDB:
27017
Service-to-service communication
Internal requests don't go through the public load balancer or the Ingress controller, they travel directly between pods over the cluster network. This means:
- •Lower latency (typically < 1ms within a region)
- •No TLS overhead required (traffic is private to the cluster)
- •No egress costs
- •No firewall rules to configure
Example: API calling an internal worker
// Call a background worker service over the internal network
const response = await fetch('http://worker.internal:3000/process', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ jobId: '123', payload: data }),
})
const result = await response.json()Authentication on the internal network
Internal network access is not authenticated by default, any service in the same project can reach any other service by its internal hostname. If your services handle sensitive data, implement application-level authentication using a shared secret environment variable or mTLS.
// In your worker service, verify caller is legitimate
app.use('/internal', (req, res, next) => {
const secret = req.headers['x-internal-secret']
if (secret !== process.env.INTERNAL_API_SECRET) {
return res.status(403).json({ error: 'Forbidden' })
}
next()
})Tip
INTERNAL_API_SECRET as a shared environment variable to both the calling service and the worker. Rotate it from the dashboard when needed.Cross-project communication
The .internal DNS zone is scoped to a single project. Services in different projects cannot reach each other via internal hostnames.
If you need cross-project communication, the options are:
- •Public URL: call the service's public
stackblaze.cloudURL. Traffic goes through the load balancer and Ingress. Secure with API keys. - •VPC peering (Enterprise): connect two projects over a private network without internet exposure. Contact support to configure.
Don't use public URLs for database connections
Under the hood