Start your 3-day free trial
Sign up to experience all premium features at no cost.
*Available only to new users. Each user is limited to one trial.


3x-ui setup is complete only when you can control the management entrance, reject an unauthorized user, and recover the database without restoring revoked access. This procedure uses a private SSH management path and a single encrypted inbound, with recovery checks that you perform in your own authorized environment.
Key Takeaways
- A hidden URL path is not authentication or a network access boundary.
- Keep administrator credentials separate from each proxy user's identity.
- Database, certificates, release versions, and later revocations belong to one recovery plan.
- A running panel and a working proxy are separate acceptance checks.
The self-hosting operations map separates ownership of the host, management plane, and user traffic. A panel simplifies entry but also becomes a valuable control point. If database and certificate maintenance are not responsibilities you want, compare self-managed VPS and managed-exit responsibilities before installing.
For WireGuard device administration, use the wg-easy peer-management route. Here the task is 3x-ui and its Xray core. The VLESS, REALITY, and Vision distinction explains why those labels are not interchangeable settings.
Scope: a dedicated Ubuntu 24.04 LTS host, native 3x-ui v3.9.0, default SQLite, a separate compatible client, and an existing valid certificate for a domain you control. This guide does not cover PostgreSQL, containers, or a pre-existing production panel. It is based on official sources, not an author end-to-end test. “Tested Recovery” means the reader must carry out the recovery acceptance below; it is not an author success claim.[1]
Record existing ports, firewall rules, routes, DNS, service units, and any certificate renewal jobs privately. Confirm a new SSH connection and independent provider console. Keep provider ingress closed except the known administration path while installing: an installer may start services before you can change settings.
The official installation route uses a privileged script. Download the exact release script rather than executing a remote pipe; read its package changes, archive downloads, service installation, and certificate branches. A syntax check is not a security review. The script's version argument pins the archive, while an unversioned invocation can resolve another release.[2][3]
umask 077
curl --fail --show-error --location \
https://raw.githubusercontent.com/MHSanaei/3x-ui/v3.9.0/install.sh \
-o install-3x-ui-v3.9.0.sh
less install-3x-ui-v3.9.0.sh
bash -n install-3x-ui-v3.9.0.sh
Proceed only after confirming project ownership and reviewing every downstream download used by your selected branch. Check any official release integrity material; if the installer reports an integrity mismatch or cannot obtain required files, stop. Do not substitute a mirror, disable TLS validation, or use the rolling development channel to force progress.
Run it interactively from a real terminal. Select SQLite. For this SSH-only administration route, choose the explicitly labeled Skip SSL — behind reverse proxy / SSH tunnel only option, then affirm loopback-only binding. Do not accept the certificate branch by default or open port 80 for it. The proxy inbound will use its own existing certificate in Step 3.[2]
sudo bash install-3x-ui-v3.9.0.sh v3.9.0
sudo systemctl stop x-ui
sudo /usr/local/x-ui/x-ui setting -listenIP 127.0.0.1 -port 2053
sudo systemctl start x-ui
sudo ss -lntup
The explicit setting command reinforces the intended panel address and port. If any preceding command fails, stop and inspect rather than blindly continuing. Keep the generated credentials, base path, and installer result file private. Verify the panel listener is 127.0.0.1:2053; a wildcard listener is a failed boundary even when the provider currently blocks it.[5]
Replace the uppercase placeholders on the workstation; port 2053 must be free locally. Use independently verified host keys in the specified trust file and stop on a mismatch. Do not accept an unknown key just to reach the panel.
ssh -N -T -o ExitOnForwardFailure=yes -o StrictHostKeyChecking=yes \
-o UserKnownHostsFile=/PATH/TO/VERIFIED_KNOWN_HOSTS \
-L 127.0.0.1:2053:127.0.0.1:2053 ADMIN@SERVER_IP
Browse http://127.0.0.1:2053/BASE_PATH/, replacing BASE_PATH with the actual generated path. HTTP here is carried inside SSH and is not a public management endpoint. Log in, set a unique administrator name and strong password, and enable the release's supported second factor if you can securely retain recovery material.
Close the browser session and verify a fresh private window requires authentication. Incorrect credentials must not allow privileged operations. From an authorized external host, verify public TCP 2053 is unreachable across both relevant address families. Keep this restriction after restarts. A random port or base path only reduces accidental discovery; neither replaces these checks.
Do not enable remote APIs, bots, or subscription listeners without a separate need and policy. Examine all listeners, not just the panel port. Exported URLs can carry credentials: the subscription-secret handling guide applies even when the subscription endpoint itself is private.
Use VLESS over TCP with ordinary TLS for this bounded example, not REALITY or Vision. In Inbounds, add an entry with the following values, then add one uniquely named client and generate its UUID using the panel. VLESS itself supplies no transport encryption; the TLS layer is required here.[6][7][8]
| Field | Value or requirement |
|---|---|
| Protocol / transport | VLESS / TCP; no Vision flow |
| Listen / port | 0.0.0.0 / TCP 8443, initially provider-blocked |
| VLESS decryption | none; this is a protocol field, not permission to remove TLS |
| Transport security | TLS enabled; valid certificate for proxy.example.com |
| Certificate / key | /etc/x-ui/tls/fullchain.pem / /etc/x-ui/tls/privkey.pem |
| Client identity | A new UUID for each person or device; no administrator password reuse |
| Optional listeners | Leave unused subscriptions, APIs, and bots disabled |
Replace the example domain. Provision the certificate by your already approved issuance method; confirm its name, validity, chain, matching key, and renewal owner before opening ingress. Install files at the shown paths with the actual service user's required read access. Private keys must not be world-readable; do not fix permissions with broad recursive grants.
Save the inbound and apply the panel's Xray configuration change. Inspect the service state and logs for config or certificate errors. Keep exports private. On the separate client, enter the real endpoint and port, the new UUID, TCP, TLS, and the matching server name, with certificate verification enabled. Leave Vision flow unset. Use a local proxy listener on 127.0.0.1; do not expose it to the LAN.
Temporarily admit the authorized test client's source to TCP 8443 through the provider and host policy. Do not open the management port. Select the new profile explicitly for the application being checked, then inspect its visible exit IP. Compare it with the host's known egress. A panel page loading through SSH proves nothing about this traffic route.
sudo systemctl status x-ui --no-pager
sudo journalctl -u x-ui --since "10 minutes ago" --no-pager
sudo ss -lntup
| Check | Expected condition | Failure response |
|---|---|---|
| Panel without a session | Privileged actions denied | Close access and inspect account/session policy |
| Correct UUID and verified TLS | A new proxied TCP request succeeds with intended exit | Split certificate/name, identity, routing, and core errors |
| A separate test profile with a wrong UUID | No new authorized proxy request | Stop exposure and inspect which inbound/profile actually received traffic |
| DNS, IPv6, and application UDP | Each follows the explicitly chosen coverage policy | Record unsupported paths; do not extrapolate TCP success |
| Client disconnect | Observed fallback agrees with your policy | Do not infer a kill switch from an application proxy |
Use only controlled test traffic for the negative profile. The example validates TCP; UDP requires a client and protocol mode that actually carries it, a controlled destination, and its own result. DNS resolution can occur outside an application proxy, and IPv6-capable applications can take another path. Keep all those checks distinct.
Create a second independently identified control user before testing revocation. Remove or disable the first user and apply the Xray change. Terminate its existing client session, reconnect with its retained UUID, and require rejection of a fresh request while the control user still works. Restart x-ui during an approved window and repeat. Existing streams and displayed traffic totals are not reliable negative tests.
Privately inventory the panel and core versions, SQLite path, TLS files, renewal configuration, service settings, users, tokens, and provider rules. The default SQLite database is /etc/x-ui/x-ui.db; certificates are separate recovery inputs even when this example places them under the same directory. PostgreSQL needs its own database backup method and is outside this file-copy procedure.[4]
Use a fresh snapshot directory, stop the panel/core during the maintenance window, and check each command's success. Copying the entire stopped SQLite directory also preserves any accompanying database files. If a copy fails, keep the source intact, diagnose the failure, and restore service deliberately.
sudo install -d -m 700 /root/3x-ui-backup-20261011
sudo systemctl stop x-ui
sudo cp -a /etc/x-ui /root/3x-ui-backup-20261011/x-ui
sudo chmod -R go-rwx /root/3x-ui-backup-20261011
sudo systemctl start x-ui
Include externally stored certificates and renewal/account material if your real paths differ. Record original ownership and modes before restricting the backup copy. Encrypt a restricted off-host copy; a readable database includes sensitive client and administrator state. Do not send backups through a bot or public chat as a shortcut.
Keep a separate dated ledger of revoked users and rotated credentials outside the snapshot. For recovery, use an isolated replacement host running the same panel and Xray core versions, with business and optional-listener ingress closed. Retain the replacement's current directory under the new rollback name below; both the snapshot and rollback destinations must exist or be absent as their commands require. Never run these commands against your only live instance without a separate rollback copy.
sudo systemctl stop x-ui
sudo mv /etc/x-ui /etc/x-ui.before-restore-20261011
sudo cp -a /root/3x-ui-backup-20261011/x-ui /etc/x-ui
The backup copy had group/other access removed. After copying, restore the original ownership and modes recorded in the inventory, especially the actual service identity’s read access to SQLite and TLS files. Keep private keys inaccessible to unrelated users; do this before running the following startup commands.
sudo /usr/local/x-ui/x-ui setting -listenIP 127.0.0.1 -port 2053
sudo systemctl start x-ui
The restored database may include old users and admin credentials. Before reopening ingress, apply all later revocations and credential rotations through the SSH-only panel, and check certificate ownership, names, expiry, and renewal jobs. Repeat correct/wrong credentials, revoked/control user, restart, and listener checks. An old revoked UUID working again is a failed recovery; close access and correct persistent plus active core state. Do not force an old schema into a newer installation or combine recovery with an upgrade.[4]
If authentication is lost, use the authorized host console and the documented x-ui management menu to reset the account, then sign in and re-establish the intended authentication policy. Do not disable second factors or expose the panel as a diagnostic shortcut. If recovery ownership is uncertain, keep ingress closed and stop.
To retire, close this inbound's provider rule, revoke its users and exports, then stop and disable x-ui. Check all listeners and renewal jobs owned by this installation. Preserve encrypted backups for the chosen retention period before using the documented uninstall route. Remove only this deployment's DNS records and cloud resources; check unrelated services and a fresh administrative connection. Uninstalling software does not cancel host billing.
No. A path can leak through history, exports, or logs. Keep the management listener restricted and require real authentication for every privileged operation.
The SSH tunnel protects this administrative browser path only. The separate VLESS inbound requires its own TLS configuration, user identities, firewall policy, and client checks.
That is the VLESS protocol's configuration value, not a recommendation for plaintext internet transport. This example separately requires ordinary TLS with verified certificates on the client.
Use a consistent backup mechanism or stop this dedicated installation before copying its database directory. A copy made during writes may not capture a coherent recoverable state.
Do not assume so. Back up the actual certificate and key paths, their access permissions, and renewal configuration separately from the database, even when stored nearby.
Yes, when the backup predates deletion. Replay the independent revocation ledger before opening ingress, then verify a fresh old-credential request fails after restart.
No author recovery test is claimed. The title describes the reader's required acceptance procedure; its results must come from your own authorized environment, not assumed success.
Sources:
Sources checked 11 October 2026.
Related Articles:
Sign up to experience all premium features at no cost.
*Available only to new users. Each user is limited to one trial.