A focused Linux desktop client for V2Ray-style links, built with Python 3.11+, PyQt6, and Xray-core.
Current release: v0.2.4 · Status: Beta (stable for daily use with a focused feature scope)
Download the latest release · Changelog · Developer guide
The v0.2.1 History view shows local daily totals, session summaries, and a bounded, peak-preserving session chart. Screenshot connection details are placeholders.
- A bounded background storage worker keeps recurring SQLite writes off the GUI thread.
- Live statistics, Traffic Monitor tabs, history queries, and diagnostics now refresh independently to keep long sessions responsive.
- Automatic session charts preserve traffic peaks while querying and rendering no more than 900 points.
- Ordered, repeat-safe shutdown saves final traffic state, restores session-owned proxy settings, and reaps only processes started by the GUI.
- Application and Xray logs rotate within documented limits; detailed Xray diagnostic logging is opt-in.
- Privacy-safe diagnostics report runtime performance, database/log sizes, process ownership, proxy state, and netmon readiness without exposing profile secrets.
See the v0.2.1 release notes for the complete upgrade and packaging details.
- Validate and run
vless://profiles through a bundled, custom, or system Xray-core. - Save multiple profiles with favorites, a default profile, duplication, editing, deletion, and validation that persists across restarts.
- Expose local SOCKS5 and HTTP proxies, automatically selecting free ports when the defaults are unavailable.
- Optionally apply, audit, repair, and safely restore supported desktop system-proxy settings while connected.
- Check connection health, server latency, proxy download speed, uptime, live throughput, and cumulative traffic.
- Explore Overview, Applications, Proxy Profiles, History, Settings, and Diagnostics in the Traffic Monitor.
- Store traffic locally in SQLite with daily/monthly totals, per-profile usage, session drill-down, charts, configurable retention, and CSV exports.
- Keep long-running monitoring responsive with bounded background persistence, cached history sections, and peak-preserving chart downsampling.
- Inspect Xray, proxy, traffic database, process ownership, and optional
v2link-netmonhelper readiness without running the GUI as root. - Check GitHub Releases for updates and switch between light and dark themes.
- Linux desktop environment (GNOME, KDE, or another desktop that can use the local manual proxy endpoints)
x86_64system for official AppImage and Debian/APT packagesaarch64source support is retained, but official ARM64 artifacts await native CI
Official AppImage, .deb, and APT releases include bundled Xray-core for normal operation. Source builds may use bundled vendor files from ./scripts/fetch_xray_core.sh or a system xray from PATH as a fallback.
Primary supported release artifacts:
- AppImage
- Debian package (
.deb)
Also available for Debian/Ubuntu users:
- APT repository (published from release workflow)
- Download the AppImage from the latest GitHub release.
Expected artifact name pattern:
v2link-client-<version>-linux-<arch>.AppImage- the currently published official architecture is
x86_64
- Make executable and run:
chmod +x v2link-client-*.AppImage
./v2link-client-*.AppImage- Optional launcher setup:
mkdir -p ~/.local/bin
cp v2link-client-*.AppImage ~/.local/bin/v2link-client.AppImage
chmod +x ~/.local/bin/v2link-client.AppImageCreate ~/.local/share/applications/v2link-client.desktop:
[Desktop Entry]
Name=v2link-client
Exec=/home/YOUR_USER/.local/bin/v2link-client.AppImage
Icon=v2link-client
Type=Application
Categories=Network;
Terminal=false- Download the
.debfrom the latest GitHub release.
Expected artifact name pattern:
v2link-client_<version>_<arch>.deb<arch>isamd64orarm64
- Install:
sudo dpkg -i v2link-client_<version>_amd64.deb
sudo apt -f install- Launch:
v2link-clientImport the repository key:
curl -fsSL https://udayasri0.github.io/v2link-client/apt/public.key \
| gpg --dearmor \
| sudo tee /usr/share/keyrings/v2link-client-archive-keyring.gpg >/dev/nullAdd the source list:
echo "deb [arch=amd64,arm64 signed-by=/usr/share/keyrings/v2link-client-archive-keyring.gpg] https://udayasri0.github.io/v2link-client/apt stable main" \
| sudo tee /etc/apt/sources.list.d/v2link-client.list >/dev/nullInstall:
sudo apt update
sudo apt install v2link-clientpython3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
pip install -r requirements.txt
./scripts/dev_run.shFor editable installs, architecture notes, important runtime invariants, tests, packaging, isolated XDG environments, and contribution guidance, see the Developer guide.
Build AppImage only:
./scripts/build_appimage.shBuild .deb only:
./scripts/build_deb.shBuild full release set (PyInstaller + AppImage + .deb + checksums):
./scripts/build_release.shThe release build fetches a pinned official Xray-core release into vendor/xray/<arch>/ and bundles it into the AppImage and .deb. Maintainers can refresh the vendor copy directly:
./scripts/fetch_xray_core.shDevelopers can normally use ./scripts/dev_run.sh; it fetches and verifies the pinned
official release once when the native vendor copy is missing. Disable that network
bootstrap with V2LINK_SKIP_XRAY_FETCH=1 ./scripts/dev_run.sh.
GitHub's automatically generated Source code ZIP and tar.gz files are not prebuilt
Linux applications. Ordinary users should download the named AppImage or .deb, both
of which contain Xray-core and its geo assets.
Artifacts are written to dist/:
v2link-client-<version>-linux-<arch>.AppImagev2link-client_<version>_<arch>.debSHA256SUMS
The manually triggered GitHub Actions release workflow validates the version and curated notes, tests the project, fetches checksum-pinned Xray-core, builds and verifies the AppImage and Debian package, and supports a non-publishing dry run.
See the maintainer release process for preparation, dry-run, publication, APT signing, and safe recovery instructions.
Public key file is committed at apt/public.key.
Export matching private key:
gpg --armor --export-secret-keys "v2link-client APT Repository <apt@v2link-client.local>"GitHub secrets:
APT_GPG_PRIVATE_KEY: ASCII-armored private keyAPT_GPG_PASSPHRASE: key passphrase (if protected)
- Paste
vless://link. - Click Validate & Save.
- Click Start.
- Enable System Proxy for desktop-wide proxying, or use Copy manual proxy settings.
The app resolves Xray-core in this order: custom path from Xray Settings, bundled Xray, then system xray from PATH. Diagnostics and About show the active Xray source, path, and version.
The Traffic Monitor records local traffic history and shows:
- Dashboard tabs for Overview, Applications, Proxy Profiles, History, Settings, and Diagnostics
- Today upload/download totals
- Current session upload/download and live speed
- This month upload/download totals
- Per saved-profile upload/download totals
- Daily usage aggregation and a lightweight in-app daily usage chart
- Daily history with Today, Last 7 days, Last 30 days, This month, and custom date ranges
- Session history for each selected date, including start/end time, duration, profile, download, upload, total, average speed, and status
- Session drill-down charts for speed or cumulative usage over time
- Advanced Applications tab with optional helper-readiness and attribution diagnostics
- Settings for detailed sample retention, CSV export, and clearing local traffic history
- Diagnostics for the stats API, helper readiness, and local traffic database
Proxy/profile tracking records traffic from Xray's Stats API while the core is running. It works in the normal GUI with no root permission because Xray provides proxy counters through its local API. The app does not use xray api -reset, so live labels and history do not fight over counters.
Live counters are polled every 2 seconds, while cumulative history is persisted every 5 seconds through one bounded SQLite writer. Overview work runs at most every 10 seconds and only for its visible tab. History and diagnostics do not query on live ticks. Automatic session charts load and render at most 900 peak-preserving points; detailed samples default to 30-day retention.
The original progressive stutter came from coupling each live callback to synchronous SQLite writes, full dashboard/history refreshes, and increasingly large chart reads. Those paths are now separated and bounded. See Traffic Monitor internals and runtime performance troubleshooting.
The main Diagnostics tab provides Copy diagnostics report, Copy latest error, and Save diagnostics report. Profile validation failures have a separate Copy validation error action, and the Applications helper card can copy structured helper diagnostics. AppImage and Debian builds include the same actions.
Displayed, copied, and saved diagnostic text is sanitized by default. Share/proxy URLs, UUIDs, email addresses, passwords, authentication and subscription tokens, API keys, cookies/session values, certificate/private-key material, certificate pins, and home-directory usernames are replaced with stable redaction placeholders. Reports are size-bounded and saved as UTF-8. There is no one-click raw-secret export.
Review a report before posting it publicly; automatic redaction is a defensive boundary, not a guarantee about every future third-party error format. A copied Xray validation error confirms offline configuration syntax only—it does not prove that a remote server was contacted or is reachable.
Bundled Xray-core is enough for proxy/profile tracking in official AppImage, .deb, and APT installs. Per-application tracking is separate and still needs the optional helper service described below.
Daily totals are aggregated by sample date and are useful for range summaries. Session totals are grouped by each Start/Stop run, so a connection from 20:00 to 20:30 appears as one session under that date. CSV export supports daily summaries, session summaries, and selected-session samples.
Traffic history is stored locally only in SQLite:
$XDG_DATA_HOME/v2link-client/traffic.sqlite3
If XDG_DATA_HOME is not set, the app uses the platform default data directory through platformdirs, usually ~/.local/share/v2link-client/traffic.sqlite3 on Linux.
Settings are stored at:
$XDG_CONFIG_HOME/v2link-client/traffic_settings.json
Per-application tracking is advanced and optional. It is separate from normal proxy/profile traffic tracking, which works through Xray's Stats API without root permission. The optional system helper v2link-netmon is installed by Debian/APT packages under a dedicated non-login account. The GUI never runs as root.
The v0.2.4 helper backend is an explicit non-operational placeholder: it reports backend-not-implemented and returns no fabricated application counters. A future production eBPF backend requires a separate implementation and privilege review.
Debian packages do not enable or initially start the service, and they do not add desktop users to its group. An administrator may opt in explicitly:
sudo usermod -aG v2link-netmon "$USER"
sudo systemctl enable --now v2link-netmonLog out and back in after the group change. The helper socket is restricted to the service account and approved group members. Installed, daemon-reachable, and backend-operational are separate states; a running placeholder is not operational.
AppImage remains unprivileged and does not contain or install the system helper. It reports that a separately installed v2link-netmon system helper is required, while normal proxy operation and aggregate Xray traffic history remain available.
Traffic history never leaves your machine. Proxy/profile stats come from Xray counters. When optional application attribution is available, it records only local process names, executable paths, UIDs, and byte counters. It does not decrypt traffic, inspect packet payloads, read messages, collect tokens/cookies, or upload telemetry anywhere.
Per-application attribution, when available, is not perfect with a local proxy. When system proxy is enabled, apps may connect to 127.0.0.1 while Xray performs the encrypted remote connection, so some traffic can appear under Xray Core / Proxy Tunnel. Xray is shown separately and is not hidden.
- If proxy/profile totals stay at zero, confirm Xray is running and the diagnostics tab shows a configured stats API server.
- If the Applications tab says the installed service is inactive, opt in with the administrator-controlled commands above.
- If access is denied, confirm group membership and log out/in; do not run the GUI as root.
- If the daemon is reachable but reports
backend-not-implemented, per-application attribution is unavailable in this release by design. - For growing CPU, memory, logs, or suspected leftover processes, run
./scripts/diagnose_runtime_performance.shas your normal user. It prints aggregate sizes and process metadata, never profile URLs, credentials, traffic rows, or process arguments. Exit code1means it found a possible stale Xray/stats process to inspect; it never kills anything. - Closing V2Link stops only the GUI-owned Xray process group and temporary
xray api statsquerychild. The independent systemv2link-netmon.servicemay remain running by design. - Python logs rotate at 2 MiB with five backups.
xray_stdout.logis bounded to 2 MiB with two backups. Xray access logging is disabled by default; detailed bounded diagnostic logging can be enabled under Xray Settings. - AppImage builds work without the helper and report
external-helper-requiredfor optional per-application attribution. - For a support request, refresh the main Diagnostics tab and copy or save its sanitized report. Copy latest error selects the newest active actionable failure; successful recovery clears only that error category.
Currently implemented:
vless://security=tlsandsecurity=none- transport:
tcp,ws,grpc - optional:
sni,fp,alpn,pcs,vcn,flow - limited
headerType=httphandling for TCP
Not yet implemented:
vmess://,trojan://,ss://- REALITY and advanced routing profiles
- Saved profiles:
$XDG_CONFIG_HOME/v2link-client/profiles.json(fallback~/.config/v2link-client/profiles.json) - Preferences/legacy compatibility:
~/.config/v2link-client/profile.json - Optional custom Xray path:
$XDG_CONFIG_HOME/v2link-client/xray_settings.json - Traffic settings:
$XDG_CONFIG_HOME/v2link-client/traffic_settings.json - Traffic database:
$XDG_DATA_HOME/v2link-client/traffic.sqlite3 - Runtime state and logs:
$XDG_STATE_HOME/v2link-client/(logs are inlogs/)
Unset XDG variables use the normal Linux defaults under ~/.config, ~/.local/share, and ~/.local/state. To stop detailed sample growth, turn off proxy/profile history in Traffic Monitor → Settings; aggregate display still remains available for the live session.
Common causes:
- Invalid endpoint or blocked server
- Mismatched
sni/verification name and the server certificate - A legacy profile that depended on the removed
allowInsecurecertificate bypass
Actions:
- verify link/server settings without pasting the complete profile URL into reports
- obtain a current profile from the service provider when the legacy profile no longer verifies
- use provider-supplied
pcscertificate SHA-256 pins and/orvcncertificate verification names when required - inspect logs via Open logs folder
Xray-core 26.3.27 no longer accepts the legacy allowInsecure bypass. v2link-client
never emits that option. Legacy false values remain harmless, while legacy true
values are migrated to normal secure certificate verification and produce a
compatibility warning. If verification then fails, obtain an updated profile
from the service provider. The application never invents a certificate pin or
retrieves one from a remote server. Imported pcs values must be valid SHA-256
certificate fingerprints; vcn values select certificate verification names.
Install missing runtime library:
sudo apt update
sudo apt install -y libxcb-cursor0
