RailwayDocs

Private Networking

Private Networking is a feature within Railway that allows you to have a private network between your services, helpful for situations where you want to have a public gateway for your API but leave internal communication private.

Preview of What The Guide is Building

How it works

Under the hood, Railway uses encrypted Wireguard tunnels to create a private mesh network between all services within an environment. This allows traffic to route between services without exposing ports publicly.

By default, all projects have private networking enabled and services will get a DNS name under the railway.internal domain. For new environments (created after October 16, 2025), this DNS name will resolve to both internal IPv4 and IPv6 addresses. Legacy environments resolve to IPv6 only.

Internal DNS

Every service in a project and environment gets an internal DNS name under the railway.internal domain that resolves to the internal IP addresses of the service.

This allows communication between services in an environment without exposing any ports publicly. Any valid IPv6 or IPv4 traffic is allowed, including UDP, TCP, and HTTP.

For more details on internal DNS names, see the Domains guide.

Communicating over the private network

To communicate over the private network, there are some specific things to know to be successful.

Service configuration

We recommend configuring your application to listen on :: (all interfaces). This ensures your app works in both new (IPv4/IPv6) and legacy (IPv6-only) environments.

Some examples are below -

Node / Express

Listen on :: to bind to both IPv4 and IPv6.

Node / Nest

Listen on :: to bind to both IPv4 and IPv6.

Node / next

Update your start command to bind to both IPv4 and IPv6.

Or if you are using a custom server, set hostname to :: in the configuration object passed to the next() function.

If neither of these options are viable, you can set a HOSTNAME service variable with the value :: to listen on both IPv4 and IPv6.

Python / gunicorn

Update your start command to bind to both IPv4 and IPv6.

Python / hypercorn

Update your start command to bind to both IPv4 and IPv6.

Python / uvicorn

Update your start command to bind to both IPv4 and IPv6.

Rust / Axum

Listen on [::] to bind to both IPv4 and IPv6.

Use internal hostname and port

For applications making requests to a service over the private network, you should use the internal DNS name of the service, plus the PORT on which the service is listening.

For example, if you have a service called api listening on port 3000, and you want to communicate with it from another service, you would use api.railway.internal as the hostname and specify the port -

Note that you should use http in the address.

Using reference variables

Using reference variables, you can accomplish the same end as the above example.

Let's say you are setting up your frontend service to talk to the api service. In the frontend service, set the following variable -

Then in the frontend code, you will simply reference the BACKEND_URL environment variable -

Private network context

The private network exists in the context of a project and environment and is not accessible over the public internet. In other words -

  • A web application that makes client-side requests cannot communicate to another service over the private network.
  • Services in one project/environment cannot communicate with services in another project/environment over the private network.

Check out the FAQ section for more information.

Library-specific configuration

Some libraries and components require explicit configuration for dual-stack (IPv4/IPv6) networking or to work properly in legacy IPv6-only environments.

See the Library Configuration guide for detailed setup instructions for:

  • Node.js: ioredis, bullmq, hot-shots
  • Go: Fiber
  • Docker: MongoDB

Changing the service name for DNS

Within the service settings you can change the service name to which you refer, e.g. api-1.railway.internal -> api-2.railway.internal

The root of the domain, railway.internal, is static and cannot be changed.

Caveats

During the feature development process we found a few caveats that you should be aware of:

  • Private networking is not available during the build phase.
  • Private networking does not function between environments.
  • Legacy environments (created before October 16, 2025) only support IPv6. New environments support both IPv4 and IPv6.

Legacy environments

Environments created before October 16th, 2025 are considered legacy environments and only support IPv6 addressing for private networking.

If you want to utilize private networking in a legacy environment, you will need to configure your service to bind to :: (the IPv6 all-interfaces address). See the Service Configuration section for more information on configuring your listener. This will continue to work after your environment receives IPv4 support.

FAQ

Troubleshooting

Having issues with private networking? Check out the Troubleshooting guide or reach out on the Railway Discord.