* feat(storage): browse a medium and exchange files with the target machine The image menu and the download page are replaced by one storage page: it lists the media the emulated USB disk can carry, mounts and ejects them, and browses the files inside a medium over that same gadget, so the two machines exchange files without going through the terminal. Mediated media: * Add the media API (list, state, mount, eject, delete, download, files) and a file browser on top of it, and keep the pre-2.6 image endpoints working as a compatibility layer over the same code. * Add diskfs: an image is mounted through a loop device so the kernel's exFAT and FAT drivers read it, and the data partition is browsed in place, because the emulated disk already hands that very directory to the target machine. * Keep the one-writer policy the read-only mounts introduced: an image is served read-only in every mode, and the whole data partition is remounted read-only here while the target machine is its writer, through the same SetDataWritable the virtual disk switch uses. The file manager refuses those writes itself as well, so a request does not depend on a mount state. * Name the mounted medium and the USB device after the image file, cut to the SCSI inquiry product field and the USB product string, and restore the defaults when the medium is released. * Close the HID devices around a gadget re-enumeration and reopen them after, since mounting and a forced eject drop them. * Report transfers through one job slot with progress, queueing behind a running transfer, and a free space preflight before an upload starts. Image uploads keep the volume descriptor and partition table check, so an unusable image is rejected while it streams. The shared folder view: * Refresh it on a timer while the target machine owns the partition. The target's block level writes land in this device's page cache, which the mounted exFAT shares, so the file data here is already current - but the dentry and inode caches are not, and a file the target grew keeps the size it was first read with. Dropping those caches and pushing a storage event makes the web UI follow the target machine within a second of its own writeback. The partition's write counter cannot drive this: it only moves once this side writes its dirty pages back, which is tens of seconds later or never. * Send the refresh notifications from their own goroutine, so a client that stopped reading cannot hold up the refresh loop. The web UI: * Add the storage page: the medium list with mount and eject, the file browser with search and sorting, uploads, downloads and deletes, and transfer progress. * Gate writing on the target machine owning the disk - image uploads and file uploads alike - instead of letting the server answer with an error the page has to surface, and drop the medium rows' download and delete buttons there too. * Give the shared folder, .iso and .img their own glyphs, and pick the file icon from the extension, so a listing can be read at a glance. * Name the partition the way the storage page does in the desktop menu as well, instead of showing the API's untranslated string. * Read the mounted medium in Settings - Device from the media state, now that the storage API it used is gone. * Tell an ISO 9660 image apart from a filesystem that cannot be read at all: the kernel of this device carries no iso9660 support (CONFIG_ISO9660_FS), so the contents of an ISO cannot be listed while the image itself is served to the target machine like any other medium. Localization: * Translate the new strings for every locale, keep the Settings - Device strings the read-only mounts added, and drop the keys the retired image menu and download page left behind. Chores: * Remove the desktop image menu, the download page and the API they used. * fix(storage): harden media file transfers Serialize medium deletion with gadget attachment and restore /data write access after failed mount transitions. Use available filesystem space for upload limits, refine virtual-device and shared-file handling, and update media path and installation test coverage. Pin an image while it is streamed out, so a writable mount cannot start between the check and the last byte; sweep stale upload temporaries from the whole data partition at startup, which the file manager itself cannot delete; and preflight URL downloads against the response size, which only the upload path did. Show dot files in the file browser again: only the two transfer temporary prefixes stay hidden, which is what the dot filter was for. Delete folders recursively after the web UI confirms, refusing when an attached or mounted medium lives inside the directory; accept every .iso and .img upload by name instead of sniffing volume descriptors; and show image and file transfers in one progress display at the top of the storage page. * fix(storage): make cache drops work and close delete and gadget races - drop_caches only accepts 1..4 on 5.10: write 4 once to silence the log, then 2/3. Writing 6/7 failed with EINVAL, so the shared folder never saw what the target machine wrote. - Resolve a delete path to its on-disk spelling (exFAT is case-insensitive) before checking it against the attached and loop-mounted media, refuse deleting a loop-mounted image or a folder holding an upload target, and fail closed when the disk state cannot be read. - GetMediaState no longer fails when the virtual disk is off and lun.0 does not exist; browsing works with the virtual disk off. - An explicit enable for the virtual disk compares against the disk being configured, so it leaves a served image alone; the settings toggle keeps the #937 semantics. - Restore /data write access after a failed gadget script or network switch. - eject clears the LUN file before resetting ro/cdrom, so a refused eject does not change the type of the medium still being served. - Mount loop images with MS_NOSYMFOLLOW and open files with O_NOFOLLOW. - Accept UDF images as optical media. - Only refuse deleting transfer temporaries while a transfer runs; sweep stale ones in the background, by exact name, and not on a read-only /data; hide them from listings. - Cap URL downloads without Content-Length at the free space and verify the received length. - Encode Content-Disposition filename* strictly per RFC 5987. - Restore image_test.go and add tests for the above. * fix(web): keep the file browser and transfers consistent on the storage page - Tag a listing with the medium and path it belongs to, so entries of the previous directory are never shown or acted on under a new path. - Poll the desktop storage menu only while it is open. - Show a dedicated message for a checksum mismatch. - Bring back the USB / SCP / TF card hints behind a help button. - Pick up a transfer already running when the page opens; make uploads cancellable; track concurrent uploads separately; let a failed job be dismissed; show a success state and guard the progress display by task. - Handle request errors that were left unhandled. - Dedicated confirmation for deleting a folder recursively. - Treat UDF images as optical, send credentials on the image download pre-check, translate the remaining Hungarian string. --------- Co-authored-by: Guoguo <i@qwq.trade>
NanoKVM
🌟 What is NanoKVM?
NanoKVM is a series of compact, open-source IP-KVM devices based on the LicheeRV Nano (RISC-V). It lets you remotely access and control computers as if you were sitting in front of them, making it useful for servers, embedded systems, and other headless machines.
📦 Product Family
Choose the NanoKVM model that best fits your deployment:
- NanoKVM-Cube Lite: A barebones kit for DIY users and bulk deployments.
- NanoKVM-Cube Full: A ready-to-use kit with a case, accessories, and a pre-flashed system SD card.
- NanoKVM-PCIe: A PCIe-bracket form factor for internal chassis mounting. It draws power from the PCIe slot and supports optional Wi-Fi and PoE.
- NanoKVM-Pro: A higher-performance version with major upgrades:
- Resolution: Up to 4K@30fps / 2K@60fps.
- Network: 1Gbps Ethernet + PoE + Wi-Fi 6, upgraded from 100Mbps Ethernet.
- Latency: Hardware-accelerated encoding reduces latency from 100-150ms to 50-100ms.
If you are looking for a USB-based KVM solution, check out NanoKVM-USB.
🛠️ Technical Specifications
| Feature | NanoKVM-Pro | NanoKVM (Cube/PCIe) | GxxKVM | JxxKVM |
|---|---|---|---|---|
| Core | AX630C 2xA53 1.2G | SG2002 1xC906 1.0G | RV1126 4xA7 1.5G | RV1106 1xA7 1.2G |
| Memory & Storage | 1G LPDDR4X + 32G eMMC | 256M DDR3 + 32G microSD | 1G DDR3 + 8G eMMC | 256M DDR3 + 16G eMMC |
| System | NanoKVM / PiKVM | NanoKVM | GxxKVM | JxxKVM |
| Resolution | 4K@30fps / 2K@60fps | 1080P@60fps | 4K@30fps / 2K@60fps | 1080P@60fps |
| HDMI Loopout | 4K loopout | — | — | — |
| Video Encoding | MJPEG / H.264 / H.265 | MJPEG / H.264 | MJPEG / H.264 | MJPEG / H.264 |
| Audio Transmit | ✓ | — | ✓ | — |
| UEFI / BIOS | ✓ | ✓ | ✓ | ✓ |
| Emulated USB Keyboard & Mouse | ✓ | ✓ | ✓ | ✓ |
| Emulated USB ISO | ✓ | ✓ | ✓ | ✓ |
| IPMI | ✓ | ✓ | ✓ | — |
| Wake-on-LAN | ✓ | ✓ | ✓ | ✓ |
| Web Terminal | ✓ | ✓ | ✓ | ✓ |
| Serial Terminal | 2 channels | 2 channels | — | 1 channel |
| Custom Scripts | ✓ | ✓ | — | — |
| Storage | 32G eMMC 300MB/s | 32G MicroSD 12MB/s | 8G eMMC 120MB/s | 8G eMMC 60MB/s |
| Ethernet | 1000M | 100M | 1000M | 100M |
| PoE | Optional | Optional | — | — |
| Wi-Fi | Optional Wi-Fi 6 | Optional Wi-Fi 6 | — | — |
| ATX Power Control | ✓ | ✓ | Extra $15 | Extra $10 |
| Display | 1.47" 320x172 LCD / 0.96" 128x64 OLED | 0.96" 128x64 OLED | — | 1.68" 280x240 |
| More Features | Sync LED Strip / Smart Assistant | — | — | — |
| Power Consumption | 0.6A@5V | 0.2A@5V | 0.4A@5V | 0.2A@5V |
| Power Input | USB-C or PoE | USB-C | USB-C | USB-C |
| Dimensions | 65x65x26mm | 40x36x36mm | 80x60x17.5mm | 60x43x(24~31)mm |
📂 Project Structure
├── kvmapp # APP update package
│ ├── jpg_stream # Legacy support for direct updates from older versions
│ ├── kvm_new_app # Triggers components for kvm_system updates
│ ├── kvm_system # Core KVM application
│ ├── server # Front-end and back-end integration
│ └── system # Essential system components
├── web # NanoKVM Front-end (UI)
├── server # NanoKVM Back-end (Service)
├── support # Auxiliary modules (Image subsystem, status, updates, OLED, HID, etc.)
├── ...
💻 Development
Start with the guide that matches the part of NanoKVM you want to work on:
- System support modules: Build and update the low-level hardware support components in support/sg2002/README.md.
- Backend service: Set up, build, and understand the Go service in server/README.md.
- Frontend UI: Develop, lint, and build the React interface in web/README.md.
- Release packaging: Assemble the
nanokvm_<version>.tar.gzupdate package in scripts/README.md.
Backend compilation and runtime validation require the target toolchain or a NanoKVM device. See the module-specific guides above for the latest development workflow.
Dev container (optional)
The repository ships a Dev Container setup (.devcontainer/) that layers the frontend toolchain (Node 22, pnpm 11) on top of the release builder image (RISC-V cross toolchain, Go, MaixCDK), so one container covers Go, C support-layer and web development. It is a convenience for IDE users; the make targets in the repository root remain the canonical CLI workflow.
- Requirements: Docker plus an editor or CLI with dev container support (e.g. the VS Code "Dev Containers" extension, or
devcontainer up). - On creation the container prepares itself automatically:
support/sg2002/build update_lib(resyncs MaixCDK components with the checkout) andpnpm installfor the frontend. - Backend: run
server/build.shfor a release-equivalent binary (BoringCrypto +dl_libRPATH).make appbuilds a plain development binary without those, so preferserver/build.shwhenever the result should match a release. - Support layer:
cd support/sg2002 && ./build kvm_system(the MaixCDK virtualenv is part of the container environment). - Frontend:
cd web && pnpm dev(VS Code forwards port 3001 automatically; other clients may need to map it themselves); see web/README.md for pointing it at a device. - The base image
ghcr.io/sipeed/nanokvm-builder:latestis x86-64 only; on Apple Silicon it runs under emulation (works, but C builds are slow). You can also build the image locally first (make builder-image) and point theBASE_IMAGEbuild arg at it (e.g. viabuild.argsindevcontainer.json). On Linux hosts the first container creation also takes a while: the container user is remapped to your uid, which re-chowns its home directory once. - Hardware-dependent verification still requires a real NanoKVM device; the container covers compiling, linting and mock-mode web development only.
🔩 Hardware Platform (NanoKVM Cube/PCIe)
NanoKVM is based on Sipeed LicheeRV Nano. You can find specifications, schematics, and dimensional drawings in the download station.
The NanoKVM Cube/PCIe hardware is built from these components:
- NanoKVM Lite: LicheeRV Nano plus the HDMI-to-CSI board.
- NanoKVM Full: NanoKVM Lite plus the NanoKVM-A/B boards and enclosure.
- HDMI-to-CSI board: Converts the HDMI input signal.
- NanoKVM-A board: Provides OLED, ATX control output through USB-C, auxiliary power, and physical ATX power/reset buttons.
- NanoKVM-B board: Connects NanoKVM-A to the host computer's ATX pins for remote power control.
The NanoKVM image is built with the LicheeRV Nano SDK and MaixCDK. It is intended for NanoKVM hardware and is not a general-purpose KVM software package for other LicheeRV Nano or SG2002 products. If you want to build an HDMI input application on LicheeRV Nano or MaixCam, please contact us for technical support.
Note: Of the 256MB memory on SG2002, 158MB is currently allocated to the multimedia subsystem for video capture and processing.
🤝 Contributing
We welcome contributions. To get started:
- Fork the repository.
- Create a feature branch.
- Commit your changes.
- Push to the branch.
- Open a Pull Request.
Please keep your pull requests small and focused to facilitate easier review and merging.
🎁 Contributors who submit high-quality Pull Requests may receive a NanoKVM Cube, PCIe, or Pro as a token of our appreciation!
🛒 Where to Buy
💬 Community & Support
- Discord
- QQ group: 703230713
- Email: support@sipeed.com
- FAQ
📜 License
This project is licensed under the GPL-3.0 License. See LICENSE for details.


