Files
community-plugins/ruh-vpn
0733efd186 Add umedbazarov/ruh-vpn: VPN/proxy manager for sing-box (#304)
* Add umedbazarov/ruh-vpn: VPN/proxy manager for sing-box

New community plugin: bar widget, panel, service and control-center
shortcut for managing SSH, VLESS, VMess, Shadowsocks and SOCKS5
connections through sing-box, with routing presets, custom rules,
system-proxy/TUN modes and a kill switch. The bundled Python backend
serves a loopback control API protected by a per-launch bearer token.

* Address review: sanitize kill-switch ruleset, scope TUN capability, fix mux error path, disclose DNS

- kill switch: only pre-resolved, canonicalized literal IPs enter the nft
  ruleset; domains are resolved first and anything unparseable is dropped,
  so subscription-supplied addresses can no longer inject nft syntax
- TUN: CAP_NET_ADMIN is granted to a plugin-private copy of sing-box in a
  0700 directory instead of the shared system binary; the copy is refreshed
  (clearing the cap) when the system binary changes, and the legacy grant
  on the shared binary is removed in the same polkit prompt
- fix NameError in the mux startup failure path (undefined mux_name) that
  hid the log tail and skipped teardown
- README: disclose plain-UDP DNS endpoints (8.8.8.8 via tunnel, 223.5.5.5
  direct in rules mode) alongside the TUN DoH endpoint

---------

Co-authored-by: Umedjon Bazarov <170195993+UmedjonBA@users.noreply.github.com>
2026-08-09 21:03:02 -04:00
..

Ruh VPN

Ruh VPN is a VPN and proxy manager for sing-box. It manages SSH, VLESS, VMess, Shadowsocks and SOCKS5 connections from a Noctalia bar widget, panel and control-center shortcut.

Plugin

Field Value
ID umedbazarov/ruh-vpn
Entries Bar widget: vpn_widget; panel: vpn_panel; service: vpn_service; shortcut: vpn_toggle

Requirements

The backend requires sing-box, python3 and pkill, plus the Python packages declared in pyproject.toml: pydantic, aiofiles, aiohttp and aiohttp-socks. The plugin never installs packages itself: it checks the configured interpreter at startup and, if something is missing, reports the exact package names in the panel and does not start the backend.

Install the packages either from your distribution (e.g. python-pydantic, python-aiofiles, python-aiohttp on Arch), or into a dedicated virtual environment:

python3 -m venv ~/.local/share/ruh-vpn-venv
~/.local/share/ruh-vpn-venv/bin/pip install pydantic aiofiles aiohttp aiohttp-socks

Then set the backend_python setting to that environment's interpreter, e.g. ~/.local/share/ruh-vpn-venv/bin/python3. The default backend_python value is python3, which works when the packages are installed system-wide.

SSH connections require ssh; password-based SSH connections additionally require sshpass. System proxy mode requires gsettings. TUN mode and the kill switch use pkexec, setcap, getcap and nft for privileged operations.

Usage

Add the Ruh VPN widget under Settings → Bar, or add the vpn_toggle shortcut to the control center. Click the widget to open the panel. Select or add a server, choose the routing mode (rules or global) and connection mode (system or tun), then enable the main switch.

Open or close the panel with:

noctalia msg panel-toggle umedbazarov/ruh-vpn:vpn_panel

Settings

Setting Type Default Description
backend_python file python3 Python executable with the backend packages installed.
auto_start bool false Connect the active server when the plugin service starts.
geoip_country bool true Resolve server countries through api.country.is.
control_port int 11090 Loopback HTTP port used by the Luau entries and Python backend.
show_ping bool true Show active-server latency in the bar.
show_traffic bool false Show live upload and download rates in the bar.

Notes

  • The service starts the Python backend, which starts sing-box and, for SSH connections, ssh or sshpass. sing-box is resolved from PATH.
  • SSH host keys are recorded on first connect into a known_hosts file inside the plugin data directory and verified on every later connect; a changed host key makes the connection fail instead of being ignored.
  • Server passwords and UUIDs never leave the backend: the panel lists servers without secrets, and an empty secret field when editing keeps the stored value.
  • Persistent settings, servers, subscriptions and generated sing-box configuration are written under the directory returned by noctalia.pluginDataDir(). Runtime state and logs are stored in its runtime/ subdirectory.
  • The backend listens on the configured loopback control port. It does not bind the control API to an external interface, and every RPC call requires a per-launch bearer token stored in a user-only (mode 0600) file under the runtime directory, so other local users cannot control the VPN or read server credentials.
  • Network access includes configured VPN endpoints and subscription URLs, api.country.is when country detection is enabled, Cloudflare's speed-test endpoint, and remote rule sets enabled by routing presets.
  • DNS in the generated configurations: Google DNS (8.8.8.8) over plain UDP through the proxy tunnel; AliDNS (223.5.5.5) over plain UDP directly, as the resolver for direct-routed and unmatched domains in rules mode; Google DNS-over-HTTPS (8.8.8.8, through the tunnel) in TUN mode.
  • TUN mode grants CAP_NET_ADMIN, after a PolicyKit prompt, to a private copy of sing-box kept in a user-only (mode 0700) directory under the plugin data directory — never to the shared system binary. The copy is recreated whenever the system sing-box changes, which also clears the previously granted capability. The kill switch installs a dedicated nftables table and removes it when disabled.