2 months ago
I'm having an issue where my frontend web service does not seem able to resolve the internal URL for the api service. My code was using api.railway.internal, but that did not resolve. When I switched the public url, the code worked as expected.
Some things I've tried are shelling into the service and trying to resolve the internal urls there. In those cases, I get a ENOTFOUND api.railway.internal error. Working with the AI agent, I tried several approaches, but none resolved the issue and finally it suggested I reach out to support.
Unfortunately, my code is in a private GitHub repo, so I can't share it. However, the web service is a NextJS app that is trying to do a fetch against the api service. The public facing URL that web service is calling is:
https://api-production-6559.up.railway.app/api/v1/cms/health
Which does work, but the equivalent api.railway.internal does not.
Pinned Solution
2 months ago
I have resolved the issue. I believe in addition to the above note about enabling private networking (which, again, I swear wasn't there before), I hadn't disabled caching for the request I was making. Next was trying to resolve it at build time. I disabled that and it is now working.
11 Replies
2 months ago
This thread has been marked as public for community involvement, as it does not contain any sensitive or personal information. Any further activity in this thread will be visible to everyone.
Status changed to Open Railway • 2 months ago
2 months ago
api.railway.internal will only resolve if the services are communicating through Railway’s private networking DNS, and that hostname is not created automatically for every service.
In Railway the internal hostname is usually based on the service name, not the public subdomain. The correct internal URL typically looks like:
http://<service-name>.railway.internalor the full internal domain shown in the service settings.
You can find the correct internal address by going to:
Service → Settings → Private Networking
Railway usually shows something like:
your-service-name.railway.internalor
your-service-name.railway.internal:PORTThat is the hostname other services inside the same project should use.
Why api.railway.internal may not resolve
The name only works if:
- The actual service name is
api - Both services are in the same Railway project/environment
- Private networking is enabled
- The request is made server-side, not from the browser
Since your frontend is a Next.js app, another common issue is that the request runs on the client side. Browser code cannot access *.railway.internal because it only exists inside the Railway network.
So make sure the fetch call runs:
- in API routes
- in server actions
- or in getServerSideProps / server components
Example:
http://api-service-name.railway.internal:3000/api/v1/cms/healthnot from browser client code.
Quick test
From the frontend service shell, try:
curl http://<api-service-name>.railway.internal:<PORT>If that resolves, the internal DNS is working and the issue is likely that the request is happening on the client side instead of the server.
So in short:
*.railway.internalonly works inside Railway services- the hostname must match the actual service name
- requests must run server-side, not in the browser
Using the public URL works because it goes through Railway’s edge routing instead of the internal service network.
2 months ago
In response to your points:
- The NextJS app is making the request server-side. It is part of server-side rendering.
- A simple way I'm verifying that is by bringing up the dev tools and looking at the network panel. No request is made to the internal URL. (Or public when it is in use.)
- In addition, I see the error result rendered in the HTML returned with the request.
- According to the dashboard, the internal url is
api.railway.internal. - The services are all running in the same AWS region, if that affects anything.
Another way I'm trying to testing resolving the domain is by shelling into the web service and running Node code like this:
```
$ railway shell --service web
Entering subshell with Railway variables available. Type 'exit' to exit.
$ node
Welcome to Node.js v24.14.0.
Type ".help" for more information.
> const dns = require('dns').promises;
undefined
>
> (async () => {
| try {
| const result = await dns.resolve4('api.railway.internal');
| console.log('DNS resolved to:', result);
| } catch (err) {
| console.error('DNS error:', err.message);
| }
| })();
Promise {
,
Symbol(async_id_symbol): 112,
Symbol(trigger_async_id_symbol): 6
}
> DNS error: queryA ENOTFOUND api.railway.internal
```
I would think that in this case, I'm within the server context and should be able to resolve the DNS. I've done the same with a curl from the shell session:
$ curl http://api.railway.internal
curl: (6) Could not resolve host: api.railway.internalAre there other / better ways to try to verify if the issue is connectivity between the services or in my code?
2 months ago
You should add the port when using private networking. I just tested this on my (equally named api) service:
root@f8f11e209ca3:/app# curl http://api.railway.internal
curl: (7) Failed to connect to api.railway.internal port 80 after 1084 ms: Couldn't connect to server
root@f8f11e209ca3:/app# curl http://api.railway.internal:8080
{"detail":"Not Found"}
*Not the "Not found" is just because I don't have an endpoint at / but it is connecting.
2 months ago
Sorry just noticed you actually have a different error (not regarding port), ignore me. I use railway ssh if that changes anything.
2 months ago
Maybe in response to this thread, but I suddenly noticed a new button in the UI. I swear that wasn't there before...
I enabled that and also added a connectivity check as a predeployment step and that is resolving the internal url. However, my NextJS code is still not resolving, so I'll move my focus there. The railway shell also doesn't resolve the URL, however I'm getting the impression that isn't running the terminal session in the actual deployed environment, but just locally.
2 months ago
I have resolved the issue. I believe in addition to the above note about enabling private networking (which, again, I swear wasn't there before), I hadn't disabled caching for the request I was making. Next was trying to resolve it at build time. I disabled that and it is now working.
Status changed to Solved chandrika • 2 months ago
2 months ago
Hey there, glad you got this working 🙌 You're right that railway shell runs locally with Railway environment variables injected, not inside the deployed container, so private DNS won't resolve there (you'd want to use railway ssh if you want to shell into the actual running container
Status changed to Awaiting User Response Railway • 2 months ago
Status changed to Solved chandrika • 2 months ago
chandrika
Hey there, glad you got this working 🙌 You're right that `railway shell` runs locally with Railway environment variables injected, not inside the deployed container, so private DNS won't resolve there (you'd want to use `railway ssh` if you want to shell into the actual running container
2 months ago
Now that my production environment is up and running, I created a staging environment and I'm facing the same issue. Did I miss some step that enables private networking? There's no button to enable it here.
Attachments
Status changed to Awaiting Railway Response Railway • 2 months ago
2 months ago
Hi there, private networking is enabled by default for all environments, which is why there's no button. Your staging screenshot shows api.railway.internal as "Ready to talk privately" with IPv4 & IPv6, so the private network is already active.
You likely need to apply the same Next.js fetch caching fix from production - ensuring your fetch calls use { cache: 'no-store' } or equivalent so they resolve at runtime rather than build time.
Status changed to Awaiting User Response Railway • 2 months ago
2 months ago
I believe the issue was that API hadn't fully deployed yet and my connectivity check failed. I'm still very curious about that button I had to click earlier on my production environment. Anyway, all is well.
Status changed to Awaiting Railway Response Railway • 2 months ago
2 months ago
Glad it's sorted! If your production environment was old, the "Enable Private Networking" button was there likely due to that — this is now enabled by default so the buttons doesn't show up in newer environments.
Status changed to Awaiting User Response Railway • 2 months ago
Status changed to Solved chandrika • 2 months ago