3X-UI on Ubuntu 24.04 on Azure User Guide
Overview
3X-UI is a web based management panel for Xray-core, the proxy platform behind protocols such as VLESS, VMess, Trojan and Shadowsocks. It gives you a browser interface to create and manage inbound connections and client accounts, apply per client traffic limits and expiry dates, watch live traffic and system statistics, and control the underlying Xray process, all without hand editing JSON configuration. The panel stores its accounts, inbounds and settings in an embedded SQLite database and runs Xray-core as a managed child process, regenerating its configuration and reloading it for you whenever you change an inbound. The cloudimg image serves 3X-UI 3.5.0 on a hardened, fully patched Ubuntu 24.04 LTS base as a single self contained Go binary managed by systemd.
This is proxy infrastructure with a privileged admin panel, so the image is built to be secure by default. There are no shared or default credentials: the well known upstream admin / admin login is never present on a running VM, because a per VM administrator username and password are generated on your own VM at first boot. The panel is served under a random secret base path, so it is not exposed at a predictable URL. And the image ships with zero inbounds, so Xray binds no proxy port and nothing relays traffic until you deliberately create an inbound. Backed by 24/7 cloudimg support.
What is included:
- 3X-UI 3.5.0, from the pinned upstream release, as a single Go binary managed by systemd
- The bundled Xray-core engine, managed by the panel as a child process
- A per VM admin username and password generated at first boot, never baked into the image
- A random secret web base path per VM, so the panel is not reachable at a predictable URL
- Zero inbounds and zero proxy accounts: Xray binds no proxy port on a fresh VM
- The subscription server disabled by default, so the panel is the only public surface
- Plain HTTP on port
2053with no baked TLS certificate, ready for you to add your own x-ui.serviceas an enabled systemd unit, gated behind first boot credential rotation- 24/7 cloudimg support
Prerequisites
An active Azure subscription, an SSH key pair, and a VNet plus subnet in the target region. Standard_B2s (2 vCPU / 4 GiB RAM) is a sensible starting point. NSG inbound: allow 22/tcp from your management network and 2053/tcp for the panel.
Read this before you boot the VM. 3X-UI configures a proxy server that will relay arbitrary traffic once you create an inbound, and the panel is a privileged admin surface. Treat this VM as your own authorised use proxy infrastructure. Scope the inbound NSG rule for 2053/tcp (the panel) and 22/tcp (SSH) to your own IP address before you boot the VM. Do not leave the panel open to 0.0.0.0/0. The panel is protected by a per VM credential and a secret base path, but limiting who can reach it at all is your first line of defence.
Step 1 - Deploy from the Azure Marketplace
Sign in to the Azure Portal, choose Create a resource, search the Marketplace for 3X-UI by cloudimg, and select Create. On Basics pick your subscription, resource group, region and size; under Administrator account choose SSH public key and paste your key; under Inbound port rules allow SSH (22), then add a custom rule for 2053 scoped to your own IP. Then Review + create then Create.
Step 2 - Deploy from the Azure CLI
az vm create \
--resource-group <your-rg> \
--name 3x-ui \
--image <marketplace-image-urn> \
--size Standard_B2s \
--admin-username azureuser \
--generate-ssh-keys \
--public-ip-sku Standard
Then open the panel port, restricted to your own address:
az network nsg rule create \
--resource-group <your-rg> \
--nsg-name 3x-uiNSG \
--name allow-3x-ui-panel \
--priority 900 \
--source-address-prefixes <your-ip>/32 \
--destination-port-ranges 2053 \
--access Allow --protocol Tcp
Step 3 - Confirm the service and listeners
SSH in as azureuser and confirm the panel is active. The only ports open to the network are 22 for SSH and 2053 for the panel; Xray binds no proxy port because the image ships with zero inbounds.
systemctl is-active x-ui
sudo ss -tlnH | awk '{print $4}' | grep -vE '^(127\.|\[::1\])' | sort -u
The command above lists every publicly bound port. On a fresh VM it prints exactly 0.0.0.0:22 (SSH) and one entry for the panel on 2053 - nothing else, because there are no inbounds and the subscription server is disabled by default.

Step 4 - Get your per VM credentials
The image ships with no usable login: the well known upstream admin / admin default never exists on a running VM. On the first boot of every VM a one shot service generates a random administrator username and password and a random secret base path, and writes them to a root only file. Read it to get your panel URL, username and password:
sudo cat /root/3x-ui-credentials.txt
The panel.url line is your login URL. It includes the random base path, so the panel is reachable only at that address; a bare visit to the host and port returns 404. Keep this file safe - it is mode 0600 and readable only by root.

Step 5 - Log in to the panel
Open the panel.url from the credentials file in your browser - it looks like http://<vm-public-ip>:2053/<random-base-path>/. The panel opens on its login form. Enter the panel.username and panel.password from the credentials file and select Login. There are no default credentials to change, because none ship - the account you are logging in with was generated for this VM alone.

Step 6 - The dashboard
After signing in, the dashboard shows the panel and Xray status, system statistics (CPU, memory, network throughput and uptime), and your inbound and client totals. On a fresh VM the inbound count is zero: Xray is running but has no proxy listener, so the VM is not relaying any traffic yet.

Step 7 - Create your first inbound
The Inbounds page is where you create the proxy endpoints your clients connect to. Select Add Inbound to open the inbound form: choose a protocol (for example VLESS, VMess or Trojan) from the Basics tab, set a remark and a port, and use the Protocol, Stream, Security and Sniffing tabs to tune the transport, then Create.

When you select Create, the panel writes the inbound to its database, regenerates the Xray configuration and reloads Xray so it starts listening on the new port immediately - you do not restart anything by hand. The screenshot below shows an inbound that has just been created and is listed as enabled. Because the image ships with none, this is your own first inbound: the panel is doing the one thing it exists to do, turning a form into a live Xray listener.

Open the inbound to manage its clients. Each client has its own UUID or password, and you can set a traffic limit, an expiry date and get its connection string or QR code to share with a device.
Step 8 - Confirm the secure by default posture
These checks confirm, from the command line, the security properties the image ships with. They read your per VM credentials from the credentials file, so they work as written.
The panel is reachable only under your secret base path - a bare request to the host and port returns 404:
PORT=$(sudo grep '^panel.port=' /root/3x-ui-credentials.txt | cut -d= -f2-)
curl -s -o /dev/null -w 'bare / -> HTTP %{http_code} (404 = panel hidden under your secret base path)\n' http://127.0.0.1:${PORT}/
The well known upstream default admin / admin is rejected by the credential check - it returns success:false, not an error, because the credential is genuinely evaluated and genuinely wrong:
CREDS=/root/3x-ui-credentials.txt
PORT=$(sudo grep '^panel.port=' $CREDS | cut -d= -f2-)
BP=$(sudo grep '^panel.basepath=' $CREDS | cut -d= -f2-)
B="http://127.0.0.1:${PORT}"
TOK=$(curl -s -c /tmp/xui-cj "${B}${BP}csrf-token" | jq -r .obj)
curl -s -b /tmp/xui-cj -X POST -H "X-CSRF-Token: ${TOK}" -H 'Content-Type: application/json' \
-d '{"username":"admin","password":"admin"}' "${B}${BP}login"; echo
Your per VM credential, by contrast, logs in successfully:
CREDS=/root/3x-ui-credentials.txt
U=$(sudo grep '^panel.username=' $CREDS | cut -d= -f2-)
P=$(sudo grep '^panel.password=' $CREDS | cut -d= -f2-)
PORT=$(sudo grep '^panel.port=' $CREDS | cut -d= -f2-)
BP=$(sudo grep '^panel.basepath=' $CREDS | cut -d= -f2-)
B="http://127.0.0.1:${PORT}"
TOK=$(curl -s -c /tmp/xui-cj "${B}${BP}csrf-token" | jq -r .obj)
curl -s -b /tmp/xui-cj -X POST -H "X-CSRF-Token: ${TOK}" -H 'Content-Type: application/json' \
-d "{\"username\":\"${U}\",\"password\":\"${P}\"}" "${B}${BP}login"; echo
rm -f /tmp/xui-cj

Step 9 - Change the panel port (optional hardening)
The panel listens on 2053 by default. Moving it to a port of your choice, together with the secret base path, further reduces drive by exposure:
sudo /usr/local/x-ui/x-ui setting -port 48291
sudo systemctl restart x-ui
Update your NSG rule and your bookmark to the new port. You can review the current settings, including the base path and port, at any time with sudo /usr/local/x-ui/x-ui setting -show true.
Step 10 - Put TLS in front of the panel
The image serves plain HTTP on port 2053. Until you terminate TLS, your panel password crosses the network in clear text, so this is not optional for anything beyond a short lived test.
Point a DNS name at the VM's public IP, obtain a certificate (for example with certbot in standalone mode, or from your own CA), then tell the panel to use it:
sudo /usr/local/x-ui/x-ui setting -webCert /etc/letsencrypt/live/panel.your-domain.com/fullchain.pem
sudo /usr/local/x-ui/x-ui setting -webCertKey /etc/letsencrypt/live/panel.your-domain.com/privkey.pem
sudo systemctl restart x-ui
The panel then serves HTTPS on 2053. The image ships no certificate, so nothing about your TLS setup is shared with any other VM.
Step 11 - Verify the stack
/usr/local/x-ui/x-ui -v
systemctl is-enabled x-ui 3x-ui-firstboot
sudo sqlite3 /etc/x-ui/x-ui.db 'SELECT COUNT(*) AS inbounds FROM inbounds;'
The inbound count above is 0 on a fresh VM, and it rises only as you add your own inbounds.

Step 12 - Where your data lives
Everything 3X-UI stores - the admin account, your inbounds and client accounts, settings and traffic statistics - lives in the SQLite database at /etc/x-ui/x-ui.db. The panel binary and the bundled Xray engine are under /usr/local/x-ui and hold no per instance state.
sudo ls -la /etc/x-ui/
Back up /etc/x-ui/x-ui.db to preserve your panel configuration. It contains your admin credential (as a bcrypt hash), your inbounds and every client account.
Security notes
- No default credentials. The upstream
admin/admindefault never exists on a running VM. A per VM administrator username and password are generated from the system random source on your own VM at first boot and written to/root/3x-ui-credentials.txt(mode0600). The panel service will not start until that rotation has happened. - Secret base path. The panel is served under a random base path generated per VM, so it is not reachable at a predictable URL. A bare request to the host and port returns 404.
- Zero inbounds ship. The image contains no inbounds and no proxy accounts, so Xray binds no proxy port and the VM relays nothing until you create an inbound. The subscription server is disabled by default, so the panel on
2053is the only public surface. - Scope the NSG. This is proxy infrastructure with a privileged admin panel. Restrict inbound access to
2053and22to your own IP address before first boot. - Plain HTTP by default. The panel serves HTTP and ships no TLS certificate. Add your own certificate (Step 10) before using it beyond a short lived test.
- Patching. The image ships fully patched and
unattended-upgradesremains enabled, so security updates continue to apply on your VM. - Authorised use. Run only proxy endpoints you are authorised to operate. You are responsible for the traffic your inbounds relay.
Support
cloudimg provides 24/7 support for this image. Contact support@cloudimg.co.uk with the VM name, region and the output of systemctl status x-ui.