gns3-server/docs/features/vnc-websocket-console.md
YueGuobin a2c1a913ca docs: add VNC WebSocket console documentation
Add comprehensive documentation for VNC WebSocket console support in GNS3.

Topics covered:
- Architecture and connection flow
- API endpoints (Controller and Compute)
- WebSocket data forwarding implementation
- Supported node types (QEMU and Docker)
- Authentication and authorization
- Configuration examples
- Troubleshooting guide
- Performance considerations
- Security best practices
- Comparison with SPICE

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-03-17 01:28:52 +08:00

15 KiB

VNC WebSocket Console

Overview

GNS3 server supports WebSocket-based VNC console access, enabling browser-based graphical console connections to QEMU and Docker VMs without requiring standalone VNC client applications.

This implementation uses GNS3's API layer as a transparent WebSocket-to-TCP proxy, forwarding binary VNC protocol data between the browser and the VM's VNC server.

Architecture

Connection Flow

┌─────────┐     WebSocket      ┌─────────────┐     HTTP/WS     ┌──────────┐
│ Browser │ ◄─────────────────► │   GNS3      │ ◄──────────────► │  GNS3    │
│ noVNC   │   (wss://port)      │  Controller │   (JWT + RBAC)   │ Compute  │
└─────────┘                     └─────────────┘                  └─────┬────┘
                                                                         │
                                                                         │ TCP
                                                                         │
                                                                    ┌────▼────┐
                                                                    │  QEMU   │
                                                                    │  VNC    │
                                                                    │ :5900   │
                                                                    └─────────┘

Components

  1. Browser (noVNC)

    • HTML5 VNC client running in the browser
    • Connects via WebSocket using binary subprotocol
    • Handles RFB protocol (Remote Frame Buffer) for VNC
  2. GNS3 Controller API

    • WebSocket endpoint: /v3/projects/{project_id}/nodes/{node_id}/console/vnc
    • Authentication: JWT token via query parameter
    • Authorization: RBAC privilege check (Node.Console)
    • Forwards WebSocket connections to compute node
  3. GNS3 Compute API

    • WebSocket endpoint: /v3/compute/projects/{project_id}/qemu/nodes/{node_id}/console/vnc
    • Authentication: HTTP Basic Auth
    • Transparent bidirectional binary forwarding
  4. Node (QEMU/Docker)

    • VNC server listening on configured port (default: 5900+)
    • RFB protocol for remote display

API Endpoints

Controller WebSocket Endpoint

URL: ws://{controller_host}:{port}/v3/projects/{project_id}/nodes/{node_id}/console/vnc?token={jwt_token}

Authentication:

  • JWT token via query parameter
  • User must have Node.Console privilege

WebSocket Subprotocols:

  • Accepts: binary
  • Used by noVNC for binary data transfer

Request Example:

const token = "eyJ0eXAiOiJKV1QiLCJhbGc...";
const wsUrl = `ws://localhost:3080/v3/projects/${projectId}/nodes/${nodeId}/console/vnc?token=${token}`;

const ws = new WebSocket(wsUrl, 'binary');
ws.binaryType = 'arraybuffer';

Compute WebSocket Endpoint

URL: ws://{compute_host}:{port}/v3/compute/projects/{project_id}/{node_type}/nodes/{node_id}/console/vnc

Authentication:

  • HTTP Basic Auth (controller credentials)
  • Configured via settings.Server.compute_username and settings.Server.compute_password

Response:

  • Bidirectional binary WebSocket connection
  • Transparent VNC protocol forwarding

Supported Node Types

QEMU VMs

Console Type Configuration:

{
  "console_type": "vnc",
  "console": 5900,
  "console_resolution": "1024x768"
}

QEMU Parameters:

-vnc :0  # VNC on display 0 (port = 5900 + display)

Implementation:

  • File: gns3server/api/routes/compute/qemu_nodes.py
  • Endpoint: /{node_id}/console/vnc
  • Method: start_vnc_websocket_console(websocket)

Docker Containers

Console Type Configuration:

{
  "console_type": "vnc",
  "console": 5900,
  "console_resolution": "1024x768",
  "console_http_port": 8080,
  "console_http_path": "/"
}

Implementation:

  • File: gns3server/api/routes/compute/docker_nodes.py
  • Endpoint: /{node_id}/console/vnc
  • Method: start_vnc_websocket_console(websocket)

WebSocket Data Forwarding

Implementation Details

Location: gns3server/compute/base_node.py:544-612

async def start_vnc_websocket_console(self, websocket):
    """Connect to VNC console using WebSocket."""

    # 1. Validation
    if self.status != "started":
        await websocket.close(code=1000)
        raise NodeError(f"Node {self.name} is not started")
    if self._console_type != "vnc":
        await websocket.close(code=1000)
        raise NodeError(f"Node {self.name} console type is not vnc")

    # 2. Connect to VNC server
    vnc_reader, vnc_writer = await asyncio.open_connection(
        self._manager.port_manager.console_host,
        self.console
    )

    # 3. Bidirectional forwarding
    async def ws_forward(vnc_writer):
        # Browser → VNC: Forward WebSocket data to VNC server
        while True:
            data = await websocket.receive_bytes()
            if data:
                vnc_writer.write(data)
                await vnc_writer.drain()

    async def vnc_forward(vnc_reader):
        # VNC → Browser: Forward VNC data to WebSocket
        while not vnc_reader.at_eof():
            data = await vnc_reader.read(4096)
            if data:
                await websocket.send_bytes(data)

    # 4. Run both forwarding tasks
    aws = [
        asyncio.create_task(ws_forward(vnc_writer)),
        asyncio.create_task(vnc_forward(vnc_reader))
    ]

    done, pending = await asyncio.wait(aws, return_when=asyncio.FIRST_COMPLETED)

    # 5. Cleanup
    for task in pending:
        task.cancel()
    vnc_writer.close()
    await vnc_writer.wait_closed()

Data Flow

Browser (noVNC)                    GNS3 Compute                  QEMU VNC
     │                                  │                            │
     │  WebSocket Frame (Binary)        │                            │
     ├─────────────────────────────────►│                            │
     │  receive_bytes()                 │                            │
     │                                  │  TCP Socket                │
     │                                  ├───────────────────────────►│
     │                                  │  write(data)               │
     │                                  │                            │
     │                                  │  TCP Socket                │
     │                                  │◄──────────────────────────┤
     │  WebSocket Frame (Binary)        │  read(4096)                │
     │◄─────────────────────────────────┤                            │
     │  send_bytes(data)                │                            │

Frontend Integration

noVNC Integration

Location: gns3-web-ui/src/assets/vnc-console/

Files:

  • index.html - VNC console page
  • vnc-controller.js - VNC connection controller
  • novnc/ - noVNC library files

Connection Example:

const sc = new RFB(document.getElementById('vnc-canvas'), {
  target: vncWsUrl,  // ws://controller:port/v3/projects/.../console/vnc?token=...
  credentials: { password: vncPassword }
});

sc.addEventListener('connect', () => {
  console.log('VNC connected');
});

sc.addEventListener('disconnect', (e) => {
  console.log('VNC disconnected:', e);
});

Console Service

Location: gns3-web-ui/src/app/services/vnc-console.service.ts

Methods:

  • buildVncWebSocketUrl() - Construct WebSocket URL
  • openVncConsole() - Open console in new window
  • buildVncConsolePageUrl() - Build standalone page URL

Authentication & Authorization

Controller Layer

  1. Authentication:

    • JWT token validation via get_current_active_user_from_websocket()
    • Token passed as query parameter: ?token={jwt}
  2. Authorization:

    • RBAC privilege check: Node.Console
    • Per-node access control
  3. WebSocket Subprotocol:

    • Client requests: binary
    • Server accepts: binary (if requested)

Compute Layer

  1. Authentication:

    • HTTP Basic Auth
    • Credentials from controller config
    • Username: settings.Server.compute_username
    • Password: settings.Server.compute_password
  2. Node Validation:

    • Check node exists
    • Check node is started
    • Check console type is vnc

Configuration

Server Settings

Controller Configuration (gns3-server.conf):

[Server]
host = 0.0.0.0
port = 3080

Compute Configuration (same file):

[Server]
compute_username = gns3
compute_password = gns3

Node Settings

QEMU VM Example:

{
  "name": "vm-1",
  "node_type": "qemu",
  "console_type": "vnc",
  "console": 5900,
  "console_resolution": "1280x720",
  "properties": {
    "qemu_path": "/usr/bin/qemu-system-x86_64"
  }
}

Docker Container Example:

{
  "name": "container-1",
  "node_type": "docker",
  "console_type": "vnc",
  "console": 5900,
  "console_resolution": "1024x768",
  "console_http_port": 8080
}

Troubleshooting

Common Issues

1. "Node is not started"

  • Symptom: WebSocket closes immediately
  • Solution: Start the VM before opening console
  • API Check: GET /v3/projects/{project_id}/nodes/{node_id} → verify status == "started"

2. "Console type is not vnc"

  • Symptom: WebSocket closes with error
  • Solution: Set node console_type to "vnc"
  • API Update: PUT /v3/projects/{project_id}/nodes/{node_id} with {"console_type": "vnc"}

3. "Cannot connect to VNC server"

  • Symptom: Connection timeout
  • Possible Causes:
    • VNC server not listening
    • Port conflict
    • Firewall blocking connection
  • Verification:
    # Check if VNC is listening
    netstat -tlnp | grep 5900
    
    # Check QEMU process
    ps aux | grep qemu
    

4. WebSocket Subprotocol Negotiation Failed

  • Symptom: Connection rejected during handshake
  • Solution: Ensure noVNC sends binary subprotocol
  • Browser Console Check:
    console.log(ws.protocol);  // Should be "binary"
    

5. Authentication Errors

  • Symptom: HTTP 401/403 responses
  • Controller: Check JWT token is valid and not expired
  • Compute: Verify compute username/password in config

Debug Logging

Enable Detailed Logging:

[gns3server]
debug = true

Check Controller Logs:

# Look for WebSocket connection messages
grep "VNC console WebSocket" /var/log/gns3/gns3.log

Check Compute Logs:

# Look for VNC forwarding messages
grep "Connected to VNC server" /var/log/gns3/gns3.log

Browser Console:

// Enable noVNC debugging
RFB.messages.log = function(msg) { console.log(msg); };

Performance Considerations

Bandwidth

  • Typical Usage: 1-5 Mbps per active VNC session
  • Full HD (1920x1080): Up to 10 Mbps with rapid screen changes
  • Optimization: Use lower resolution for slower connections

Latency

  • Target: < 50ms for local connections
  • Factors:
    • Network latency
    • WebSocket frame processing overhead
    • VNC encoding efficiency
  • Mitigation:
    • Use QXL driver for QEMU VMs
    • Enable VNC password authentication (reduces overhead)
    • Adjust console resolution

Concurrent Connections

  • Multiple Clients: Each VNC console supports one WebSocket connection
  • Multi-viewer: Not supported (VNC protocol limitation)
  • Shared Sessions: Use SPICE for multi-client support

Security

Authentication

  1. Controller → Client

    • JWT token with expiration
    • RBAC authorization
    • Privilege: Node.Console
  2. Controller → Compute

    • HTTP Basic Auth over TLS (recommended)
    • Separate compute credentials
  3. VNC Server

    • Optional VNC password (QEMU only)
    • Configured via node properties

Network Security

Recommendations:

  1. Use HTTPS/WSS for production deployments
  2. Firewall compute API ports
  3. Use short-lived JWT tokens
  4. Enable VNC password for sensitive VMs

Example:

# Controller with TLS
gns3server --ssl --cert /path/to/cert.pem --key /path/to/key.pem

# VNC with password
qemu-system-x86_64 -vnc :0,password

WebSocket Security

Subprotocol Validation:

  • Only binary subprotocol is accepted
  • Prevents protocol downgrade attacks

Origin Validation:

  • Browser enforces same-origin policy
  • Configure CORS if using separate domains

Limitations

  1. Single Client per VNC Port

    • VNC protocol supports one client at a time
    • New connections disconnect existing clients
  2. No Audio Redirection

    • VNC doesn't support audio
    • Use SPICE for audio support
  3. No USB Redirection

    • VNC doesn't support device redirection
    • Use SPICE for USB support
  4. Performance

    • Higher CPU usage than native VNC clients
    • Binary forwarding adds processing overhead

Comparison with SPICE

Feature VNC WebSocket SPICE WebSocket
Browser Support Excellent Good (with spice-html5)
Audio Redirection No Yes
USB Redirection No Yes
Clipboard Sharing ⚠️ Limited Full
Multi-monitor Yes Yes
Performance ⚠️ Moderate Better
Guest Agent No Yes (spice-vdagent)
Stability Very Stable ⚠️ Moderate
Implementation Complete Removed (dependencies)

Future Enhancements

Planned improvements:

  1. WebSocket Compression

    • Enable per-message compression
    • Reduce bandwidth usage
  2. Connection Pooling

    • Reuse WebSocket connections
    • Reduce connection overhead
  3. Recording Support

    • Record VNC sessions
    • Playback functionality
  4. Multi-viewer Mode

    • Read-only shared viewing
    • Teacher/student scenarios

References

Version History

Version Date Changes
1.0 2026-03-17 Initial VNC WebSocket documentation
0.9 2026-03-15 Added VNC WebSocket support to QEMU and Docker