Repository navigation
Xrayebator v0.7.0
Xrayebator v0.7 — multi-protocol, PQ on every transport, DNS-01 and a reworked panel
An update of the server manager and the Xrayebator Desktop GUI. It installs over
0.6.0(and over any0.6.5-beta) — migrations finish the rest on their own, servers do not need to be reconfigured. Found a problem, have logs or errors — post them in the comments of this release or a separate issue: logs are the fastest way to a fix.
Changes since 0.6.5-beta.2
That cut shipped unchanged code, but everything accumulated after it (112 commits) was not in beta.2. In short:
- PQ on every transport:
mlkem768x25519plusis no longer hard-wired to xhttp —profile-pq --transport tcp|tcp-utls|tcp-xudp|tcp-mux|grpc|xhttpadds a post-quantum route on any of them, with its own inbound and port (VLESSdecryptionis inbound-level). - Four subscription bodies from one token: Clash/mihomo (YAML) and sing-box (JSON) join HAPP and base64; the body is chosen by
?target=andUser-Agent, the default is still HAPP. - DNS-01 as a deployment fallback plus
repair-dns01for a subscription that already degraded: the chain is "existing cert → http-01 on the IP → DNS-01 →http_tls". - ACME staging contour and
dns01-test: a verification-only issuance in staging with its own lineage and no side effects, so debugging no longer burns the production Let's Encrypt quota. - Per-profile traffic limits: accounting through the Stats API, automatic disabling on overrun,
profile-limit/traffic-check, a chip and a dialog in the GUI. - Telegram alerts and monitoring:
alerts-setup,monitor-checkevery 15 minutes (units, backends, expiry, limits, subscription liveness, TLS mode, SNI probe, reboots). The GUI has no alerts surface any more — terminal only. channel-test: channel verification with a real Xray client, no Let's Encrypt needed, PQ routes included.- A GUI wave from feedback: the "Existing profiles" page split off from creation, sections in the server settings, a collapsible "Subscription and TLS" card, a shorter deployment form, backend keys next to a profile, the green "Done" button.
- Fixes found on live servers:
profile-pqno longer drops the base route,profile-deleteleaves no orphaned inbounds, the SNI probe rejects unreachable hosts,?target=v2raydoes not return the HAPP body, traffic accounting actually counts, AWG comes back after a reboot, and jq 1.6 no longer breaks PQ on Ubuntu 22.04. - Documentation is synchronized across three languages and cross-checked against the code; the test set grew to 42 scripts (from 28).
In two words
Until now the server spoke one protocol — Xray Reality over TCP. Censorship strangles TCP, and the whole VPN dies with it: one transport, one point of failure.
v0.7 puts two more transports on the same server, and the panel learns to manage them:
- Hysteria 2 — a UDP/QUIC transport: fast on bad links, alive where TCP is cut;
- AmneziaWG 3.1 — a system VPN (WireGuard with anti-DPI junk in the headers): a full tunnel, native AmneziaVPN apps;
- Per-profile grants — each protocol's key is issued separately and lives in the profile's lifecycle: revoke, expiry and deletion revoke the backend keys together with VLESS.
┌────────────────────────────────────────────────────────┐
│ one VPS │
│ │
│ Xray (Reality, TCP) ── ports 443 / high 30xxx │
│ Hysteria 2 (QUIC, UDP) ── its own port │
│ AmneziaWG 3.1 (UDP) ── awg0, its own port │
│ │
│ subscription: vless:// + hysteria2:// + HAPP routes │
└────────────────────────────────────────────────────────┘
▲ ▲ ▲
│ │ │
HAPP / v2rayNG HAPP / Hiddify AmneziaVPN
( Reality+Hysteria ) ( Reality+Hysteria ) ( AmneziaWG 3.1 )
The client subscription stays one: hysteria2:// lines go into the same bodies (with a kill switch in the GUI), the AWG config is handed out as a .conf file or a QR, and for the full AmneziaVPN app in its native vpn:// shape. A single token serves four bodies: HAPP, base64 v2ray, Clash/mihomo and sing-box.
What's new
1. A neutral backend registry
The add-on protocol state lives in the neutral root /usr/local/etc/xrayebator/ (the backends.json registry is 644 with no secrets, the runtime state with secrets is 750). /usr/local/etc/xray/ stays Xray-only. A single choke point — _backend_apply_profile_lifecycle — runs every profile lifecycle through all installed backends, so revoke/expiry/deletion never leave orphaned credentials.
2. Hysteria 2 (UDP/QUIC)
- installed from the official
HyNetworks/hysteriareleases with a sha256 check, a dedicatedhysteriasystem user and its ownhysteria-server.service(CAP_NET_BIND_SERVICE, auto-restart), QUIC buffers in sysctl; - TLS is adaptive: if the subscription has a Let's Encrypt certificate it is copied into the backend (with a renewal deploy hook), otherwise a self-signed one is generated — and the client links honestly carry
insecure=1; - per-profile keys: the password lives in the profile's
.backends.hysteria2, andserver.yamlis always regenerated from the profiles — revoking or extending a key is a regeneration plus a restart with rollback; hysteria2://is appended to both bodies (HAPP and v2rayNG) and is controlled by a kill switch without a service restart.
3. AmneziaWG 3.1 (system VPN)
- the kernel module via DKMS: the primary path is the
amnezia/ppaPPA, the fallback is a source build (kernels ≥5.6 need the fulllinux-sourcetree); the module is loaded at boot, otherwise the tunnel stayed down after a reboot while the card said "active"; - junk parameters match the official Amnezia dialect one-for-one (Jc=5, Jmin/Jmax, H1–H4, S1–S4): their native apps apply them predictably;
- format 3.1 is on by default:
HeaderProtectionKey,RandomTrailers,S3/S4; theawg-31toggle exists with an explicit warning — previously issued client.conffiles have to be downloaded again (AmneziaVPN ≥ 5.0.1.5); - per-profile peers: a client key pair plus a preshared key, addresses from
10.8.1.0/24;awg0.confis regenerated from the profiles; - the client
.confis a full tunnel (AllowedIPs = 0.0.0.0/0, ::/0), keepalive 25; in the GUI a key can be taken as.conf, QR, or "QR · AmneziaVPN" — the nativevpn://shape that the app imports whole (a raw.confpasted into the full AmneziaVPN app does not reach its tunnel intact).
4. PQ (VLESS Encryption) on every transport
xrayebator profile-pq --name N [--transport tcp|tcp-utls|tcp-xudp|tcp-mux|grpc|xhttp]adds a post-quantum route (mlkem768x25519plus) on any transport;- VLESS
decryptionis inbound-level, so a PQ route gets its own inbound and port with the shared key from.vless_decryption; ordinary routes keepencryption=noneand stay usable by every client; - PQ routes are hidden from the base64/v2ray body (a client without ML-KEM could not connect anyway) and skipped with a reason in Clash/sing-box; the HAPP body keeps them;
profilescarries the additivepq_routescounter — the top-levelpq_enabledonly describes the first route.
5. Subscription: four bodies from one token
- HAPP, base64 v2ray, Clash/mihomo (YAML) and sing-box (JSON) are rendered from one link set; the body is chosen by
?target=andUser-Agent, HAPP by default so already-issued links keep working; - routes a client cannot use (PQ, xhttp in sing-box, xhttp in Clash without
?xhttp=1) are skipped with a reason instead of breaking the whole config; subscription-userinfois sent for every body; format links are cached in the server card, so the GUI no longer grows them after the SSH answer;- in the GUI this is an extra view, not an obligation: by default the Keys page serves the main set — the HAPP/v2ray subscription and the VLESS links, as before — and the Clash/sing-box formats are switched on by the «Clash / sing-box formats» toggle in the page header. Without it the same token was printed three times per profile, which read as a duplicated key.
6. DNS-01 and ACME
dns01-setup --domain --provider cloudflare|route53issues a certificate through a TXT record — inbound port 80 is not needed at all;repair-dns01converts a subscription that already degraded tohttp_tlsonto a domain, idempotently;- the staging contour (
--staging) anddns01-test— a verification-only issuance with its own lineage, no deploy hook and no side effects: debugging no longer burns the production quota (5 certificates per exact identifier set per 168 hours); dns01-statusdecides the contour from the certificate itself and accepts both spellings of the hook record (deploy-hook/renew_hook).
7. Per-profile traffic limits
- accounting through the Xray Stats API (a loopback
dokodemo-door), deltas against a watermark — an Xray restart does not lose already-counted bytes; profile-limit --name N --limit 500MB|2TB|none [--reset],traffic-checkevery 5 minutes; on overrun the client is removed from the inbound and restored when the limit is raised;- expiry and limits are cross-guarded: a profile does not come back while the other restriction still applies;
- the GUI shows a chip in the profile card and a limit dialog.
8. Telegram alerts and monitoring
alerts-setupvalidates the token withgetMeand delivers a test message before writing the config — an undeliverable chat never leaves a half-configuration;monitor-checkevery 15 minutes: units, installed backends, approaching and expired profiles, profiles disabled by a limit, subscription liveness, TLS-mode degradation, a daily SNI probe, reboots;- deduplication, "no more often than once per N", and a retry after a failed send live in
monitor-state.json; - the desktop app has no alerts surface — the bot token has exactly one entry point, the terminal.
9. Lifecycle: keys do not live on their own
- Profile creation — a key is NOT issued automatically: the operator picks a protocol in the GUI (or runs an explicit
hysteria2-grant/awg-grant), otherwise every new profile would receive keys from all installed backends at once; - Revoke — rotates the Hysteria password and the AWG peer key pair plus PSK (old configs stop connecting, the address is kept);
- Expiry/extension — for backends this is a regeneration from the profiles filtered by the disabled flag: an expired profile stops receiving its key, an extended one comes back;
- Profile deletion — the peer is removed from
awg0.confand the password leavesserver.yamlin the same command; no orphaned credentials.
10. GUI: sections, a profiles page and compact cards
- "Server settings" is split into sections instead of one long scroll; panels are hidden by an attribute, so typed input is not lost on switching;
- an "Existing profiles" page separate from creation: search by name/SNI/subscription domain, an "All/Active/Disabled" filter, a card counter; both screens live in one component, so switching does not open a second SSH session;
- the "Subscription and TLS" card is collapsible: a certificate icon, the mode as a badge, three values in monospace boxes;
- the deployment form is a quarter shorter: the IP shares a row with the SSH port, PQ and DNS-01 sit in one "Additional options" block, and the host-key note is the progress card's footer;
- the backend panel in "Server settings": official logos, state (version, port, TLS mode / interface, junk summary), install/uninstall, and a "Start" button for an installed but idle backend;
- backend keys next to a profile, on par with VLESS: QR (including "QR · AmneziaVPN"), expiry with presets, Revoke, delete; confirmations use the soft danger style.
11. HAPP routing: split routing from bypass groups
The managed HAPP profile can be assembled from bypass sets (bypass list/add/remove/reset/bundle): domains of the selected groups go direct, everything else goes through the tunnel. The client downloads geo bases through the subscription itself ({{GEOIP_URL}} / {{GEOSITE_URL}} / {{LAST_UPDATED}} placeholders are rendered per subscriber — the base URL is bound to their token).
12. quickstart degrades to http_tls instead of dying
Some hosters filter inbound port 80 for foreign sources — Let's Encrypt cannot validate http-01 for a bare IP (Connection reset by peer from validation hosts). That used to be a dead end; now:
- the deploy finishes with
degraded:true,tls_mode:"http_tls"and the certbot reason; - the subscription stays loopback-only — there is no public URL at all: the GUI fetches keys over SSH from
http://127.0.0.1:8080/sub/<token>on the server itself (nothing can leak); - a self-signed certificate is prepared in advance for future Hysteria installs;
- if a domain and a DNS provider token are supplied, the fallback goes through DNS-01 and the subscription stays on HTTPS;
- the ACME location on :80 is kept: once the hoster unblocks the port, a repeated quickstart (idempotent) issues the LE certificate and restores HTTPS.
The GUI stores such a server as "Partially configured" with a degradation note.
13. SNI and country
probe-testand the default SNI choice follow a strict criterion: a completed TLS 1.3 handshake with a verified certificate and an HTTP answer, two measurements, a 3 s budget per attempt. An unreachabledestis no longer handed to fresh profiles;- subscription keys are labelled with the server country: fragments look like
🇫🇮 Finland · happ-*— handy when there are several servers.
Also in this branch
profile-pqno longer discards the base route of the profile it was asked to extend (the single-route shape is expanded intoroutes[]first);profile-deleteleaves no orphaned inbounds: the port set is the union of the top-level.portand everyroutes[].port;?target=v2rayno longer returns the HAPP body; the rule that dropped an xhttp route from HAPP is gone — it silently removed a workingxhttp-pq;- jq 1.6 no longer breaks PQ (
labelis a keyword): the route is created on Ubuntu 22.04 / Debian 12 too; quickstart --pqis no longer dead code — the block moved out of the failure branch it used to sit in;- traffic accounting is enabled where the Xray policy actually reports it (
statsUserUplink/Downlink), plus a repair migration for servers with an early marker; - AWG:
S1 != S2, the card's label and colour come from one field,revokerotates the PSK too; inspect --jsonno longer reports installed backends as missing;xrayebator-uninstalltears backends down before removing state;revoke --fullworks on single-route profiles;profile-deleteprints JSON only;- GUI polish from feedback: the profile row is one line, "valid until" no longer shifts the card, the update-branch menu is a HeroUI
Dropdownagain, and the green "Done" button has no blur.
Stability and security
- TLS and ACME. The staging contour and
dns01-testverify a domain and a token without burning the production Let's Encrypt quota;dns01-statusdecides the contour from the certificate itself and accepts both spellings of the hook record; the short-lived IP certificate no longer fights the distributioncertbot.timer;repair-dns01no longer shifts the subscription port. - Access. The SSH host key is pinned on the first successful login, root/sudo is an explicit choice, passwords and keys live in the system keychain; DNS-01 credentials are stored on the server in a
0600root file and are never kept by the GUI; the Telegram bot token is not printed by any command and is configured from the terminal only. - Subscription. PQ routes are kept out of bodies a client without ML-KEM could not use anyway, and unsupported routes are skipped with a reason instead of shipping a broken config; deleting a profile no longer leaves orphaned inbounds still serving the removed profile.
- Limits. Hitting a traffic limit removes the client from the inbound and restores it when the limit is raised; expiry and limits are cross-guarded, so one restriction cannot be bypassed through the other.
- Network. The default SNI is chosen only by a strict criterion — a completed TLS 1.3 handshake with a verified certificate and an HTTP answer — so fresh profiles no longer receive dead routes.
- Reliability. Migrations are idempotent and registered on every entry path;
safe_restart_xrayvalidates the config and rolls back on failure; UFW rules and nginx vhosts are tracked by a manifest so removal leaves no leftovers.
How well this is tested
Automated:
- Bash validation: 42 scripts (up from 28) — new ones cover PQ on every transport, subscription formats, DNS-01/certbot, the
quickstartTLS fallback, traffic limits, alerts/monitoring, the Hysteria 2 and AmneziaWG lifecycles, the backend registry,channel-test, HAPP client routing, SNI reachability, legacy profile port sync, and jq 1.6 compatibility; - GUI: 25 Vitest files (172 tests) — AWG export (
vpn://, range timers, qCompress), backend-manager, the inspector, render tests for the settings and profiles pages, andru/en/zhi18n parity; typecheck and build are clean; - CI on ubuntu-24.04 runs all 42 scripts; bundles are built on three OSes.
Live runs: three deployments with live measurements — two control deploys from scratch on Ubuntu 22.04 (the GUI default mode and one with the PQ route enabled) and a production server deployed earlier, where the profiles, subscription bodies and both backends were verified; plus control deploys on four distributions (Ubuntu 22.04/24.04, Debian 12/13), including the http_tls fallback on a hoster filtering :80. All three were checked with a real Xray client on every route, post-quantum ones included (HTTP 200, ≈170–330 ms); all four subscription bodies from outside; Hysteria 2 and AmneziaWG installs and grants; a vpn:// import into AmneziaVPN ≥ 5.0.1.5; and the CLI self-update main → dev.
And manual device testing: every route of all three deployments connects and works from a phone and from a PC through HAPP and Hiddify — link acceptance out of the subscription is verified not only server-side but by real clients.
Before you upgrade
Server requirements
- Debian 12/13 or Ubuntu 22.04/24.04, systemd, bash, root/sudo;
- for AmneziaWG — kernel ≥ 5.6 and a working DKMS build (PPA or sources);
- migrations catch the state up automatically on the first menu launch or quickstart.
Breaking changes
There are none for existing VLESS installations: everything is additive, profiles and the subscription stay compatible. Worth knowing:
- one AWG key = one device — two devices on the same
.confwill fight over the endpoint; - Hysteria under a self-signed certificate runs with
insecure=1— a deliberate mode until an LE certificate is issued; - an
http_tlsserver has no public subscription — keys are taken over SSH from the GUI (or with curl over SSH on the server); - a PQ route is not part of the base64/v2ray body — HAPP gets it, other clients need ML-KEM;
- Telegram alerts are configured from the CLI only — the GUI no longer has that surface.
Honest limitations
- the routes of all three deployments were also verified on devices — from a phone and from a PC through HAPP and Hiddify they connect and work; per-app latency was not measured separately, the numbers in this release come from
channel-teston the server; - a real AmneziaWG client connection and the network parts of backend installs were verified in a live spike, not in CI — DKMS builds and tunnels are not reproducible there;
- restarting
awg0on a grant/revoke briefly drops the tunnel for every peer; - HAPP geo bases are unavailable to a client without preloaded bases under an
http_tlsfallback ("no data" — not a broken key).
How to upgrade
Server
sudo xrayebator update mainBackends are not installed automatically: after the update open "Server settings" → "Extra protocols" and install Hysteria 2 and/or AmneziaWG with the button. Keys are issued per profile — creation goes through the protocol choice.
Xrayebator Desktop GUI
- Download the package for your OS from the GitHub Release.
- Install it over the previous version — server cards are preserved.
- New: the "Existing profiles" page, settings sections, the compact "Subscription and TLS" card, backend cards next to a profile, Hysteria/AWG keys on the "Keys" page.
- The "Update Xrayebator" button is now a branch menu: "Auto — as pinned on the server", "main — the latest stable", "dev — all the new stuff at once" (may be unstable — that is how this beta reaches a server before the release).
Build
The release is built natively for three systems:
- Windows —
Xrayebator-0.7.0-win.exe; - macOS Apple Silicon —
Xrayebator-0.7.0-mac-arm64.dmgand.zip(the ZIP is needed by the built-in auto-updater); - Linux —
Xrayebator-0.7.0-linux.AppImage.
Before building on Ubuntu the pipeline runs typecheck, unit tests and the full Bash validation set (42 scripts).