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
- Download from Official GitHub repository, choosing the version, platform, and OS.
- 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/
- 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
- 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
)
- 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
- 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
}
-
Configure xray like the above step 4 “Add Xray websocket configuration”
-
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
-
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;
-
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: