When running both HTTP services (like PHP applications) and WebSocket servers (like Ratchet) on the same machine, port contention becomes inevitable. While WebSocket connections begin as HTTP requests before upgrading, they ultimately require different protocol handling than regular HTTP traffic.
The most robust approach involves configuring Nginx to:
http {
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
server_name example.com;
# Handle HTTP requests
location / {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
# Handle WebSocket connections
location /ws {
proxy_pass http://localhost:8081;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
}
}
}
The key components of this setup:
- Nginx listens on port 80 for all incoming traffic
- Regular HTTP requests get proxied to your PHP application (e.g., on port 8080)
- WebSocket connections (under /ws path) get routed to Ratchet (e.g., on port 8081)
Here's how to configure your Ratchet application:
run();
Regarding port blocking concerns:
- Port 80 is rarely blocked as it's essential for web traffic
- Even if internal ports (8080, 8081) are blocked, they're only used locally
- Corporate networks might block WebSocket, but this is protocol-level, not port-specific
For better reliability:
# In Nginx configuration
location /ws {
proxy_read_timeout 86400; # WebSocket connections can stay alive
proxy_send_timeout 86400;
proxy_connect_timeout 5;
proxy_buffering off;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
Verify with this JavaScript client code:
const socket = new WebSocket('ws://example.com/ws');
socket.onopen = function(e) {
console.log("Connection established");
socket.send("Test message");
};
socket.onmessage = function(event) {
console.log(Data received: ${event.data});
};
socket.onclose = function(event) {
console.log(Connection closed: ${event.code});
};
Essential security measures:
- Implement WSS (WebSocket Secure) with SSL certificates
- Add authentication at both Nginx and application levels
- Limit WebSocket frame size to prevent DoS attacks
- Implement rate limiting for WebSocket connections
When running both a traditional HTTP server (like PHP-FPM) and a WebSocket server (like Ratchet) on the same machine, port conflicts arise since both typically want to use port 80. Here's how to properly configure Nginx as a reverse proxy to handle both traffic types.
WebSocket connections begin as HTTP requests with an Upgrade
header. The handshake process:
GET /chat HTTP/1.1
Host: example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
Here's a complete Nginx configuration that routes both HTTP and WebSocket traffic through port 80:
server {
listen 80;
server_name example.com;
location / {
# Regular HTTP traffic
try_files $uri $uri/ /index.php?$query_string;
}
location /ws {
# WebSocket specific configuration
proxy_pass http://localhost:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
location ~ \.php$ {
# PHP processing
include fastcgi_params;
fastcgi_pass unix:/run/php/php7.4-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
- Your Ratchet server should listen on a different port (e.g., 8080)
- The
/ws
location block handles WebSocket upgrade requests - Standard HTTP traffic continues to be processed normally
For production environments, consider adding:
- SSL termination (port 443)
- Rate limiting for WebSocket connections
- IP-based access controls
Here's a basic Ratchet implementation that works with this setup:
run();