This guide walks you through setting up Nginx and HAProxy as reverse proxies for WebSocket proxying, including handling both ws and wss connections. The example will use the GoLang WebSocket implementation.

Prerequisites:

To follow this guide, you’ll need:

  • A Linux server with sudo privileges
  • Nginx and HAProxy installed on the server
  • Go installed on the server

Part I: Setting up the Go WebSocket Server

Let’s start by creating a simple WebSocket server in Go. This example uses the gorilla/websocket package, which you can install with go get.

package main

import (
	"fmt"
	"net/http"

	"github.com/gorilla/websocket"
)

var upgrader = websocket.Upgrader{
	CheckOrigin: func(r *http.Request) bool {
		return true
	},
}

func handleConnections(w http.ResponseWriter, r *http.Request) {
	// Upgrade initial GET request to a websocket
	ws, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		fmt.Println(err)
		return
	}
	defer ws.Close()

	// Simple echo back
	for {
		// Read in a new message as JSON and map it to a Message object
		var msg string
		err := ws.ReadJSON(&msg)
		if err != nil {
			fmt.Println(err)
			break
		}
		fmt.Println("Received:", msg)
		err = ws.WriteJSON("Echo: " + msg)
		if err != nil {
			fmt.Println(err)
			break
		}
	}
}

func main() {
	http.HandleFunc("/ws", handleConnections)
	err := http.ListenAndServe(":8080", nil)
	if err != nil {
		fmt.Println("Failed to start server:", err)
		return
	}
}

This code creates a simple WebSocket server that echoes any message it receives. Save this file as main.go.

To start your WebSocket server, use the go run command:

go run main.go

Your server is now listening on port 8080. Test it using a WebSocket client by connecting to ws://your-server-ip:8080/ws.

Part II: Setting up Nginx

First, we will configure Nginx as a reverse proxy for the WebSocket connections.

Update the Nginx configuration file, usually found at /etc/nginx/nginx.conf or /etc/nginx/sites-available/default, and add a new server block for your WebSocket server:

http {
    map $http_upgrade $connection_upgrade {
        default upgrade;
        '' close;
    }

    server {
        listen 80;

        location /ws {
            proxy_pass http://localhost:8080;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $connection_upgrade;
            proxy_read_timeout 86400;
        }
    }
}

This configuration tells Nginx to pass any requests at http://your-server-ip/ws to your WebSocket server at localhost:8080. The Upgrade and Connection headers allow the WebSocket protocol to function correctly. The proxy_read_timeout is set to a day to prevent Nginx from closing the connection prematurely.

After updating the configuration, verify it with the following:

sudo nginx -t

If the configuration is correct, reload Nginx:

sudo systemctl reload nginx

You can now connect to your WebSocket server through Nginx at ws://your-server-ip/ws.

Part III: Enabling SSL for wss connections

You must enable SSL on your server for wss (WebSocket Secure) connections. You can get a free SSL certificate from Let’s Encrypt. Install the Certbot software and get a certificate:

sudo apt-get install certbot python-certbot-nginx
sudo certbot --nginx -d your-domain.com

This will automatically update your Nginx configuration to handle HTTPS connections and set up a cron job to renew the certificate automatically.

After installing the SSL certificate, you can connect securely to your WebSocket server at wss://your-server-ip/ws.

Part IV: Setting up HAProxy

HAProxy can also act as a reverse proxy for WebSocket connections. This can be useful for load balancing, failover, and other advanced scenarios.

To use HAProxy, first, install it:

sudo apt-get install haproxy

Update the HAProxy configuration file, usually found at /etc/haproxy/haproxy.cfg, and add a new frontend and backend for your WebSocket server:

frontend http_front
   bind *:80
   default_backend ws_back

backend ws_back
   balance roundrobin
   server ws1 localhost:8080 check

This configuration tells HAProxy to listen on port 80 and to balance the load between the servers listed in the ws_back backend. In this case, there’s only one server: localhost:8080.

After updating the configuration, check it with the following command:

sudo haproxy -c -f /etc/haproxy/haproxy.cfg

If the configuration is correct, restart HAProxy:

sudo systemctl restart haproxy

You can now connect to your WebSocket server through HAProxy at ws://your-server-ip/ws.

Part V: Enabling SSL for HAProxy

Like with Nginx, you must enable SSL on HAProxy to handle wss connections. You can reuse the same certificate that you got for Nginx. Add a new bind directive in your frontend part with the path to the certificate and private key:

frontend http_front
   bind *:80
   bind *:443 ssl crt /etc/letsencrypt/live/your-domain.com/fullchain.pem  privkey /etc/letsencrypt/live/your-domain.com/privkey.pem
   default_backend ws_back

After updating the configuration, check it and restart HAProxy as before.

You can now connect securely to your WebSocket server through HAProxy at wss://your-server-ip/ws.

Conclusion

This guide showed you how to set up Nginx and HAProxy as reverse proxies for WebSocket proxying and how to enable both ws and wss connections. This setup can help serve WebSocket connections from a Go server, with the added benefits of SSL security and load balancing.