This is a very simple HTTP echo server with support for websockets and server-sent events (SSE), available at https://echo-websocket.fly.dev/
The server is designed for testing HTTP proxies and clients. It echoes information about HTTP request headers and bodies back to the client.
# Clone and build
git clone https://github.com/ably/echo.websocket.org.git
cd echo.websocket.org
go build -o echo-server ./cmd/echo-server
# Run the server
./echo-server
# Test WebSocket connection
curl http://localhost:8080/.ws # Opens WebSocket test UI in browser
- Any messages sent from a websocket client are echoed as a websocket message.
- Visit
/.ws
in a browser for a basic UI to connect and send websocket messages. - Request
/.sse
to receive the echo response via server-sent events. - Request any other URL to receive the echo response in plain text.
The PORT
environment variable sets the server port, which defaults to 8080
.
Set the LOG_HTTP_HEADERS
environment variable to print request headers to
STDOUT
. Additionally, set the LOG_HTTP_BODY
environment variable to print
entire request bodies.
Set the SEND_SERVER_HOSTNAME
environment variable to false
to prevent the
server from responding with its hostname before echoing the request. The client
may send the X-Send-Server-Hostname
request header to true
or false
to
override this server-wide setting on a per-request basis.
Set the CONNECTION_TIMEOUT_MINUTES
environment variable to configure the maximum
duration for WebSocket and SSE connections. The default is 10 minutes. For backward
compatibility, WEBSOCKET_TIMEOUT_MINUTES
is still supported but deprecated.
For WebSocket connections: The timeout is absolute and NOT reset by client activity. Connections will be closed after the configured duration regardless of messages being sent or received. When the timeout is reached, the server sends a close frame with a message indicating the connection has been closed.
For SSE connections: The timeout is absolute from connection start. When the timeout is reached, the server sends an error event with the timeout message before closing the connection.
Set the SEND_HEADER_<header-name>
variable to send arbitrary additional
headers in the response. Underscores in the variable name are converted to
hyphens in the header. For example, the following environment variables can be
used to disable CORS:
SEND_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN="*"
SEND_HEADER_ACCESS_CONTROL_ALLOW_METHODS="*"
SEND_HEADER_ACCESS_CONTROL_ALLOW_HEADERS="*"
The server includes a comprehensive test suite covering HTTP echo, WebSocket, SSE, and timeout functionality.
# Run all tests
go test -v ./cmd/echo-server
# Run specific test pattern
go test -v ./cmd/echo-server -run TestWebSocket
# Run tests with custom timeout
go test -v ./cmd/echo-server -timeout 30s
# Run tests with coverage
go test -cover ./cmd/echo-server
The test suite includes:
- WebSocket and SSE echo functionality tests
- HTTP echo tests
- Connection timeout tests (verifying absolute timeout behavior)
- Configuration tests for environment variables
- Multiple concurrent client tests
Note: WebSocket connections timeout after the configured duration regardless of activity (absolute timeout, not idle timeout).
- Go 1.21 or later
- Git
- Clone the repository:
git clone https://github.com/ably/echo.websocket.org.git
cd echo.websocket.org
- Build the server:
go build -o echo-server ./cmd/echo-server
- Run the server:
# Default port 8080
./echo-server
# Custom port
PORT=10000 ./echo-server
# With connection timeout (in minutes)
CONNECTION_TIMEOUT_MINUTES=5 ./echo-server
- Build the Docker image:
# Build for your current platform
docker build -t echo-server .
# Build for multiple platforms (requires buildx)
docker buildx build --platform linux/amd64,linux/arm64 -t echo-server .
- Run the container:
# Run on port 8080
docker run -p 8080:8080 echo-server
# Run on custom port
docker run -p 10000:8080 -e PORT=8080 echo-server
# Run with custom timeout
docker run -p 8080:8080 -e CONNECTION_TIMEOUT_MINUTES=5 echo-server
This server is configured for deployment on Fly.io. The deployment uses a minimal Docker image built from scratch with just the Go binary.
Before deploying, you need to build the Linux binaries:
# Build Linux binaries for both architectures
mkdir -p artifacts/build/release/linux/amd64
mkdir -p artifacts/build/release/linux/arm64
GOOS=linux GOARCH=amd64 go build -o artifacts/build/release/linux/amd64/echo-server ./cmd/echo-server
GOOS=linux GOARCH=arm64 go build -o artifacts/build/release/linux/arm64/echo-server ./cmd/echo-server
# First time setup
fly launch
# Deploy updates (after building binaries)
fly deploy
The GitHub Actions workflow automatically deploys to Fly.io on every push to the main branch. The workflow:
- Runs tests to ensure code quality
- Builds Linux binaries for both amd64 and arm64 architectures
- Deploys using
flyctl deploy --remote-only
The deployment uses the Dockerfile which copies the platform-specific binary from artifacts/build/release/$TARGETPLATFORM/echo-server
to /bin/echo-server
in the container.
Note: The FLY_API_TOKEN
secret must be configured in the repository settings for automatic deployment to work.
This project is licensed under the MIT License - see LICENSE for details.
Originally forked from https://github.com/jmalloc/echo-server