# V2Ray Setup with X-UI and Cloudflare domain fronting
*V2Ray is the #1 way to systematically bypass the [[Great Firewall]].*
*This is my personal guide to getting V2Ray set up relatively quickly, written in late 2025*
## Step 1: Acquire a plausible domain
- If using a new domain, I recommend using CloudFlare's domain registrar, as we'll want to enable domain fronting through Cloudflare later.
- If using an existing domain, you can simply set Cloudflare as your DNS provider, by changing your domain’s nameservers at your existing registrar to Cloudflare's nameservers.
- The domain name is visible to the [[Great Firewall]] (via TLS SNI), so make it as boring and non-descript as possible. The idea is to make our v2ray traffic plausible look like 'legitimate' usage.
- Avoid sensitive terms like "VPN", "proxy", "v2ray", "bitcoin", "crypto", "chainsync", `xinjianggenocide.tiananmenmassacre.freetibet.liberatehongkong.independenttaiwan.net`, etc
- Some examples domain names which have plausible traffic profiles:
- "Generic mid-size SaaS": `api.coredata.io`, `api.unifiedsystems.io`
- Infrastructure / middleware / “plumbing”: `api.netcore.io`, `svc.databridge.io`
- Analytics / data / internal tooling: `api.datainsights.io`, `svc.metricsplatform.com`
- Reputation matters; the subdomain may be blocked, so prefer domain names you can throw away.
### Step 2: Acquire a VPS
I set mine up with [[DigitalOcean]] - cheap, easy, reliable. This was $6/mo at the time of writing.
### Create a droplet
The region you choose determines the location of your exit node.
![[Pasted image 20251222190813.png]]
The cheapest, most vanilla option is perfectly sufficient. You can always upgrade it later if needed:
- Latest Ubuntu LTS release
- "Basic"
- Regular SSD
- 1 GB / 1 CPU, 25 GB SSD, 1000 GB transfer
- No backups
- SSH Authentication: Add your SSH key; it's a bit more secure against password auth
![[Pasted image 20251222191231.png]]
Create the droplet and find its IP address in the console. In this example the IP is `123.321.213.132`.
![[Pasted image 20251222191800.png]]
### Step 3: Point your domain at the VPS
In Cloudflare DNS, add an A record pointing your subdomain to the VPS IP address:
- **Type**: A
- **Name**: Set this to whatever subdomain you chose, e.g. `api`
- **IPv4 address**: Your VPS IP (e.g. `123.321.213.132`)
- **Proxy status**: **DNS only** (grey cloud, not orange). The proxy must be disabled for now so that Let's Encrypt can verify the domain directly. We'll enable Cloudflare proxying later for additional stealth.
![[Screenshot 2025-12-22 at 7.58.05 PM.png]]
### Step 4: Install V2Ray X-UI and acquire a TLS cert
SSH into the VM.
```bash
# e.g. $ ssh
[email protected]
$ ssh root@<ip>
```
Inside the VM, run the official X-UI install script
```bash
bash <(curl -Ls https://raw.githubusercontent.com/vaxilu/x-ui/master/install.sh)
```
You will see a short series of prompts in Chinese:
```bash
# "For security reasons, you must change the port and account password after installation."
出于安全考虑,安装/更新完成后需要强制修改端口与账户密码
# "Confirm whether to continue?"
# Type `y` and `Enter` to continue.
确认是否继续?[y/n]: y
# "Please set your account name:"
# For security, it's best not to use a generic name like `admin` or `root`.
# Your usual username (e.g. `maxfangx`) is probably fine.
请设置您的账户名: maxfangx
# "Please set your account password:"
# Use a password manager to generate a strong random password.
# Save it in your password manager alongside your admin username.
请设置您的账户密码: ••••••••
# "Please set the panel access port:"
# Choose a random high port number between 10000-65535 (e.g. `42069`)
# This makes it more difficult for attackers to find your admin panel login interface.
请设置面板访问端口: 42069
```
The final output looks like:
```
出于安全考虑,安装/更新完成后需要强制修改端口与账户密码
确认是否继续?[y/n]:y
请设置您的账户名:<username>
您的账户名将设定为:<username>
请设置您的账户密码:<password>
您的账户密码将设定为:<password>
请设置面板访问端口:<port>
您的面板访问端口将设定为:<port>
确认设定,设定中
set username and password success
账户密码设定完成
set port <port> success面板端口设定完成
Created symlink /etc/systemd/system/multi-user.target.wants/x-ui.service → /etc/systemd/system/x-ui.service.
x-ui v0.3.2 安装完成,面板已启动,
x-ui 管理脚本使用方法:
----------------------------------------------
x-ui - 显示管理菜单 (功能更多)
x-ui start - 启动 x-ui 面板
x-ui stop - 停止 x-ui 面板
x-ui restart - 重启 x-ui 面板
x-ui status - 查看 x-ui 状态
x-ui enable - 设置 x-ui 开机自启
x-ui disable - 取消 x-ui 开机自启
x-ui log - 查看 x-ui 日志
x-ui v2-ui - 迁移本机器的 v2-ui 账号数据至 x-ui
x-ui update - 更新 x-ui 面板
x-ui install - 安装 x-ui 面板
x-ui uninstall - 卸载 x-ui 面板
----------------------------------------------
```
Install `socat`, which will be used when getting our cert later:
```bash
$ apt update && apt install -y socat
```
Install an [[ACME]] client, which we'll use to acquire a TLS cert: (still in the VM)
```bash
$ curl https://get.acme.sh | sh
```
Acquire the TLS cert for your domain. For example, if I am using `api.unifiedsystems.io` as my domain:
```bash
$ ~/.acme.sh/acme.sh --issue -d api.unifiedsystems.io --standalone
[Mon Dec 22 09:59:50 UTC 2025] Using CA: https://acme-v02.api.letsencrypt.org/directory
[Mon Dec 22 09:59:50 UTC 2025] Standalone mode.
[Mon Dec 22 09:59:50 UTC 2025] Creating domain key
[Mon Dec 22 09:59:50 UTC 2025] The domain key is here: /root/.acme.sh/api.unifiedsystems.io_ecc/api.unifiedsystems.io.key
[Mon Dec 22 09:59:50 UTC 2025] Single domain='api.unifiedsystems.io'
[Mon Dec 22 09:59:51 UTC 2025] Getting webroot for domain='api.unifiedsystems.io'
[Mon Dec 22 09:59:51 UTC 2025] Verifying: api.unifiedsystems.io
[Mon Dec 22 09:59:51 UTC 2025] Standalone mode server
[Mon Dec 22 09:59:52 UTC 2025] Pending. The CA is processing your order, please wait. (1/30)
[Mon Dec 22 09:59:56 UTC 2025] It seems the CA server is busy now, let's wait and retry. Sleeping for 1 seconds.
[Mon Dec 22 09:59:58 UTC 2025] Success
[Mon Dec 22 09:59:58 UTC 2025] Verification finished, beginning signing.
[Mon Dec 22 09:59:58 UTC 2025] Let's finalize the order.
[Mon Dec 22 09:59:58 UTC 2025] Le_OrderFinalize='https://acme-v02.api.letsencrypt.org/acme/finalize/2899697836/461448936896'
[Mon Dec 22 10:00:01 UTC 2025] Downloading cert.
[Mon Dec 22 10:00:01 UTC 2025] Le_LinkCert='https://acme-v02.api.letsencrypt.org/acme/cert/05609ad3bcf06b29706605745798b29ed9f4'
[Mon Dec 22 10:00:01 UTC 2025] Cert success.
-----BEGIN CERTIFICATE-----
<... certificate here ...>
-----END CERTIFICATE-----
[Mon Dec 22 10:00:01 UTC 2025] Your cert is in: /root/.acme.sh/api.unifiedsystems.io_ecc/api.unifiedsystems.io.cer
[Mon Dec 22 10:00:01 UTC 2025] Your cert key is in: /root/.acme.sh/api.unifiedsystems.io_ecc/api.unifiedsystems.io.key
[Mon Dec 22 10:00:01 UTC 2025] The intermediate CA cert is in: /root/.acme.sh/api.unifiedsystems.io_ecc/ca.cer
[Mon Dec 22 10:00:01 UTC 2025] And the full-chain cert is in: /root/.acme.sh/api.unifiedsystems.io_ecc/fullchain.cer
```
Install the cert to `/root/certs` where we can easily find it later:
```bash
$ mkdir -p /root/certs && chmod 700 /root/certs
$ ~/.acme.sh/acme.sh --installcert -d api.unifiedsystems.io \
--key-file /root/certs/api.unifiedsystems.io.private.key \
--fullchain-file /root/certs/api.unifiedsystems.io.fullchain.crt
The domain 'api.unifiedsystems.io' seems to already have an ECC cert, let's use it.
Installing key to: /root/certs/api.unifiedsystems.io.private.key
Installing full chain to: /root/certs/api.unifiedsystems.io.fullchain.crt
$ cd ~ && ls
certs/
$ ls ~/certs
api.unifiedsystems.io.fullchain.crt api.unifiedsystems.io.private.key
```
You'll specify these paths (`/root/certs/api.unifiedsystems.io.private.key` and `/root/certs/api.unifiedsystems.io.fullchain.crt`) later when configuring TLS in X-UI. It is helpful to namespace the certs by domain name so it's easy to set up another domain on the same machine later if the first domain gets busted by the Great Firewall (this happened to me).
Start X-UI and enable it to run on boot:
```bash
$ x-ui start
# "Panel is already running, no need to start again. If you need to restart, select restart"
[INF] 面板已运行,无需再次启动,如需重启请选择重启
$ x-ui enable
# "x-ui auto-start on boot set successfully"
[INF] x-ui 设置开机自启成功
```
### Step 4: Configure Cloudflare proxy
Now that we've acquired a TLS cert, we can enable the Cloudflare proxy, so that all traffic to our V2Ray server is routed through Cloudflare's CDN. This makes it very hard for the Chinese government to block, since blocking Cloudflare would break millions of legitimate websites.
Go to Cloudflare's DNS management page and enable the Cloudflare proxy (orange switch)
![[Screenshot 2025-12-22 at 7.57.56 PM.png]]
Then go to `SSL/TLS > Overview` and press `Configure`. Select "Custom SSL/TLS". Since our server is set up with a real TLS cert issued by a real CA, we can enable "Full (Strict)". If we leave it at "Flexible" (the default), our protocols will not work.
![[Screenshot 2025-12-22 at 10.33.56 PM.png]]
### Step 5: Add DigitalOcean firewall
For security, it's also a good idea to enable a firewall for your VPS. Create a new firewall configuration under "Networking" in DigitalOcean, and apply it to your droplet.
Allow these inbound ports:
- 22: SSH
- 80: If we ever need to rotate the cert later
- 443: We'll use this for VLESS
- 2053: Cloudflare-compatible port that we'll use for VMESS
- Your admin port, (e.g. 42069)
![[Pasted image 20251222223951.png]]
> [!tip] Advanced: Hide the admin panel entirely
> If you don't want to expose the X-UI admin panel to the internet at all, you can access it via SSH tunneling instead. Exclude the admin panel port in your firewall, then tunnel through SSH:
> ```bash
> ssh -L 8080:localhost:42069
[email protected]
> ```
> Then open `http://localhost:8080` in your browser. The panel is now only accessible through your SSH connection.
### Step 6: Configure inbound rules
You can now visit `http://123.321.213.132:42069` in the browser and log into the X-UI admin panel!
![[Pasted image 20251222202628.png]]
Main dashboard:
![[Pasted image 20251222202719.png]]
Once logged in, go to "Inbound List" (入站列表) on the left and press `[+]` to add a new inbound rule.
![[Pasted image 20251222205627.png]]
### Primary Inbound Rule: VLESS + WebSocket + TLS
For Cloudflare domain fronting, we need WebSocket transport so traffic can pass through Cloudflare's proxy. VLESS is the recommended protocol — it's a newer, lighter-weight successor to VMess. VMess has its own encryption layer built-in, but since we're already using TLS, that's redundant overhead. VLESS skips the duplicate encryption and relies on TLS alone, resulting in less CPU usage and better performance.
| Field | Value |
| ------------------ | --------------------------------------------------- |
| remark | `VLESS-WS-CF-unifiedsystems` (or any name you like) |
| protocol | `vless` |
| 监听 IP (listen IP) | *(leave empty)* |
| 端口 (port) | `443` (Primary Cloudflare-supported HTTPS port) |
| 传输 (transport) | `ws` |
| 路径 (path) | `/` (the root path) |
| tls | **ON** |
| 域名 (domain) | `api.unifiedsystems.io` (your domain) |
| 证书 (certificate) | `certificate file path` |
| 公钥文件路径 (cert path) | `/root/certs/api.unifiedsystems.io.fullchain.crt` |
| 密钥文件路径 (key path) | `/root/certs/api.unifiedsystems.io.private.key` |
- 路径 (path): You can use any path, e.g. `/vws`, but the root path `/` is simplest.
- 端口 (port): For simplicity, I recommend using the standard port `443`, but Cloudflare also supports these HTTPS ports: 2053, 2083, 2087, 2096, 8443. Use one of these or traffic won't pass through the CDN. Note that if you use anything other than 443 or 2053, you'll need to update your firewall as well.
- Note that the cert and cert key paths in the screenshot are missing the `api.unifiedsystems.io` namespace in the filename.
![[Pasted image 20251222203541.png]]
Click 添加 (Add) to confirm.
### Backup Inbound Rule: VMess + WebSocket + TLS
As a fallback, add a VMess inbound on a different Cloudflare-supported HTTPS port. This gives you redundancy if VLESS gets targeted.
| Field | Value |
| ------------------ | --------------------------------------------------- |
| remark | `VMESS-WS-CF-unifiedsystems` (or any name you like) |
| protocol | `vmess` |
| 监听 IP (listen IP) | *(leave empty)* |
| 端口 (port) | `2053` (Secondary Cloudflare-supported HTTPS port) |
| 传输 (transport) | `ws` |
| 路径 (path) | `/` |
| tls | **ON** |
| 域名 (domain) | `api.unifiedsystems.io` (your domain) |
| 证书 (certificate) | `certificate file path` |
| 公钥文件路径 (cert path) | `/root/certs/api.unifiedsystems.io.fullchain.crt` |
| 密钥文件路径 (key path) | `/root/certs/api.unifiedsystems.io.private.key` |
- VMess will auto-generate a UUID (id). The `alterID` should be `0` for modern VMess AEAD encryption.
- Note that the cert and cert key paths in the screenshot are missing the `api.unifiedsystems.io` namespace in the filename.
![[Pasted image 20251222205129.png]]
Click 添加 (Add) to confirm.
### Result
VLESS and VMESS have now been configured. We can now proceed to test!
![[Pasted image 20251222205650.png]]
For VLESS or VMESS, click on the connection and select 二维码 (QR code). It will display a QR code which you can scan with a compatible client to connect. You can also copy the connection string encoded in the QR code.
![[Pasted image 20251222224914.png]]
## Step 7: Test your setup!
If you're heading to China, make sure to set everything up and test thoroughly *before* going to China.
### V2Ray Clients
These are the V2Ray clients that worked for my setup.
- macOS: [V2RayU](https://en.v2rayu.org/) - Creates an icon in your taskbar which allows you to configure v2ray
- Android: [v2rayNG](https://en.v2rayng.org/) - I had to sideload the app by downloading an `.apk` for my phone.
### V2RayU Setup
Open the taskbar menu and click "Configure..."
![[Pasted image 20251222225845.png]]
Press `+` to add a server and paste the connection string into the "Import" tab.
![[Pasted image 20251222230054.png]]
Press `+` then either "Import configuration from QRcode" or "Import configuration from Clipboard".
![[Screenshot_20251222_230306.jpg|300]]
### V2Ray GL iNet AX6000 Router Setup
**Initial router setup**
Plug in the router's power cord, Ethernet cable optional.
Look for a Wifi network like GL-MT6000-100. Connect to it using the WiFi password hard-coded on the bottom of the router.
Navigate the admin panel at 192.16.8.1 and set an admin password.
Connect the router to internet with an Ethernet cable, or set it up in repeater mode (connecting to an existing WiFi network).
Go to System > Upgrade and ensure the router is up to date.
![[Pasted image 20260213003513.png]]
Go to Applications > Plug-ins. Install `xray-core` and `xray-geodata`, in that order.
![[Pasted image 20260213004559.png]]
(Local) SSH into the machine. The admin password is the SSH password
```bash
ssh
[email protected]
```
(Router) Install V2RayA - a UI for configuring V2Ray.
```bash
# Add the V2RayA signing key
$ wget https://downloads.sourceforge.net/project/v2raya/openwrt/v2raya.pub -O /etc/opkg/keys/94cc2a834fb0aa03
# Add the V2RayA feed
$ echo "src/gz v2raya https://downloads.sourceforge.net/project/v2raya/openwrt/$(. /etc/openwrt_release && echo "$DISTRIB_ARCH")" | tee -a "/etc/opkg/customfeeds.conf"
# Update and install
$ opkg update
$ opkg install v2raya
# Install the iptables firewall dependencies (needed for fw3 / OpenWrt 21.02):
$ opkg install iptables-mod-conntrack-extra iptables-mod-extra iptables-mod-filter iptables-mod-tproxy kmod-ipt-nat6
# Enable and start V2RayA
$ uci set v2raya.config.enabled='1'
$ uci commit v2raya
$ /etc/init.d/v2raya start
```
Go to http://192.168.8.1:2017 in your browser and create an admin account:
![[Pasted image 20260213005253.png]]
Press "Import", then paste your VLESS and VMESS share links.
![[Pasted image 20260213005526.png]]
Connect to one of the servers and press the "Ready" button at the top of the screen. The "Ready" button should now say "Running".
![[Pasted image 20260213010601.png]]
Go to Settings and ensure that "Transparent Proxy / System Proxy" is set to one of the "On:" options.
![[Pasted image 20260213011354.png|400]]
If you're traveling to China, I recommend choosing "On: Proxy except CN Sites". This will proxy everything except traffic to Chinese domestic sites like WeChat and Alipay, otherwise you might get flagged by these apps at the network level. If you're setting up V2Ray just for use as a day-to-day proxy, "On: Do not Split Traffic" may be the best option for you. Once you've made your choice, click "Save and Apply".
![[Pasted image 20260213010750.png]]
Go to a website like https://mullvad.net/en or https://nordvpn.com/what-is-my-ip/ where you can see your location inferred from your current IP address. If the location shows the IP of your DigitalOcean server, congrats! Your V2Ray proxy is set up.
![[Pasted image 20260213011537.png]]
### Conclusion
Enjoy your fast uncensored internet!
![[Pasted image 20260213011218.png]]