WebSocket Handshake Succeeds but No Messages Received (Rust + Axum Service)
lcnewhook
PROOP

4 months ago

Hi Railway Support,

I’m running into an issue with a WebSocket service I’ve deployed on Railway. The initial handshake completes successfully, but no messages are coming through from the server to the client after the connection is established.

Service Info

  • Service Name:rust-matching-engine

  • URL:https://laureate-matching-engine.railway.app

  • WebSocket Endpoint:wss://laureate-matching-engine.railway.app/ws

  • Stack: Rust + Axum 0.7 + Tokio

  • Docker: Multi-stage build, based on Debian bookworm-slim

What I’m Seeing

Locally (everything works):bash # ws://localhost:3002/ws white_check_mark emoji Connects white_check_mark emoji Receives: {"type":"auth_required"} white_check_mark emoji Receives: {"type":"pong"} white_check_mark emoji Receives: {"type":"auth_failed",...}

On Railway (connection succeeds, but...):bash # wss://...railway.app/ws white_check_mark emoji Connects white_check_mark emoji TLS handshake succeeds x emoji No messages received at all x emoji No errors or warnings

Things I’ve Already Checked

  • white_check_mark emoji/health endpoint returns 200 — service is up

  • white_check_mark emoji WebSocket upgrade works — handshake completes

  • white_check_mark emoji Identical binary works fine locally

  • white_check_mark emoji Using Axum’s standard WebSocketUpgrade implementation

  • white_check_mark emojisend() calls succeed — logs confirm messages are being sent

  • white_check_mark emoji Explicit .flush() calls added — no effect

  • white_check_mark emoji Listening on 0.0.0.0:${PORT} — port binding is correct

Quick Test You Can Run

npm install ws jsonwebtoken

cat > test.js << 'EOF'
const WebSocket = require('ws');
const ws = new WebSocket('wss://laureate-matching-engine.railway.app/ws');

ws.on('open', () => {
  console.log('✅ Connected');
  ws.send(JSON.stringify({ type: 'ping' }));
});

ws.on('message', (data) => {
  console.log('📥 Received:', data.toString());
});

setTimeout(() => {
  console.log('❌ No messages received in 5 seconds');
  process.exit(1);
}, 5000);
EOF

node test.js

Expected:{"type":"auth_required"} should come back right after connect
Actual: Nothing is received

Core WebSocket Handler (Axum)

pub async fn websocket_handler(
    State(ws_server): State>,
    ws: WebSocketUpgrade,
    headers: HeaderMap,
) -> impl IntoResponse {
    info!("[WebSocket] Upgrade request received");
    ws.on_upgrade(move |socket| ws_server.handle_socket(socket))
}

self.send_message(&connection, WebSocketMessage::AuthRequired).await?;
conn.sender.send(Message::Text(json)).await?;
conn.sender.flush().await?;

A Few Questions

  1. Does Railway require any special config for WebSocket services?

  2. Is there any proxy buffering or header-related behavior that might block or delay messages?

  3. Are there known limitations or quirks with Axum + WebSockets on Railway?

  4. Can someone check the proxy logs on your end to see if messages are getting stuck?

Repo

Code is available here: https://github.com/lcnewhook/laureate

Relevant files: - backend/rust-engine/src/websocket.rs - backend/rust-engine/src/main.rs - backend/rust-engine/test-websocket-simple.js

This setup works flawlessly on my machine, but something seems to be going wrong when running behind Railway’s infra. Any help or pointers would be hugely appreciated!

Thanks again,
Lawrence Newhook

$10 Bounty

2 Replies

Railway
BOT

4 months ago

Hey there! We've found the following might help you get unblocked faster:

If you find the answer from one of these, please let us know by solving the thread!


yeeet
PRO

4 months ago

hey, railway supports websockets over HTTP/1.1 as stated in their docs so you might have to configure hyper/axum to use http1_only(true)

for axum, im not too familiar with it, but looking at rust's docs, you might have to split and continuously read the socket with a receive loop.

let me know if that worked out! if it didnt, can you drop the logs for the redeployment?


Loading...