A system-level transparent proxy for rooted Android and Linux desktop β routes all traffic through Xray-core / sing-box at the kernel level, with a clean React UI.
On Android, Kasumi Proxy is a Magisk / KernelSU / APatch module (not a standalone app): it
runs the proxy core as a system daemon and steers traffic with native Linux routing
(iptables / ip rule) instead of Android's user-space VpnService. On desktop it is a
Tauri 2 app that owns the same data path with a real TUN. Both shells drive one shared Rust
backend, so the domain logic β profiles, share links, config builders, subscriptions β lives in
exactly one place.
π΄ Fork of vincentng295/Magic_V2Ray.
π€ AI SLOP WARNING. Most of this codebase was written by AI β review before trusting.
If you come from v2rayNG, NekoBox, or Matsuri, here is what changes on Android:
- Survives Low-Memory-Killer. User-space apps get killed under memory pressure, dropping the tunnel and leaking your real IP. Kasumi Proxy runs as a root daemon the OS won't reap.
- Kernel-level routing. No virtual
tun0software bottleneck for app traffic β packets are intercepted at the Netfilter layer and handed straight to the core, cutting latency and the CPU overhead of Javaβkernel context switching. - Seamless network switches. Wi-Fi β 4G/5G transitions hot-reload the routing rules in-kernel.
- Universal root support. Magisk, KernelSU, and APatch out of the box.
β οΈ No root? The Android side is a system module, not an app. For a regular GUI client, see the Xray-core GUI clients.
- Dual core β Xray-core for VLESS / VMess / Trojan / Shadowsocks / SOCKS / HTTP / WireGuard, sing-box for Hysteria2 / TUIC. The engine is resolved per profile.
- Smart import β paste subscription URLs, raw config strings, or mixed text; scan QR.
- Category organizing β group servers into folders, one-tap update a whole category.
- Truthful status β the main screen distinguishes connecting / connected / no-internet / failed via an end-to-end probe, not just "the process started".
- Per-profile diagnostics β tcp-ping, real-ping and a speed test, streamed as they finish.
- Headless subscription auto-update β applies in the background with no UI open.
Android (root):
- Download the latest
kasumi-proxy-module-vX.Y.Z.ziprelease. - Flash it in Magisk / KernelSU / APatch and reboot.
- Open the module's Action (Magisk) or its WebUI entry β it launches the control center in your browser, authenticated with a per-install token.
State and logs live under /data/adb/kasumi-proxy/.
Linux desktop: install the .deb or run the .AppImage from the latest release, or build with
nix build .#kasumi-desktop (see below). For a no-install copy that keeps all state next to the
binary, download kasumi-proxy-linux-portable-vX.Y.Z.zip, unzip it, and run ./kasumi-desktop β it
re-execs itself through pkexec/sudo for the tun adapter and routes.
Windows desktop: run the -setup.exe (NSIS) installer or the .msi from the latest release.
For a no-install copy β runs from anywhere, keeps all state next to the executable β download
kasumi-proxy-windows-portable-vX.Y.Z.zip, unzip it, and launch kasumi-desktop.exe. The app needs
administrator rights to bring up the tun adapter and routes, so accept the UAC prompt.
Release .AppImage bundles are GPG-signed with the project's release key
(release-signing-key.asc, fingerprint
2AA0 03A9 D670 653C FAA8 F7B0 88BE 4761 6D49 65E9):
gpg --import release-signing-key.asc
# AppImage signatures are embedded; extract and verify against the imported key:
./Kasumi*.AppImage --appimage-extract '.appimage_signature'
gpg --verify squashfs-root/.appimage_signature Kasumi*.AppImageThe repo is one Rust workspace + the React UI, with two thin shells over a shared backend:
.
βββ crates/
β βββ kasumi-core/ # neutral domain: profiles, share links, xray/sing-box config
β β # builders, sub-apply, on-disk migrations (serde + specta::Type)
β βββ kasumi-backend/ # neutral orchestration: Platform trait, typed Command/Response +
β β # dispatch, lifecycle/jobs/sub-update, the Service
β βββ kasumi-daemon/ # Android-only bin: axum HTTP webroot + token-gated WS β the Service
βββ src-tauri/ # Tauri 2 desktop app: the same Service in managed state + Linux Platform
βββ frontend/ # React + TypeScript UI (Vite, Zustand, Biome); runs on generated bindings
βββ module/ # contents that become the installable Android zip root
β βββ module.prop customize.sh service.sh action.sh uninstall.sh META-INF/
β βββ bin/ # kasumi-proxy daemon + xray/sing-box/tun2socks (built/fetched, gitignored)
β βββ webroot/ # built UI (generated, gitignored)
βββ scripts/ # fetch-binaries, build-daemon-android, build-webroot, package-release
βββ Cargo.toml # Rust workspace manifest
βββ flake.nix # Nix dev shell + crane-tauri desktop build + android daemon toolchain
The frontend's TypeScript bindings, Zod schemas and runtime defaults are generated from the
Rust types (tauri-specta), so the two sides can't drift. Everything OS-specific lives behind
the Platform trait β Android in kasumi-daemon, Linux desktop in src-tauri.
The Nix flake is the supported build path (no system Rust needed):
# Rust gate
nix develop --command cargo test --workspace
nix develop --command cargo clippy --workspace --all-targets -- -D warnings
# Frontend
cd frontend && bun install && bun run build && bunx vitest run
# Desktop app (reproducible)
nix build .#kasumi-desktop
# Android module zip (cross-builds the daemon + cores + webroot, then zips)
nix run .#package-release -- build/kasumi-proxy.zipCore/daemon binaries and the built module/webroot/ are intentionally not committed β they
are produced at release time (see .gitignore).
flake.nix declares a public Cachix cache (kasumi-proxy) as a
substituter, so nix develop / nix build pull the prebuilt Rust toolchain, webkit and devshell
closure instead of building them. Nix asks once to trust the flake's cache settings β accept the
prompt, pass --accept-flake-config (e.g. nix develop --accept-flake-config), or set
accept-flake-config = true in your nix.conf. CI already sets it.
Prompt-free alternative (writes the substituter straight to your own Nix config):
nix profile install nixpkgs#cachix # once, if you don't already have cachix
cachix use kasumi-proxyReads are public β no token needed. (CI additionally caches the workspace's cargo build via the
GitHub Actions cache; that layer is CI-only β a local cargo build still compiles normally.)
The flake exposes kasumi-desktop as a package, and each release builds it and pushes it to the
kasumi-proxy Cachix cache, so you can install a released tag without compiling. Add the cache to
your own Nix config first β a flake's nixConfig is not applied to downstream consumers, so
ours doesn't reach you automatically:
cachix use kasumi-proxy # or add the substituter + key below to your nix.conf
nix build github:loss-and-quick/Kasumi-Proxy/vX.Y.Z#kasumi-desktopOr wire it into your own flake:
{
inputs.kasumi-proxy.url = "github:loss-and-quick/Kasumi-Proxy";
# outputs: inputs.kasumi-proxy.packages.${system}.kasumi-desktop
nixConfig = {
extra-substituters = [ "https://kasumi-proxy.cachix.org" ];
extra-trusted-public-keys = [
"kasumi-proxy.cachix.org-1:V22nNqK4m1rSZRfuak86S1aY1eLlGhty05m8VtK25gM="
];
};
}Without our substituter in your config, the build still works β it just compiles from source instead of pulling the prebuilt closure. The cache hit is per exact revision (the released tag), so build the same tag you reference.
On NixOS the flake also exposes nixosModules.default, which installs the app and ensures polkit is
present for its root re-exec (the desktop brings up the tun + routes by re-execing itself through
pkexec):
{
inputs.kasumi-proxy.url = "github:loss-and-quick/Kasumi-Proxy";
outputs = { nixpkgs, kasumi-proxy, ... }: {
nixosConfigurations.your-host = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
kasumi-proxy.nixosModules.default
{ programs.kasumi-proxy.enable = true; }
];
};
};
}programs.kasumi-proxy.package overrides the build; it defaults to this flake's kasumi-desktop.
The data-path helper is granted the Linux capabilities it needs (CAP_NET_ADMIN, CAP_NET_RAW,
CAP_CHOWN, CAP_DAC_OVERRIDE) through a security.wrappers setcap wrapper, so the app brings the
tunnel up with no password prompt and the helper runs as your user with only those caps β not full
root. If setcap doesn't take in your setup, fall back to a setuid-root wrapper:
programs.kasumi-proxy.helperSetuid = true;cd frontend
bun install
bun run dev # mock bridge β no device needed
bunx vitest run # unit tests
bunx biome check # lint/formatThe UI talks to the backend through a Bridge abstraction (src/lib/bridge.ts): the Tauri
build invokes the backend in-process, the Android build speaks a token-guarded WebSocket RPC to
the daemon, and mock-bridge.ts simulates it for local development β all carrying the same typed
Command / Response.
- One backend, two shells.
kasumi-backendowns the data-path lifecycle (core +tun2socks, routing, watchdogs, headless subscription updates) as aService. On Android thekasumi-proxydaemon hosts it behind an axum WS server; on desktop the Tauri process is the backend. The UI never builds raw shell β it speaks one typed command set over the bridge. - Domain logic lives in
kasumi-core. Profiles in, engine config (xray_config/singbox_config) out, built server-side so subscription updates apply with no UI open. frontend/is the management UI, running on the generated bindings.
Kasumi Proxy bundles pre-built binaries from these open-source projects:
- Xray-core β primary proxy engine.
- sing-box β second core.
- tun2socks β wraps the proxy into a TUN interface.
See LICENSE.
