mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-08-27 12:30:13 +03:00
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>
This commit is contained in:
parent
64d3c02d42
commit
a2c1a913ca
513
docs/features/vnc-websocket-console.md
Normal file
513
docs/features/vnc-websocket-console.md
Normal file
@ -0,0 +1,513 @@
|
||||
# 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**:
|
||||
```javascript
|
||||
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**:
|
||||
```json
|
||||
{
|
||||
"console_type": "vnc",
|
||||
"console": 5900,
|
||||
"console_resolution": "1024x768"
|
||||
}
|
||||
```
|
||||
|
||||
**QEMU Parameters**:
|
||||
```bash
|
||||
-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**:
|
||||
```json
|
||||
{
|
||||
"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`
|
||||
|
||||
```python
|
||||
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**:
|
||||
```javascript
|
||||
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`):
|
||||
```ini
|
||||
[Server]
|
||||
host = 0.0.0.0
|
||||
port = 3080
|
||||
```
|
||||
|
||||
**Compute Configuration** (same file):
|
||||
```ini
|
||||
[Server]
|
||||
compute_username = gns3
|
||||
compute_password = gns3
|
||||
```
|
||||
|
||||
### Node Settings
|
||||
|
||||
**QEMU VM Example**:
|
||||
```json
|
||||
{
|
||||
"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**:
|
||||
```json
|
||||
{
|
||||
"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**:
|
||||
```bash
|
||||
# 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**:
|
||||
```javascript
|
||||
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**:
|
||||
```ini
|
||||
[gns3server]
|
||||
debug = true
|
||||
```
|
||||
|
||||
**Check Controller Logs**:
|
||||
```bash
|
||||
# Look for WebSocket connection messages
|
||||
grep "VNC console WebSocket" /var/log/gns3/gns3.log
|
||||
```
|
||||
|
||||
**Check Compute Logs**:
|
||||
```bash
|
||||
# Look for VNC forwarding messages
|
||||
grep "Connected to VNC server" /var/log/gns3/gns3.log
|
||||
```
|
||||
|
||||
**Browser Console**:
|
||||
```javascript
|
||||
// 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**:
|
||||
```bash
|
||||
# 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
|
||||
|
||||
- [RFB Protocol 3.8](https://tools.ietf.org/html/rfc6143) - VNC Protocol Specification
|
||||
- [noVNC Documentation](https://github.com/novnc/noVNC) - HTML5 VNC Client
|
||||
- [FastAPI WebSocket](https://fastapi.tiangolo.com/advanced/websockets/) - WebSocket Implementation
|
||||
- [GNS3 Documentation](https://docs.gns3.com/) - General GNS3 Documentation
|
||||
|
||||
## 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 |
|
||||
Loading…
x
Reference in New Issue
Block a user