Railway Firewall is blocking HTML content

titusg
PRO

23 days ago

For the last couple of days I've been struggling to do something very trivial: put a reverse proxy in front of my web project.

[Caddy] ---> [NodeJS web project]

  • All requests were returning 502 bad gateway

  • I made sure my Node project was binding to "::" and "0.0.0.0" - same error, 502 bad gateway and timeout when I tried to access from Caddy

  • I switched to NGINX ---> Same issue

  • I wrote a simple reverse proxy ---> Same issue

  • I installed Tailscale and tried to curl [NodeJS web project] ---> same thing!

  • When I use a custom domain I am able to access the web project, but not through the internal network

So I wrote a very simple web server to debug.

  • The first endpoint "/" returns text and it's working.

  • The second endpoint "/html" returns HTML content and it's not working.

Did I miss something in the Railway docs? Is there a firewall blocking some content types like HTML? What am I doing wrong here?

package main

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"time"
)

func main() {
	port := os.Getenv("PORT")
	if port == "" {
		port = "8080"
	}

	host := os.Getenv("HOST")
	if host == "" {
		host = "0.0.0.0"
	}

	// Route: / - Plain text "Hello World"
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		// Only handle root path for this handler
		if r.URL.Path != "/" {
			http.NotFound(w, r)
			return
		}

		timestamp := time.Now().Format(time.RFC3339)

		// Log request
		log.Printf("[%s] %s %s from %s", timestamp, r.Method, r.URL.Path, r.RemoteAddr)
		log.Printf("Host: %s", r.Host)
		log.Printf("Headers: %v", r.Header)

		// Set response headers
		w.Header().Set("Content-Type", "text/plain")
		w.Header().Set("X-Server", "Go-Simple-Server")

		// Write plain text response
		fmt.Fprintf(w, "Hello World\n")
		log.Printf("[%s] Response sent: 200 OK (text/plain)", timestamp)
	})

	// Route: /html - HTML page with request info
	http.HandleFunc("/html", func(w http.ResponseWriter, r *http.Request) {
		timestamp := time.Now().Format(time.RFC3339)

		// Log request
		log.Printf("[%s] %s %s from %s", timestamp, r.Method, r.URL.Path, r.RemoteAddr)
		log.Printf("Host: %s", r.Host)
		log.Printf("Headers: %v", r.Header)

		// Set response headers
		w.Header().Set("Content-Type", "text/html; charset=utf-8")
		w.Header().Set("X-Server", "Go-Simple-Server")

		// Write HTML response
		html := `<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Go Test Server</title>
  <style>
    body {
      font-family: system-ui, -apple-system, sans-serif;
      max-width: 800px;
      margin: 50px auto;
      padding: 20px;
      background: #f5f5f5;
    }
    .container {
      background: white;
      padding: 30px;
      border-radius: 8px;
      box-shadow: 0 2px 4px rgba(0,0,0,0.1);
    }
    h1 { color: #2563eb; }
    .success { color: #16a34a; font-weight: bold; }
    .info {
      background: #eff6ff;
      padding: 15px;
      border-radius: 4px;
      margin: 15px 0;
    }
    pre {
      background: #1f2937;
      color: #f3f4f6;
      padding: 15px;
      border-radius: 4px;
      overflow-x: auto;
    }
  </style>
</head>
<body>
  <div class="container">
    <h1>โœ“ Go Test Server</h1>
    <p class="success">Server is responding correctly!</p>

    <div class="info">
      <strong>Request Info:</strong>
      <pre>Method: %s
Path: %s
Host: %s
Remote: %s
Time: %s</pre>
    </div>

    <div class="info">
      <strong>Server Info:</strong>
      <ul>
        <li>Language: Go</li>
        <li>Handler: net/http</li>
        <li>PID: %d</li>
      </ul>
    </div>
  </div>
</body>
</html>
`
		fmt.Fprintf(w, html, r.Method, r.URL.Path, r.Host, r.RemoteAddr, timestamp, os.Getpid())
		log.Printf("[%s] Response sent: 200 OK (text/html)", timestamp)
	})

	addr := fmt.Sprintf("%s:%s", host, port)

	log.Println("================================================================================")
	log.Println("[GO SERVER] Starting...")
	log.Printf("[INFO] Listening on http://%s", addr)
	log.Printf("[INFO] PID: %d", os.Getpid())
	log.Println("================================================================================")

	if err := http.ListenAndServe(addr, nil); err != nil {
		log.Fatalf("[ERROR] Server failed to start: %v", err)
	}
}

Solved

10 Replies

Railway
BOT

23 days ago


Railway
BOT

23 days ago

Hello!

We're acknowledging your issue and attaching a ticket to this thread.

We don't have an ETA for it, but, our engineering team will take a look and you will be updated as we update the ticket.

Please reply to this thread if you have any questions!


23 days ago

Hello,

This is not a firewall that is blocking HTML, the issue is with the beta IPv4 private networking feature you have enabled, sometimes the IPv4 private networking will cause packets to be dropped.

Please disable that flag, and then fully recreate the environment in a new project.

Best,
Brody


Status changed to Awaiting User Response Railway โ€ข 23 days ago


titusg
PRO

23 days ago

Hello,

Thanks for the quick response.

Please note that your support tool is deleting some messages.

It happened to me a couple of times, and other users are also reporting this behavior.

I posted a message just 1 hour after yours and I couldn't find it.


Status changed to Awaiting Railway Response Railway โ€ข 23 days ago


titusg
PRO

23 days ago

I created a new project: 81f749fc-6b7d-4701-9ad4-0810a35927e4

PROXY (Caddy) -----> WEBSITE (Astro)

The website is listening on 0.0.0.0:8080 (I also tried :: :8080) and can be accessed publicly on https://bantu-sites-staging.up.railway.app/ (it works)
For the proxy i'm using Caddy>

{

	admin off

	persist_config off

	auto_https off

	log {

		format json

	}

	servers {

		trusted_proxies static private_ranges

	}

}

:{$PORT} {

	log {

		format json

	}

	# Health check (bypass auth)

	handle /health {

		respond {"status":"UP"} 200

	}

	# Blog proxy - proxies all other paths to frontend

	handle {

		reverse_proxy {$FRONTEND_URL}

	}

}

In this case FRONTEND_URL is http://bantu-sites.railway.internal:8080
When I use the proxy https://bantu-front-gateway-production.up.railway.app/ I get a 502 error.

Here is my astro config:

// @ts-check
import node from "@astrojs/node";
import { defineConfig } from "astro/config";
// https://astro.build/config
export default defineConfig({
	output: "server",
	adapter: node({
		mode: "standalone",
	}),
	server: {
		host: "0.0.0.0",
		port: 8080,
	},
});

titusg
PRO

23 days ago

I set the env variable HOST="::" on the astro project and it's working now


titusg
PRO

23 days ago

I created a new environment in the same project after disabling the flag.
So far so good.


23 days ago

Glad to hear it is working for you now.


Status changed to Awaiting User Response Railway โ€ข 23 days ago


Status changed to Solved brody โ€ข 23 days ago


Railway
BOT

22 days ago

โœ… The ticket Packet loss in Private Networking has been marked as completed.


22 days ago

Hello,

Update here: The previously mentioned issues with IPv4 private networking have been fixed. However, you will need to redeploy the affected services.


Status changed to Awaiting User Response Railway โ€ข 22 days ago


Railway
BOT

8 days ago

This thread has been marked as solved automatically due to a lack of recent activity. Please re-open this thread or create a new one if you require further assistance. Thank you!

Status changed to Solved Railway โ€ข 8 days ago


Loading...
Railway Firewall is blocking HTML content - Railway Help Station