Mastering SSE and WebSocket with Nginx: Complete Configuration Guide

This guide explains the differences between Server‑Sent Events and WebSocket, shows when to choose each technology, and provides step‑by‑step Nginx configuration snippets—including global mapping, SSE and WebSocket location blocks, troubleshooting tips, and a minimal debug setup—to ensure reliable real‑time communication in production.

Xiao Liu Lab
Xiao Liu Lab
Xiao Liu Lab
Mastering SSE and WebSocket with Nginx: Complete Configuration Guide

Why Real‑Time Communication Matters

In modern web applications, real‑time communication is essential. Developers can use Server‑Sent Events (SSE) for one‑way server pushes or WebSocket for full‑duplex channels, but incorrect Nginx settings often cause the classic “works locally, fails in production” problem.

SSE vs. WebSocket: Quick Comparison

Direction : SSE – server → client (one‑way); WebSocket – bidirectional.

Protocol base : SSE uses HTTP/1.1 with text/event-stream; WebSocket is a separate protocol upgraded via Upgrade: websocket.

Connection management : Browsers auto‑reconnect for SSE; WebSocket requires the application to handle reconnection.

Typical use cases : SSE – notifications, log streams, market data; WebSocket – chat, collaborative editing, online games.

💡 Recommendation: Use SSE when you only need to push data; choose WebSocket for interactive, two‑way communication.

Full Nginx Configuration (with Chinese comments)

Assume the backend service is reachable at http://127.0.0.1:8000.

Frontend routing conventions: Normal request: / SSE endpoint: /sse/… WebSocket endpoint: /ws/…

Step 1 – Global map for WebSocket upgrade

# Dynamically set Connection based on Upgrade header
# WebSocket request ($http_upgrade = "websocket") → "upgrade"
# Other requests → "close"
map $http_upgrade $connection_upgrade {
    default upgrade;   # default for WebSocket
    ''      close;     # empty value for normal HTTP
}

⚠️ This map directive must be placed inside the http {} block, not inside server or location.

Step 2 – Server block with detailed comments

server {
    listen 80;
    server_name your-domain.com;  # replace with your domain or IP

    # ── Normal API requests ──
    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    # ── SSE configuration (critical!) ──
    location ~ ^/sse/ {
        proxy_pass http://127.0.0.1:8000;
        proxy_http_version 1.1;          # SSE needs HTTP/1.1
        proxy_buffering off;              # disable buffering so events flow instantly
        proxy_cache off;                  # prevent caching of the event stream
        gzip off;                         # SSE cannot be gzipped
        proxy_set_header Connection '';
        proxy_read_timeout 3600s;         # long timeout for idle connections
        proxy_send_timeout 3600s;
        proxy_connect_timeout 3600s;
        proxy_set_header X-Accel-Buffering no;  # tell upstream not to buffer
        chunked_transfer_encoding on;    # enable chunked encoding
        # Optional CORS headers
        add_header 'Access-Control-Allow-Origin' '*' always;
        add_header 'Access-Control-Allow-Methods' 'GET, OPTIONS' always;
        add_header 'Access-Control-Allow-Headers' 'Origin,Authorization,Accept,X-Requested-With' always;
        if ($request_method = 'OPTIONS') {
            add_header 'Access-Control-Max-Age' 1728000;
            add_header 'Content-Length' 0;
            return 204;
        }
    }

    # ── WebSocket configuration (core is protocol upgrade) ──
    location ^~ /ws/ {
        proxy_pass http://127.0.0.1:8000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        # Optional auth header forwarding
        # proxy_set_header Authorization $http_authorization;
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 300s;   # 5‑minute idle timeout (adjust as needed)
        proxy_send_timeout 300s;
        proxy_connect_timeout 3600s;
    }
}

Alternative without map (set Connection directly):

proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

High‑Frequency Issue Checklist

SSE not connecting?

Verify proxy_buffering off; is present.

Ensure the backend returns Content-Type: text/event-stream.

Confirm gzip off; is set.

If multiple Nginx layers exist, each must have proxy_buffering off;.

WebSocket connection fails?

Check that both Upgrade and Connection headers are forwarded:

proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_http_version 1.1;

In browser dev tools, the request should show HTTP 101 status. Also increase proxy_read_timeout if the default 60 s is insufficient.

Minimal Viable Config (debugging)

SSE

location /sse {
    proxy_pass http://backend;
    proxy_buffering off;
    proxy_cache off;
    gzip off;
    proxy_set_header Connection '';
    proxy_http_version 1.1;
    proxy_read_timeout 3600s;
}

WebSocket

location /ws {
    proxy_pass http://backend;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_read_timeout 300s;
}

Applying the Changes

After editing the configuration, test and reload Nginx:

sudo nginx -t && sudo nginx -s reload
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

WebSocketreverse proxyserver configurationreal-time communicationSSE
Xiao Liu Lab
Written by

Xiao Liu Lab

An operations lab passionate about server tinkering 🔬 Sharing automation scripts, high-availability architecture, alert optimization, and incident reviews. Using technology to reduce overtime and experience to avoid major pitfalls. Follow me for easier, more reliable operations!

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.