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.
By default, all projects have private networking enabled and services will get a new DNS name under the
railway.internal domain. This DNS name will resolve to the internal IPv6 address of the services within a project.
To communicate over the private network, there are some specific things to know to be successful.
Since the private network is an IPv6 network, applications that will receive requests over the private network must be configured to listen on IPv6. On most web frameworks, you can do this via
:: and specifying the port(s) to which you want to bind.
For example -
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 -
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.
Some libraries and components require you to be explicit when either listening or establishing a connection over IPv6.
ioredis is a Redis client for node.js, commonly used for connecting to Redis from a node application. When initializing a Redis client using
ioredis, you must specify
family=0 in the connection string to support connecting to both IPv6 and IPv4 connections:
Mongo Docker image
If you are creating a service using the official Mongo Docker image in Docker Hub and would like to connect to it over the private network, you must start the container with some options to instruct the Mongo instance to listen on IPv6. For example, this would be set in your Start Command:
Note that the official template provided by Railway is already deployed with this Start Command.
hot-shots is a StatsD client for node.js, which can be used to ship metrics to a DataDog agent for example. When initializing a StatsD client using
hot-shots, you must specify that it should connect over IPv6:
fiber is a web framework for Go. When configuring your Fiber app, you should set the Network field to
tcp to have it listen on IPv6 as well as IPv4:
Within the service settings you can change the service name to which you refer, e.g.
The root of the domain,
railway.internal, is static and cannot be changed.
During private networking initialization (the period under 100ms), DNS resolution is handled via a fallback DNS server 18.104.22.168 in the container DNS config.
In Alpine-based images, due to how DNS resolution is handled, if that public DNS server's response is faster than the private networking DNS, it causes private resolution to fail.
You can workaround this issue by adding
ENABLE_ALPINE_PRIVATE_NETWORKING=true in your service environment variables.
This will effectively remove the fallback DNS server 22.214.171.124 which is used during the private networking 100ms initialization period.
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.
- You will need to establish a wireguard tunnel to external services if you wish to vendor requests in your application.
- You will need to bind to a IPv6 port to receive traffic on the private network.
- Private networking is enabled automatically for new projects/environments. If you want to use private networking in an existing environment, you will have to enable it manually in the settings panel of one of the environment services.
- Private networks take 100ms to initialize on deploy, we ask that you set initial requests on a retry loop.
- We don't support IPv4 private networking
- Alpine-based images may not work with our internal DNS due to how it performs resolution. See the section above for a workaround.
What is a client side app, a sever side app, and what kind of app am I running?
In the context of private networking, the key distinction between client- and server-side is from where requests are being made.
- In client-side applications, requests to other resources (like other Railway services) are made from a browser, which exists on the public network and outside the private network.
- In server-side applications, requests to other resources are made from the server hosting the application, which would exist within the private network (assuming the server hosting the app is in Railway).
One way to determine whether your application is making client- or server-side requests is by inspecting the request in the Network tab of DevTools. If the RequestURL is the resource to which the request is being made, e.g. a backend server, this is a good indication that the browser itself is making the request (client-side).
What if I am making a request server-side, but from Vercel?
Since an application hosted on Vercel exists outside of the private network in Railway, requests coming from Vercel servers cannot be made over the private network.
Edit this file on GitHub