WebSocket Proxy Setup#

When using CloudXR.js with HTTPS hosting (for development or production), you need a WebSocket proxy with TLS support to establish secure connections from the browser to the CloudXR Runtime.

Overview#

A WebSocket proxy is required when:

  • Hosting your web application using HTTPS

  • Deploying to production environments with SSL certificates

  • Accessing CloudXR from remote networks or the internet

  • Using Pico 4 Ultra devices (which require HTTPS)

The proxy acts as a secure gateway, providing TLS termination for WebSocket connections.

Connection Architecture#

Without proxy (HTTP mode):

Browser →
ws://<server>:49100
CloudXR Runtime

With proxy (HTTPS mode):

Browser →
wss://<proxy>:48322 →
CloudXR Runtime (ws://localhost:49100)

Important

When hosting your web application using HTTPS, you must configure a WebSocket proxy and connect using wss://. Browsers block non-secure WebSocket (ws://) connections from secure (HTTPS) pages due to mixed content security policies.

Available Proxy Examples#

CloudXR.js supports the following common deployment scenarios:

Deployment Scenario

Example Solution

Setup Complexity

Local development with HTTP

No proxy needed (direct ws:// connection)

None

Development/testing with HTTPS

Docker + HAProxy example

Low

Single-server production

Docker + HAProxy example

Low

Kubernetes production

nginx Ingress example

Medium

Example 1: Development Proxy (Docker + HAProxy)#

This example uses HAProxy in a Docker container for HTTPS development and single-server deployments.

Quick Start#

  1. Build the proxy image:

    cd proxy
    docker build -t cloudxr-wss-proxy .
    
  2. Run the proxy:

    docker run -d --name wss-proxy \
      --network host \
      -e BACKEND_HOST=localhost \
      -e BACKEND_PORT=49100 \
      -e PROXY_PORT=48322 \
      cloudxr-wss-proxy
    
  3. View logs:

    docker logs -f wss-proxy
    

Configuration Options#

Variable

Default

Description

BACKEND_HOST

localhost

CloudXR Runtime hostname or IP.

BACKEND_PORT

49100

CloudXR Runtime WebSocket signaling port.

PROXY_PORT

48322

TLS proxy listening port.

HEALTH_CHECK_INTERVAL

2s

Time between backend health checks.

HEALTH_CHECK_RISE

2

Consecutive successful checks to mark backend up.

HEALTH_CHECK_FALL

3

Consecutive failed checks to mark backend down.

Using Custom Certificates#

If you have your own TLS certificate, combine certificate and key into a PEM and mount it:

cat your-cert.crt your-key.key > server.pem
docker run -d --name wss-proxy \
  --network host \
  -v /path/to/server.pem:/usr/local/etc/haproxy/certs/server.pem:ro \
  -e BACKEND_HOST=localhost \
  -e BACKEND_PORT=49100 \
  -e PROXY_PORT=48322 \
  cloudxr-wss-proxy

Managing the Proxy#

docker stop wss-proxy
docker start wss-proxy
docker stop wss-proxy
docker rm wss-proxy
docker stop wss-proxy
docker rm wss-proxy
docker volume rm cloudxr-proxy-certs

Note

To persist self-signed certificates across container restarts, mount a Docker volume: -v cloudxr-proxy-certs:/usr/local/etc/haproxy/certs.

Common Issues#

  • Connection refused at startup: Expected while CloudXR Runtime is still initializing.

  • Certificate warnings: Trust the proxy certificate on the headset/browser before connecting.

  • Firewall blocking: Ensure proxy TCP port (default 48322) is open.

Example 2: Production Proxy (Kubernetes + nginx)#

For Kubernetes deployments, use nginx Ingress with TLS termination and WebSocket routing.

Typical setup flow:

  1. Create TLS secret.

  2. Deploy nginx proxy service/config.

  3. Configure Ingress for HTTPS + WebSocket traffic.

  4. Validate endpoint, then connect clients using wss://.

For CloudXR.js path-based proxy routing behavior, see Session API.

Firewall Configuration#

Refer to Ports and Firewalls for required ports and firewall configuration instructions.