Static outbound IP — all outbound TCP failing
srjohnson589
PROOP

10 days ago

Our service has a static outbound IP configured but all outbound TCP is failing.

Confirmed symptoms:

  • DNS resolution succeeds
  • All outbound TCP times out — tested port 1433 to an external SQL server and port 443 to api.ipify.org, checkip.amazonaws.com, and icanhazip.com
  • Cannot determine our actual egress IP from inside the container

Service:Centauri Vehicle API - both dev and staging environments

Static outbound IP shown in dashboard:34.168.253.122 (for both dev and staging)

Our live service in a different region works correctly with the same configuration. This service has been redeployed since enabling the static outbound IP.

Is the static outbound IP for this service active and routing traffic?

Solved$20 Bounty

Pinned Solution

Does disabling Static IP then redeploying fix the issue?

14 Replies

Status changed to Awaiting Railway Response Railway 10 days ago


Railway
BOT

10 days 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 10 days ago


Does curl -4 ifconfig.me work?


0x5b62656e5d

Does `curl -4 ifconfig.me` work?

srjohnson589
PROOP

9 days ago

railway shell runs locally, not in the container. And if outbound TCP is broken, curl would timeout anyway.

We'd need to either add a temporary endpoint to the running service that executes it, or ask Railway support if they have a way to exec directly into a running container on their end.


curl via SSH.


0x5b62656e5d

`curl` via SSH.

srjohnson589
PROOP

9 days ago

Sorry, I'm unfamiliar how to get inside the live container that is running - I think I need support for how to do that? I do not see a live shell I could access in my project. It is a NestJS API deployed via Dockerfile


srjohnson589
PROOP

9 days ago

The results of these functions from within the container:

public async testConnection(): Promise<void> {
    const { host, port } = this.connectionConfig;

    // DNS resolution check — confirms the hostname resolves and flags unexpected private IPs
    // (relevant when SQL Server is behind VPN, split DNS, or Azure private endpoints)
    try {
      const addresses = await dns.promises.lookup(host, { all: true });
      const ips = addresses.map((a) => a.address);
      this.log.log('DNS resolution succeeded', { host, resolvedAddresses: ips });   // THIS IS SUCCEEDING
      for (const ip of ips) {
        if (isPrivateIp(ip)) {
          this.log.warn('Resolved to private/internal address — VPN or private endpoint required to reach this host', { host, ip });
        }
      }
    } catch (err: unknown) {
      const e = err as NodeJS.ErrnoException;
      this.log.error('DNS resolution failed — hostname may not exist or DNS is misconfigured', { host, error: e.message, code: e.code });
    }

    await new Promise<void>((resolve) => {
      const socket = new net.Socket();
      socket.setTimeout(10_000);
      socket.connect(port, host, () => {
        this.log.log('TCP connection test succeeded', { host, port });
        socket.destroy();
        resolve();
      });
      socket.on('timeout', () => {
        this.log.error('TCP connection test timed out — traffic may not be reaching the server', { host, port }); // THIS IS TIMING OUT
        socket.destroy();
        resolve();
      });
      socket.on('error', (err: NodeJS.ErrnoException) => {
        this.log.error('TCP connection test failed', { host, port, error: err.message, code: err.code });
        socket.destroy();
        resolve();
      });
    });

    const tmpFile = `/tmp/bcp-conn-test-${Date.now()}.csv`;
    const command = formatBCPCommand({
      connection: this.connectionConfig,
      outFile: tmpFile,
      query: 'SELECT 1',
    });

    try {
      const result = await exec(command, { failOnStderr: false });
      this.log.log('BCP connection test succeeded', {
        host,
        port,
        stdout: result.stdout,
        stderr: result.stderr,
      });
    } catch (e: unknown) {
      const err = e as { stderr?: string; stdout?: string };
      this.log.error('BCP connection test failed', { // THIS IS FAILING
        host,
        port,
        stderr: err.stderr,
        stdout: err.stdout,
      });
    } finally {
      try {
        await unlink(tmpFile);
      } catch {}
    }
  }

srjohnson589

Sorry, I'm unfamiliar how to get inside the live container that is running - I think I need support for how to do that? I do not see a live shell I could access in my project. It is a NestJS API deployed via Dockerfile

Right click your service > Copy SSH Command, then run the command locally.


srjohnson589

The results of these functions from within the container: ```typescript public async testConnection(): Promise<void> { const { host, port } = this.connectionConfig; // DNS resolution check — confirms the hostname resolves and flags unexpected private IPs // (relevant when SQL Server is behind VPN, split DNS, or Azure private endpoints) try { const addresses = await dns.promises.lookup(host, { all: true }); const ips = addresses.map((a) => a.address); this.log.log('DNS resolution succeeded', { host, resolvedAddresses: ips }); // THIS IS SUCCEEDING for (const ip of ips) { if (isPrivateIp(ip)) { this.log.warn('Resolved to private/internal address — VPN or private endpoint required to reach this host', { host, ip }); } } } catch (err: unknown) { const e = err as NodeJS.ErrnoException; this.log.error('DNS resolution failed — hostname may not exist or DNS is misconfigured', { host, error: e.message, code: e.code }); } await new Promise<void>((resolve) => { const socket = new net.Socket(); socket.setTimeout(10_000); socket.connect(port, host, () => { this.log.log('TCP connection test succeeded', { host, port }); socket.destroy(); resolve(); }); socket.on('timeout', () => { this.log.error('TCP connection test timed out — traffic may not be reaching the server', { host, port }); // THIS IS TIMING OUT socket.destroy(); resolve(); }); socket.on('error', (err: NodeJS.ErrnoException) => { this.log.error('TCP connection test failed', { host, port, error: err.message, code: err.code }); socket.destroy(); resolve(); }); }); const tmpFile = `/tmp/bcp-conn-test-${Date.now()}.csv`; const command = formatBCPCommand({ connection: this.connectionConfig, outFile: tmpFile, query: 'SELECT 1', }); try { const result = await exec(command, { failOnStderr: false }); this.log.log('BCP connection test succeeded', { host, port, stdout: result.stdout, stderr: result.stderr, }); } catch (e: unknown) { const err = e as { stderr?: string; stdout?: string }; this.log.error('BCP connection test failed', { // THIS IS FAILING host, port, stderr: err.stderr, stdout: err.stdout, }); } finally { try { await unlink(tmpFile); } catch {} } } ```

I’d suggest just fetching the URLs instead.


srjohnson589
PROOP

9 days ago

Woo! I got in via SSH! I had to upgrade my railway CLI as I had an old version. Thank you for that tip, this will be so helpful in the future.

Ok these are both hanging

root@fddd56e9fbd7:/home/node/app# curl -4 ifconfig.me

^C

root@fddd56e9fbd7:/home/node/app# curl whatismyip.akamai.com echo

^C

root@fddd56e9fbd7:/home/node/app#


srjohnson589

Woo! I got in via SSH! I had to upgrade my railway CLI as I had an old version. Thank you for that tip, this will be so helpful in the future. Ok these are both hanging root@fddd56e9fbd7:/home/node/app# curl -4 [ifconfig.me](http://ifconfig.me) ^C root@fddd56e9fbd7:/home/node/app# curl [whatismyip.akamai.com](http://whatismyip.akamai.com) echo ^C root@fddd56e9fbd7:/home/node/app#

Are you able to run curl -I google.com?


0x5b62656e5d

Are you able to run `curl -I google.com`?

srjohnson589
PROOP

9 days ago

Just hangs


Does disabling Static IP then redeploying fix the issue?


0x5b62656e5d

Does disabling Static IP then redeploying fix the issue?

srjohnson589
PROOP

9 days ago

I mean, it is essential that we do have an Static Outbound IP in order to be whitelisted by our client's database. I can try that, and then would you suggest re-enabling and redeploy, in order to get it back?


srjohnson589
PROOP

9 days ago

Ok, disabling Static IP fixes curl -I google.com (so I can get out of the container now)

root@945e770bb7ca:/home/node/app# curl -I google.com

HTTP/1.1 301 Moved Permanently

Location: http://www.google.com/

Content-Type: text/html; charset=UTF-8

Content-Security-Policy-Report-Only: object-src 'none';base-uri 'self';script-src 'nonce-x3d7IuL4hQqHmOtyEHJSMA' 'strict-dynamic' 'report-sample' 'unsafe-eval' 'unsafe-inline' https: http:;report-uri https://csp.withgoogle.com/csp/gws/other-hp

Date: Wed, 13 May 2026 13:42:09 GMT

Expires: Fri, 12 Jun 2026 13:42:09 GMT

Cache-Control: public, max-age=2592000

Server: gws

Content-Length: 219

X-XSS-Protection: 0

X-Frame-Options: SAMEORIGIN

I will re-enable Static IP and see what happens.


srjohnson589
PROOP

9 days ago

Awesome. I'm able to get out again. Thank you.

"Turn it off and turn it back on" - works every time, haha. Thank you very much @0x5b62656e5d! Appreciate you.


Status changed to Solved brody 9 days ago


Welcome!

Sign in to your Railway account to join the conversation.

Loading...