Repository navigation
Xrayebator v0.6.0
Xrayebator v0.6.0 — the panel learned to revoke access and to expire profiles
An update to the server manager and the Xrayebator Desktop GUI. Installs over
v0.5.5— migrations do the work, no need to reconfigure existing servers.
In two words
Until now the panel could create keys but could not handle them when things went wrong. If a subscription link leaked into a chat, the only option was to delete the profile and reissue links to everyone.
v0.6.0 closes three gaps:
- Subscription revoke — a button on every profile. "New link only": the
sub_tokenand URL change, routes and keys stay the same, downloaded configs keep working. "Full revocation": uuids rotate too — already-downloaded configs are cut off immediately. Only full revocation actually closes access through a leaked link. - Profile expiry — a profile can now carry an expiry date. The server switches the client off by itself when the date passes and restores it on renewal; clients do not re-import anything. In the GUI: a date chip with a warning three days before the cutoff, a calendar picker and +7/+30/+90/+365 presets.
- An expired profile no longer hands out routes — the subscription answers a truthful
410 Goneinstead of a "working-looking" link that would not connect anyway.
┌─────────────────────────┐
│ Xrayebator Desktop │
│ profile "friend" │
│ until 2026-12-31 ⚠ 3 days left
│ [Revoke] [Expiry] [QR]│
└───────────┬─────────────┘
│
revoke: new token (+ uuid on full revocation)
expiry: timer removes the client from inbounds → 410
renewed: the same uuid comes back → 200
What is new
1. Revoke: two modes instead of "delete and recreate"
- New link only — reissues
sub_token. The old URL dies instantly; routes, ports and keys stay untouched — nothing changes for people who did not leak anything. - Full revocation — a new token and a new uuid in every route of the profile. Devices that already downloaded the config disconnect — the only real way to close access through a leaked link. It requires a second confirmation; on success the panel shows the new link right away.
Command: xrayebator profile-revoke --name NAME [--full]. The transaction keeps config and profile from ever diverging: config + validation + restart first, profile JSON second; if the second step fails, the config rolls back from the transaction backup.
2. Expiry: the server switches off by itself
- CLI:
profile-create --expire DATE(a date straight at creation),profile-expire --name NAME --expire DATE|epoch|none,expire-check; - profile JSON carries
.expire(epoch seconds,0= unlimited); - enforcement is server-side: the
xrayebator-expire.timersystemd timer runsexpire-checkevery 10 minutes and removes the client from the inbounds when the date passes. The GUI does not need to be open — the date still fires; - renewal restores the very same client: the snapshot lives in
.expire_clients, so uuid and every link issued earlier stay valid; - a date without a time is inclusive: "September 30" lives until
23:59:59on the server's clock; - the
profilesJSON now carriesexpire_datenext to the epoch — the calendar date in the server's timezone. A desktop in another timezone does not turn "until 30.09" into "until 29.09".
Why the inbounds are never recreated: a fresh inbound means a new Reality shortId, which would kill every link ever issued. Disabling is a surgical edit; the routes stay alive.
3. 410 Gone for expired profiles
An expired profile used to keep serving its link list: the client imported a config that could not connect, and it looked like a VPN bug. The subhttp handler now checks both the disabled flag and the raw timestamp (the timer runs every 10 minutes — the date can pass between runs) and answers 410 Gone with the body Profile expired or disabled. The subhttp_expired_410_2026 migration regenerates the handler on existing servers — the behavior switches on by itself after the update.
4. A calendar of our own in the panel
Expiry is no longer the system input[type=date]: a themed calendar with square day cells, today highlighted and the selected day in the accent tone; past days are disabled, backward paging stops at the current month, and the header never jumps around while paging.
5. Real error messages instead of "exit code 1"
CLI failures now surface the actual reason: it is parsed from stderr, and from stdout when stderr is empty (the manager prints some errors exactly there). An unknown command on an outdated server now comes with a hint — "update Xrayebator" — instead of a bare exit code.
6. The update branch is remembered
xrayebator update <branch> replaced the script but did not record the branch: the next "Update Xrayebator" click silently rolled the server back to main, and fresh commands disappeared. Now the branch is pinned to .current_branch right after a successful self-update, and the branch name is validated before it goes into a URL. This fixes the "updated — but the feature is not there" trap.
What else is in this release
docs/superpowersremoved — agent development plans, not product documentation.- Documentation synchronized across Russian, English and Chinese: new commands in the CLI reference, the
expire_datecontract, the "expires soon" chip tone, the outdated-server warning, and a troubleshooting entry about the 410 subscription response. - bypass did not change: the server-side implementation and menu entry 7 stay as they were. Domain bypass in the GUI is not part of this release.
How tested this is
Automated:
- Bash validation: 28 scripts, including the new
test-profile-revoke-expire-cli.sh(both revoke modes, expiry, idempotentexpire-check, JSON-clean stdout,expire_dateacross timezones, dates with leading zeros) andtest-update-branch-pinning.sh(branch pinning); - GUI: Vitest for the calendar and the expiry helpers; typecheck and the packaging build are clean;
- CI on Ubuntu/Windows/macOS — green.
On a live VPS (Debian 13): setting a past expiry → 410 Gone with the body Profile expired or disabled and the client removed; clearing the date → 200 with the same routes; revoke --full rotates uuid on every shared port without touching other clients; "Update" from a pinned branch no longer drops the features.
Field notes (live-session experience, no personal data)
Findings that save hours to anyone running Reality — they are also the real cause of "it is configured right but does not work":
- Reality needs a TLS1.3 dest with an X25519 key_share. Some governmental domains answer with
ECDH prime256v1on certain CDN edges, and every route with such a dest silently degrades (target sent incorrect server hello). Check from the VPS itself:echo | openssl s_client -connect host:443 -tls1_3and look atServer Temp Key:. Which edge your VPS reaches — and how it behaves — changes over time. - PQ xhttp requires the paired
encryption=string. A client withencryption=noneon a PQ route hangs without a single log line. PQ is intentionally excluded from the subscription body (the URL is ~2 KB) — that is size, not a bug. - Reachability before protocols. If plain ping and direct TCP to the subscription/VPN ports already fail, the IP is blocked upstream — no dest/SNI edits will help. The order that saves hours: reachability → the 200/404/410 subscription contract → tunnels.
- Testing hygiene: change runtime state only through the manager CLI (backup + validation + rollback come free), restore debug settings from the same backups, and do not leave scripts with real keys or packet dumps in the repo or on the server.
Before you update
Server requirements
- Debian 12/13 or Ubuntu 22.04/24.04, systemd, bash, root/sudo;
- migrations catch the state up on the first menu run or quickstart.
Breaking changes
There are none. .expire/expire_date are additions only; profiles without a date behave exactly as before; profiles command output stays compatible.
Honest limitations
- enforcement lags up to 10 minutes (the timer period); releasing the date through CLI/GUI is immediate;
- servers older than this release do not report
expire_supported— the panel says the server is outdated instead of pretending every profile is unlimited; probe-testchecks TLS1.3 on a dest but not the key-share type — see the field notes above.
How to update
Server
sudo xrayebator update mainXrayebator Desktop GUI
- Download the package for your OS from GitHub Release.
- Install over the previous version — server cards are kept.
- Open Server Settings: every profile now has Revoke and Expiry buttons.
Builds
The release is built natively for three platforms:
- Windows —
Xrayebator-0.6.0-win.exe; - macOS Apple Silicon —
Xrayebator-0.6.0-mac-arm64.dmgand.zip(the ZIP feeds the built-in auto-updater); - Linux —
Xrayebator-0.6.0-linux.AppImage.
Before packaging, Ubuntu CI runs typecheck, unit tests and the full Bash validation suite (28 scripts).