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.

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. Passwords, sudo passwords, key passphrases and private-key bytes are kept only in the active form or operation; they are not persisted. A private key is read only after it was selected through the native Electron file dialog.

The GUI does persist the server metadata needed to return to a server, including the host, SSH port, username, authentication method, privilege mode and selected key path. It also persists 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.

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.

keytar is listed in package.json, but the active Electron GUI does not use it to store SSH passwords or passphrases in an operating-system keychain. The secrets remain session-only.

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

There aren't any published security advisories