Home

Bypass GFW with V2Ray XTLS/Xray websocket

Background Introduction

People living in China, Iran or other totalitarian states are banned from visiting popular websites such as Google, YouTube, Instagram, Wikipedia, Reddit, Telegram, BBC and so forth. The censorship techniques used are so sophisticated that only specially designed software can bypass. OpenVPN, for instance, cannot be used to circumvent GFW because its traffic characteristics is easily detectable, although its contents are strongly encrypted.

There are two types of solutions aimed at erasing the traffic fingerprints:

  • Random byte stream, which means no characteristics at all (eg. Shadowsocks)
  • Imitating other widely used protocols that GFW cannot block totally, which is temporary collateral freedom (eg. XTLS/Xray)

Actually, there are many other effective strategies, which will be discussed in the future. In this post, I demonstrate how to setup a V2Ray/Xray proxy server with websocket transport. Other options like XTLS/Reality, meek, XHTTP will be discussed later. As V2Ray and Xray share some features, including the ones discussed below, you may choose either one at will. I take XTLS/Xray for example.

Installation

Presume that the server is running OS of a flavour of Linux with systemd or init, while users of other unix-like systems may refer to the OS wiki.

Systemd

Automatic installation with official script

This is easy nine times out of ten.

Manually download and Install

  1. Download from Official GitHub repository, choosing the version, platform, and OS.
  2. Extract and move the files:

$ bsdtar -xf Xray-*.zip or $ unzip Xray-*.zip then

# mv xray /usr/local/bin/

# mkdir /usr/local/share/xray /usr/local/etc/xray

# mv geoip.dat geosite.dat /usr/local/share/xray/

  1. Setup systemd .service file:

/etc/systemd/system/[email protected]

[Unit]
Description=Xray Service
Documentation=https://github.com/xtls
After=network.target nss-lookup.target

[Service]
User=nobody
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
NoNewPrivileges=true
ExecStart=/usr/local/bin/xray -c /usr/local/etc/xray/%i.json
Restart=on-failure
RestartPreventExitStatus=23
LimitNPROC=10000
LimitNOFILE=1000000

[Install]
WantedBy=multi-user.target
  1. Add Xray websocket configuration:

/usr/local/etc/xray/http.upgrade.json

{
    "log": { "loglevel": "none" },
    "routing": {
        "domainStrategy": "IPIfNonMatch",
        "rules": [
            {
                "type": "field",
                "domain": [ "geosite:category-ads-all", "geosite:cn" ],
                "outboundTag": "block"
            },
            {
                "type": "field",
                "ip": [ "geoip:cn" ],
                "outboundTag": "block"
            }
        ]
    },
    "inbounds": [
    {
        "listen": "YOUR-IP-ADDRESS", "port": 8080, "protocol": "vless",
        "settings": {
            "clients": [ { "id": "YOUR-UUID" } ],
            "decryption": "none"
        },
        "streamSettings": {
            "network": "httpupgrade",
            "httpupgradeSettings": {
                "path": "/YOUR-PATH"
            }
        },
        "sniffing": {
            "enabled": false, "destOverride": [ "http", "tls", "quic" ] }
    }
    ],
    "outbounds": [
        { "protocol": "freedom", "tag": "direct" },
        { "protocol": "blackhole", "tag": "block" }
    ],
    "policy": {
        "levels": {
            "0": { "handshake": 3 }
        }
    }
}

Note that the above configuration is not complete, and you must supply before running Xray:

  • change “geosite:cn” and “geoip:cn” to your own country code if you don’t want to access domestic websites via this proxy
  • change “YOUR-IP-ADDRESS”, which you can get via $ ip a or $ curl ip.me, both IPv4 and IPv6(eg. 2001:4860:4860::8844) is fine
  • change “YOUR-UUID”, which you can get via $ xray uuid or $ uuidgen
  • change “YOUR-PATH” to legal URL path (eg. my_secret-path-2O25)
  1. Start Xray with systemd

# systemctl start [email protected]

Check the status:

$ systemctl status [email protected]

If it is active (running), you may enable it to auto start with the system:

# systemctl enable [email protected]

Init

Take Alpine Linux for example

  1. Create init.d file for Xray /etc/init.d/xray
#!/sbin/openrc-run

name="Xray"
description="The best v2ray-core, with XTLS support"
description_checkconfig="Test configuration file"

: ${env:="XRAY_LOCATION_ASSET=/usr/local/lib/xray/"}
: ${confdir:="/usr/local/etc/xray/"}

command="/usr/local/bin/xray"
command_args="run -c /usr/local/etc/xray/http.upgrade.json"
command_user="nobody"

pidfile="/run/xray.pid"
command_background="yes"

extra_commands="checkconfig"

depend() {
	need net
}

checkconfig() {
	if [ ! -d "$confdir" ]; then
		eerror "You need to setup $confdir first"
		return 1
	fi
	export $env
	$command $command_args -test
}

start_pre() {
	checkconfig
}
  1. Configure xray like the above step 4 “Add Xray websocket configuration”

  2. Start or enable Xray Start:

# rc-service xray start

Enable to auto start:

# rc-update add xray

Stop:

# rc-service xray stop

Disable:

# rc-update del xray

CDN

Now that xray is setup successfully, however the traffic over websocket remains unencrypted, which is not secure. You need to put the server behind a CDN, then the traffic from / to clients will be encrypted.

Since there are many CDN providers, I will skip this step. But note that

  1. Some CDN providers don’t allow huge proxy traffic, in principle. So just use the proxy yourself and avoid huge traffic. Or seek another provider with less limits;

  2. You have to switch on “websocket” on CDN, otherwise xray won’t work. Some CDNs don’t offer this for free tier customers. But Xray still works via XHTTP (V2Ray over meek), which I will talk about later.

Firewall

You might setup firewall to protect the server from uninvited access. I take ufw for instance. To install ufw on a Debian-based server:

# apt update && apt install ufw

On a Alpine Linux server:

# apk update && apk add ufw

Then open ports for ssh and xray. Note that you may need to change the port 8080 accordingly to match the value in /usr/local/etc/xray/http.upgrade.json:

# ufw allow ssh

# ufw allow 8080

You may append a whitelist if the visitors’ IP address varies in certain range. For example, if you use the proxy via CDN, then you can put CDN’s IP range to the whitelist:

# ufw allow from WHITE-LIST-IP-RANGE to YOUR-IP port 8080

Now enable ufw:

# systemctl enable --now ufw

# ufw enable

(Optional) Issuing a SSL cert with acme

As I said, the traffic is not encrypted, which CDN helps the client side. If you want to solve the server side, then issue and install a SSL cert.

Q&A

TODO:

    Kindly visit GitHub issue page if you have comments. I apologize for not having a complete comment system at the moment.