This document explains how the kernel-images repository uses neko to expose a web UI for the browser running in the container at port 8080.
The kernel-images repository uses neko as a WebRTC-based remote desktop solution with the following architecture:
- Neko Server: Runs the neko server binary (
/usr/bin/neko
) on port 8080 - WebRTC Streaming: Uses WebRTC for real-time video/audio streaming of the desktop
- Vue.js Client: Includes a custom Vue.js client built from source
- X11 Desktop: Streams an X11 desktop running Chromium browser
- Fallback Option: Uses noVNC as fallback when WebRTC is disabled
- Location:
/home/mike/src/kernel-images/images/chromium-headful/client/
- Framework: Vue.js 2 application with TypeScript
-
Entry Point
client/src/main.ts
- Mounts the Vue app to#neko
element- Sets up plugins (Logger, Notifications, ToolTip, Axios, etc.)
- Initializes the neko client
-
Main Components
client/src/app.vue
- Main application componentclient/src/components/video.vue
- Main video streaming component that handles WebRTCclient/src/components/controls.vue
- Control interfaceclient/src/components/connect.vue
- Connection interface
-
WebRTC Implementation
client/src/neko/index.ts
- WebSocket and WebRTC client implementationclient/src/neko/base.ts
- Base client class with WebRTC peer connection logicclient/src/neko/messages.ts
- Message types for WebSocket communicationclient/src/neko/events.ts
- Event definitions
-
HTML Template
client/public/index.html
- The HTML template served at port 8080
client/package.json
- Dependencies and build scriptsclient/vue.config.js
- Vue CLI configuration- Build script:
npm run build
(also hasbuild:lib
for library build)
The client has several features disabled (marked with "KERNEL" comments):
- Fullscreen button disabled
- Resolution controls disabled
- Clipboard controls disabled
- Picture-in-Picture disabled
- Play/unmute overlays disabled
From the Dockerfile:
# Copy neko binary from official image
COPY --from=neko /usr/bin/neko /usr/bin/neko
# Copy built client files to web root
COPY --from=client /src/dist/ /var/www
# Copy configuration
COPY neko.yaml /etc/neko/neko.yaml
desktop:
screen: "1920x1080@60"
member:
provider: "noauth"
session:
merciful_reconnect: true
implicit_hosting: true
cookie:
enabled: false # disabled for legacy API
plugins:
enabled: false
chat:
enabled: false
filetransfer:
enabled: false
From wrapper.sh
:
if [[ "${ENABLE_WEBRTC:-}" == "true" ]]; then
# use webrtc
echo "✨ Starting neko (webrtc server)."
/usr/bin/neko serve --server.static /var/www --server.bind 0.0.0.0:8080 >&2 &
else
# use novnc
./novnc_startup.sh
echo "✨ noVNC demo is ready to use!"
fi
Key parameters:
--server.static /var/www
- Serves static client files--server.bind 0.0.0.0:8080
- Binds to all interfaces on port 8080
-
Initial Page Load
- User visits http://localhost:8080
- Neko server serves the static
index.html
from/var/www
- HTML loads the Vue.js application
-
Connection Establishment
- Vue app initializes and creates WebSocket connection to the server
- WebSocket URL is constructed based on current location
- Authentication happens via URL parameters (username/password)
-
WebRTC Negotiation
- WebRTC offer/answer exchange happens over WebSocket
- ICE candidates are exchanged for NAT traversal
- Peer connection is established
-
Streaming
- Video stream from X11 desktop is captured
- Audio is captured from PulseAudio
- Streams are sent via WebRTC to the client
- Client displays video in
<video>
element
-
User Interaction
- Mouse/keyboard events are captured in overlay textarea
- Events are sent via WebRTC data channel
- Server injects events into X11 using custom neko input driver
// Simple iframe embedding
<iframe
src="http://server:8080/?usr=neko&pwd=neko&embed=1"
allowFullScreen
webkitallowfullscreen="true"
mozallowfullscreen="true"
allow="fullscreen *"
/>
Benefits:
- No code changes needed
embed=1
parameter hides sidebar/top bar- Complete isolation from parent app
The client supports building as a library:
npm run build:lib
This creates a library build that exports Vue components:
- NekoVideo
- NekoControls
- NekoConnect
- etc.
Current limitation: Vue 2 based, would need wrapper for React
Build a custom React client that:
- Connects to neko WebSocket API
- Handles WebRTC negotiation
- Displays video stream
- Sends input events
This requires understanding the neko protocol and significant development effort.
According to the neko roadmap, V3 will include:
- A modular TypeScript client library without Vue dependency
- Better extensibility for embedding in other applications
- Improved component architecture
This would make React integration much easier in the future.
- The repository includes custom X11 input drivers for mouse/keyboard injection
- Chrome is run with specific flags for better compatibility
- The setup includes cleanup of Chrome lock files to prevent startup issues
- D-Bus is configured to reduce error messages
- Scale-to-zero functionality is managed for Unikraft Cloud deployment