Skip to content

Security: howdeploy/Xrayebator

Security

docs/security.md

Security

← Back to README · Русский · 简体中文

Sections: Service account and permissions · Subscription security · SSH access to the VPS · Desktop GUI credentials


Service account and permissions

Xray runs as the system user xray. The drop-in /etc/systemd/system/xray.service.d/security.conf sets User=xray and narrows the capabilities to CAP_NET_BIND_SERVICE, which is enough for low ports. The manager state is deliberately outside the service account's write boundary.

The ownership model is:

Path or class Owner and access
/usr/local/etc/xray/ and its state directories Mostly root-owned and not service-writable; generated metadata such as .server_country may be xray-owned
config.json, profiles and migration markers Normally root:root and readable by Xray as required; a rollback helper may set the live config to root:xray with mode 0640
Reality and VLESS private key files root:root, mode 0600
public key files and generated metadata Readable where Xray or the subscription handler needs them; ownership can differ for generated metadata
/usr/local/etc/xray/scripts/ and /usr/local/bin/xrayebator* root:root, executable manager scripts protected from service-account replacement
/var/log/xray/ writable by the Xray runtime account for service logs

The service account can read the configuration it needs, but cannot replace executable manager scripts, markers or private keys. Most state/config files are root-protected, not universally immutable or necessarily root:root; do not treat .server_country as a private key or as a permission boundary. Backups are root-owned and kept separately from the live files. Do not put unrelated secrets in the Xray state directory.

Runtime configuration changes made by xrayebator use a backup, validated atomic write and the safe_restart_xray transaction. This scope is limited to runtime mutations owned by xrayebator. Install and update have separate validation, restart and rollback paths and are not guaranteed to be identical. After either lifecycle update, the operator should verify Xray, DNS and the subscription endpoint/service rather than assuming that a successful script exit proves every path is healthy.

Subscription security

The subscription URL is a bearer credential. It is not public, but anyone holding the full URL can download the route list and the token-protected subscription resources. The desktop GUI therefore masks the token (…) before the URL can appear in either console — the deployment log and the import wizard console; passwords and private-key bytes are never written there.

Already handled server-side:

  • a 32-character hexadecimal token generated by openssl rand -hex 16;
  • /sub/ without a valid token returns an identical 404;
  • a profile with no live routes returns 410 and serves no routes; a partially stale multi-route profile can still return its remaining live routes with 200;
  • nginx adds Cache-Control: no-store and rate-limits the subscription location;
  • the root path and paths outside /sub/ return 404;
  • Revoke rotates sub_token, so the old URL stops working.

Left to the operator:

  • do not post the subscription_url in public chats or issue trackers;
  • press Revoke immediately after a leak;
  • treat every saved vless:// link as a credential too;
  • never hand a local-only URL to an external client;
  • do not host third-party panels or proxies on the same domain without understanding the nginx configuration.

SSH access to the VPS

Xrayebator can be installed straight from root, but a dedicated user with narrowly scoped sudo is the better practice.

On the server:

adduser <username>
usermod -aG sudo <username>
su - <username>

On your own machine:

ssh-keygen -t ed25519 -C <your_email@example.com>
ssh-copy-id <username>@<server_ip>

Then log in as <username>@<server_ip>. Once key-based login works, disable passwords and optionally forbid root login:

sudo nano /etc/ssh/sshd_config
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes

Losing the SSH keys means losing access to the server. Confirm that key-based login works before disabling passwords.

A keep-alive helps the SSH session survive VPN reconfiguration:

ClientAliveInterval 60
ClientAliveCountMax 120
TCPKeepAlive yes

Desktop GUI credentials

The active Electron GUI supports SSH passwords and private keys, with direct-root or sudo execution. A private key selected through the native Electron file dialog is read by the main process and stored in the operating-system keychain via keytar (Windows Credential Manager, macOS Keychain, Linux Secret Service), so the same key can be reused for later operations and after app restarts without selecting the file again. When the OS keychain is unavailable there is deliberately no plaintext fallback: the key survives only in main-process memory for the current session and the UI warns that re-selection will be required after restart.

The SSH login password and a selected private key are persisted to the operating-system keychain after successful authentication — the password only after the first successful sign-in, the key when it is picked through the native file dialog — and are reused for later operations and after app restarts. When the OS keychain is unavailable there is deliberately no plaintext fallback: the key survives only in main-process memory for the current session and the UI warns that re-selection will be required after restart.

A distinct sudo password and an encrypted key's passphrase are never persisted; they are requested again in each session. Credentials and password values never cross the preload boundary — the renderer receives only non-secret credential ids and the display key name.

The GUI does persist the server metadata needed to return to a server, including the host, SSH port, username, authentication method, privilege mode, credential ids, display key name and installation diagnostics, plus preferences, the subscription_url, fetched vless:// links and the SHA-256 SSH host-key pin. The subscription URL and VLESS links are bearer credentials, so protect the local Electron application data and revoke the subscription if they leak. Removing the last server card that references a credential deletes that keychain entry; entries shared with another card are kept.

Existing and imported servers can also be managed read-only: importing over SSH recognizes Xrayebator installations only and never reconfigures a server implicitly. An email is optional during deployment: without one, Certbot registers the ACME account with --register-unsafely-without-email, so renewal notices and account recovery are unavailable — both consequences are shown in the UI before deploying.

SSH host keys use trust on first successful authentication. The fingerprint is then pinned; any later mismatch fails closed before commands are executed. After an intentional VPS reinstall, explicitly reset the pin in Server Settings and confirm the new key on the next successful connection.

See Electron Desktop GUI for the complete Electron boundary, command adapters and packaging details.

There aren't any published security advisories