| name | install-windows-3-11 |
| description | Guidance for setting up legacy Windows VMs (like Windows 3.11) in QEMU with web-based remote access via noVNC. This skill should be used when tasks involve running legacy operating systems in virtual machines, configuring QEMU for older OS images, setting up VNC/noVNC web interfaces, or establishing programmatic keyboard control via QMP. Covers VM boot verification strategies, nginx reverse proxy configuration, and websockify setup. |
Install Windows 3.11
Overview
This skill provides guidance for setting up legacy Windows virtual machines (particularly Windows 3.11) using QEMU with web-based remote access. The core challenge is not just launching the VM, but verifying it reaches a usable state and providing reliable remote access.
Critical Success Criteria
Before marking any VM setup task complete, verify:
- The VM actually boots to the expected state - Screenshots, VNC connection tests, or QMP display queries must confirm the desktop/expected state
- Web interface is fully functional - End-to-end test through the browser, not just service status checks
- Keyboard/mouse input works - Verify input actually affects VM state, not just that commands are accepted
Approach
Phase 1: Environment Assessment
Before installing anything:
- Check QEMU version requirements in task description - note any specific version compatibility statements
- Audit existing nginx configuration to understand current server blocks
- Identify required ports and check for conflicts
- Determine the disk image format and any special QEMU flags needed
Phase 2: QEMU Configuration
When configuring QEMU for legacy operating systems:
- Memory allocation: Windows 3.11 typically needs 16-64MB RAM. Check image documentation for requirements
- VNC setup: Use
-vnc :1for display 1 (port 5901). Consider-vnc :1,share=ignore-disconnectsfor stability - QMP socket: Enable with
-qmp unix:/path/to/qmp.sock,server,nowaitfor programmatic control - Display: Legacy OS may need specific display settings like
-vga stdor-vga cirrus
Example QEMU command structure:
qemu-system-i386 \
-m 32 \
-hda /path/to/disk.img \
-vnc :1 \
-qmp unix:/tmp/qmp.sock,server,nowait \
-vga std
Phase 3: Web Access Stack
The typical stack for web-based VNC access:
Browser → nginx (port 80) → websockify → VNC server (QEMU)
nginx configuration approach:
- First, examine
/etc/nginx/nginx.conffor existing server blocks - Check if
sites-enabledis included in the main config - Create configuration in the appropriate location to avoid conflicts
- Test configuration with
nginx -tbefore reloading
websockify setup:
websockify --web=/usr/share/novnc 6080 localhost:5901
Key parameters:
--webserves noVNC static files- Port 6080 is the WebSocket endpoint
- Target is the VNC port (5901 for display :1)
Phase 4: Boot Verification
This is the most commonly failed step. Never assume boot succeeded based on process status alone.
Verification strategies:
- QMP display query: Send
{"execute": "query-status"}to check VM state - VNC screenshot: Use
vncsnapshotor similar to capture current display - QMP screendump:
{"execute": "screendump", "arguments": {"filename": "/tmp/screen.ppm"}} - Connect via VNC client: Actually view the display, not just test connectivity
Boot timing considerations:
- Legacy OS may need user interaction to complete boot (pressing Enter, clicking OK)
- Implement polling rather than fixed sleep delays
- Consider boot sequence: BIOS → DOS → Windows (multiple stages)
Phase 5: Input Verification
After establishing QMP connection:
- Send test keystrokes and verify display changes
- Each QMP connection requires capability negotiation first:
{"execute": "qmp_capabilities"} - Then send keys:
{"execute": "send-key", "arguments": {"keys": [{"type": "qcode", "data": "ret"}]}}
Common Pitfalls
QEMU Version Compatibility
If task specifies "compatible with QEMU X.Y.Z" but a different version is installed:
- Document the version mismatch
- Test if the image actually boots with the available version
- Report any compatibility issues observed
nginx Configuration Conflicts
Symptoms: 502 Bad Gateway, connection refused
Prevention:
- Always audit existing nginx config before adding new server blocks
- Check for conflicting
listendirectives - Verify upstream (websockify) is running before nginx tries to proxy to it
Premature Task Completion
Never mark "VM booted successfully" without:
- Visual confirmation (screenshot or VNC connection)
- Or QMP state verification showing expected state
QMP Socket Issues
- Stale socket files from previous runs cause connection failures
- Always clean up
/tmp/*.sockor equivalent before starting QEMU - Use
socatorncto test socket connectivity
Boot Detection
Arbitrary sleep commands are unreliable. Instead:
- Poll QMP status at intervals
- Check for specific display content changes
- Implement timeout with failure handling
Verification Checklist
Before declaring task complete:
- QEMU process is running (check with
pgreporps) - VNC port is listening (
ss -tlnp | grep 5901) - Websockify is running and connected to VNC
- nginx is proxying correctly (test with curl to WebSocket endpoint)
- Visual confirmation of expected OS state (screenshot or live view)
- Keyboard input affects VM display (send test key, verify change)
- Web interface loads in browser and connects to VM
Resources
references/
Refer to references/qemu_legacy_os.md for detailed QEMU flags and compatibility notes for legacy operating systems.
Refer to references/novnc_nginx_config.md for production-ready nginx configuration templates.