Bypass GFW China 2019

An article on the 逗比根据地 website, doub.io, gave some advice for improving the obfuscation of your ShadowsocksR (SSR) server. That website has now disappeared. Fortunately, some of the information it contained was preserved at https://doubibackup.com. Other sites with related information include https://www.flyzy2005.com, https://fanqiangdang.com, and https://shenzhensuzy.wordpress.com/2018/11/30/shadowsocksr-ssr/.

This post is based on these articles and summarizes their advice for obfuscating your SSR server. The examples in this post are all for an Ubuntu 18.04 SSR server, and a Windows or Android SSR client.

1. VPS location
2. VPS security
3. Cover website
3.1. Domain name
3.2. Install Nginx
3.3. Add content to website
3.4. Add Letsencrypt free SSL certificate
3.5. Change listening port
4. SSR server
5. SSR client
6. End-to-end tests

1. VPS location

The author of the 逗比根据地 website found that Hong Kong, Japan, and the United States are the most popular locations for virtual private servers (VPS) for ShadowsocksR (SSR). In an informal survey, 86% of respondents said they located their servers in one of these areas. Not surprisingly, these are also the most frequently blocked by the GFW. Here is a quote from the original article:

我也在 Telegram 做过一个两千人参与的哪些地区被墙次数最多的投票(仅供参考,不要杠),结果香港、日本、美国加起来占了 86%,而美国就占了 48%,差不多一半。或许有人会说什么基数,的确这种小规模投票不能代表所有人,但是我这个投票是选择你手里被墙次数最多的地区,这意味着如果一个人选择了美国,那么代表他的美国服务器被墙次数高于他手里的其他地区代理服务器。这不是什么大数据统计,但也能反映一些问题。至少比个人经验、看脸论强一些。正因为这些热门地区搭建代理的人多,所以GFW会重点关注这些地区,导致被墙几率相比其它地区会更高。另外说一说我自身情况。我手里有一些这几年买的自用服务器,一直以来搭建的都是 SSR,香港、日本、美国、欧洲、俄罗斯地区都有。在今年之前,也就是 GFW1.0 的时候,都是敏感时期一波一波的封,偶尔可能会封我各香港、日本、美国的服务器,但是欧洲和俄罗斯的毛事没有。但是今年之后,日本和美国的服务器是遭了殃,频繁被墙,换IP也顶不了多长时间,最后只能无奈放弃日本、美国服务器了。不过很奇怪的是,我的香港服务器今年开始就一次都没有被墙过,很迷。而欧洲和俄罗斯这些相对冷门的地区依然是毛事没有。再说说我分享的免费账号,今年之前,无论是美国还是加拿大的服务器都是一波一波的偶尔就会被墙一次,但是今年之后,美国服务器也是如上所述遭了殃,我陆续更换了很多美国地区都没什么卵用(目前都换到了欧洲),然而是加拿大的服务器今年开始一次都没有被墙过(和我自用的香港似的),很迷。综上所述,如果你使用某个地区的服务器频繁被墙,那么你 要么更换代理软件,要么就换其他地区试试,否则只能继续送人头了。

Servers in Japan and the U.S. are the most frequently blocked. Sometimes Hong Kong servers will continue to work even during sensitive periods. The locations most likely to work all the time are Canada, Europe, and Russia.

2. VPS security

Follow standard practice for securing your server.

Use an SSH public-private key pair instead of a password to authenticate yourself for SSH or PuTTY. For Windows users, PuTTY comes with a utility, PuTTYgen, for generating your public-private key pair.

Update your software on a regular basis. For an Ubuntu 18.04 server, update all your packages like this:

apt-get update
apt-get upgrade

If at all possible, whitelist your IP address for access to port 22 (the SSH or PuTTY port). In this example, we assume you always connect to the server from a single IP address of 111.22.33.44:

iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -s 111.22.33.44/32 -j ACCEPT
iptables -P INPUT DROP
apt-get install iptables-persistent

Replace 111.22.33.44/32 by your actual IP address. If your ISP changes your IP periodically, but always allocates you an IP address within a known range, you can instead specify that range in your whitelist. For example, you could whitelist the source range 111.22.0.0/16. This cuts down on nuisance attempts to enter your server on port 22.

Improve network performance with the BBR congestion control algorithm by editing the system control configuration file:

vi /etc/sysctl.conf

Add the following two lines at the end of the file:

net.core.default_qdisc=fq
net.ipv4.tcp_congestion_control=bbr

Write the system control configuration file to disk, and quit the editor:

:wq

Reload the system control configuration:

sysctl -p

3. Cover website

Obfuscation depends on pretending your server hosts a website. If you want this strategy to work, you must build an actual website. A quote from the original article:

SS SSR都有混淆功能,不过我今天主要说 SSR,SS 用户可以参考下,而很多SSR脚本(包括我的脚本)默认的混淆参数都是 tls1.2_ticket_auth(前段时间两个脚本都改成默认 plain 了),而经过我的简单研究发现:只使用HTTP或HTTPS混淆的代理服务器被墙几率更高。首先,无论是 SS 还是 SSR 的混淆,都属于伪混淆,即代理客户端将访问代理服务器的流量伪装成访问 HTTP HTTPS 网页的流量,但是如果你没有做真实网站(SSR 服务端的 redirect 参数),那么这都是有可能被主动探测识破的。SSR 的HTTP HTTPS混淆一开始的目的是针对那些被限速的地区(例如学校、公司),混淆伪装为 HTTP HTTPS 即可避开限速。后来 HTTP HTTPS混淆就更偏向于让 GFW 难以发现(服务端 redirect 参数),不过很多人依然是只选择 HTTP HTTPS 混淆插件,混淆参数也不填,服务端 redirect 参数也不做,端口也不是 80 443。这样在外界看来,你的流量就是在访问 http://ip:4567 一样,看起来就很奇怪。有的人可能还会填个混淆参数,不过填写的混淆域名也是各种逗比,有什么 bing.com 、www.icloud.com 之类的。。。我就很纳闷了,首先这种单纯混淆伪装的方式是没有真实域名解析的,即互联网中根本没有该域名解析为你的服务器IP的解析记录。其次你用个 Vultr 、搬瓦工,混淆个 微软、苹果 的域名,难道微软和苹果都已经差钱到只能买 Vultr、搬瓦工这等级的服务器维生了么?这也太假了吧,就不能站在 GFW 的角度想一想。。。但是,就算你选个没毛病的域名来混淆伪装,结果被 GFW 一波主动探测识破根本没有网站,那岂不是直接明白你在用 SS 或 SSR 了吗?综上所述,要么你搭配服务端的 redirect 参数做个真实网站,要么就干脆用原版混淆插件( plain )。不想看前面解释的,直接看简单说明。首先 SSR 目前依然是可以正常使用的,不过在热门地区(日本、美国等)被墙几率会高一些。很多人都是默认只用 HTTP HTTPS 混淆插件 ,或者再写个混淆参数 ,但是这样属于伪混淆 ,仅仅是将流量伪装成 HTTP HTTPS 流量,并没有真实网站,所以可以被主动探测识破。因此,在热门地区(日本、美国等)搭建 SSR 代理的,建议要么搭配服务端的 redirect 参数做个真实网站(只能降低被墙记录,不能保证不被墙),要么就干脆用原版混淆插件( plain )。

3.1. Domain name

Since you want the website to be as realistic as possible, you will need a domain name. If you buy a paid domain name, make sure your domain name registrar includes “whois” privacy. If you choose a free domain name, you can get one from https://www.freenom.com.

For the rest of this post, we will use the example of a domain name phoebe2019.cf and a server host name www.phoebe2019.cf. These were obtained from Freenom.

Once you have chosen and obtained your domain name, add a DNS “A” record pointing from your host name to your server’s public IP address. To continue with the example of Freenom, click Services > My Domains. On the row for your domain, click Manage Domain. Then click the tab for Manage Freenom DNS. Add a record:

  • Name www
  • Type A
  • Time to live (TTL) 3600 (seconds)
  • Target your.server.IP.address

In this example, we give 55.66.77.88 as an example of a server IP address. Substitute in your actual server IP address.

Click Save Changes. A message appears, “Record added successfully.”

To make your web server more realistic, try also to set up reverse DNS (rDNS) entry from your VPS IP address back to its hostname if your VPS provider allows this.

3.2. Install Nginx

For an Ubuntu 18.04 server, you can install a web server like this.

Open the firewall for ports 80 (HTTP port) and 443 (HTTPS port).

iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
dpkg-reconfigure iptables-persistent

Install the Nginx web server:

apt-get install nginx

Set your server name in the Nginx default site configuration file:

vi /etc/nginx/sites-available/default

Find the line server_name _; and change it to read (in our example):

server_name www.phoebe2019.cf;

Write the file to disk, and quit the editor:

:wq

Restart Nginx for this change:

systemctl restart nginx

Provided your domain name entry has had time to propagate, you can test your work so far by opening a browser and visiting your site. For example:

http://www.phoebe2019.cf

You should see the “Welcome to nginx!” page.

3.3. Add content to website

Make your website realistic by adding some non-controversial content. In this example, we have stored some content at https://s3.jp-tok.cloud-object-storage.appdomain.cloud/template/w3-css-startup-template.zip. To add this content to your web server, in your SSH or PuTTY session with the server, issue in turn the commands:

mkdir ~/Downloads
cd ~/Downloads
apt-get install wget
wget https://s3.jp-tok.cloud-object-storage.appdomain.cloud/template/w3-css-startup-template.zip
apt-get install unzip
unzip w3-css-startup-template.zip
cp -rf w3-css-startup-template/* /var/www/html/
rm /var/www/html/index.nginx-debian.html

Again, you can test your work so far by opening a browser and visiting the HTTP (i.e., not HTTPS yet) version of your site. In our example, this would be:

http://www.phoebe2019.cf

Of course, you can add and change the content of the website to make it look more realistic.

3.4. Add Letsencrypt free SSL certificate

Proceed as follows to install and configure Letsencrypt on your Ubuntu 18.04 server.

Add the Personal Package Archive (PPA) repository for certbot, the Letsencrypt client:

add-apt-repository ppa:certbot/certbot

Install certbot for Nginx:

apt-get install python-certbot-nginx

Now run the Letsencryt client for your domain name:

certbot --nginx -d www.phoebe2019.cf

When prompted, enter an email address for urgent renewal and security notices.

Enter a to agree to the terms of service.

When asked if you want to share your email address, enter n for no.

Certbot asks if you want to force redirect of HTTP to HTTPS. Choose 1, no redirect, since this option will give more flexibility, which is what we want in our use case.

Certbot does its work and ends with a message telling you where it has stored the SSL certificate chain and key:

/etc/letsencrypt/live/www.phoebe2019.cf/fullchain.pem
/etc/letsencrypt/live/www.phoebe2019.cf/privkey.pem

Letsencrypt certificates are valid for only 90 days. After that, they must be renewed. The certbot package adds a renewal script, /etc/cron.d/certbot. Check that the certbot script has been set up to run twice daily with:

systemctl list-timers

To test the renewal process, do a dry run:

certbot renew --dry-run

Now test the HTTPS version of your website. In our example, open a browser and go to:

https://www.phoebe2019.cf

You should see the HTTPS version of your website. This was accessed on port 443.

3.5 Change listening port

We will change the listening port so that port 80 continues to host the HTTP version of the website, while the HTTPS version listens on port 8443. This is so that we can use port 443 for ShadowsocksR (SSR).

Edit the default Nginx default site configuration file:

vi /etc/nginx/sites-available/default

Change the lines:

listen [::]:443 ssl ipv6only=on; # managed by Certbot
listen 443 ssl; # managed by Certbot

to read:

listen [::]:8443 ssl ipv6only=on; # managed by Certbot
listen 8443 ssl; # managed by Certbot

Write the file to disk, and quit the editor:

:wq

Restart Nginx for these changes:

systemctl restart nginx

Note that the firewall is not open on port 8443. Therefore you cannot do any more testing just yet.

4. SSR server

The main advice is to make realistic use of the redirect parameter. In our example, we will redirect traffic with an incorrect SSR password from port 443 to the web server listening on port 8443.

Install the prerequisite packages for ShadowsocksR:

apt-get install git python-m2crypto libsodium23

Change into the directory where you will install SSR:

cd /usr/local

Clone SSR from the shadowsocksrr repository on Github :

git clone -b manyuser https://github.com/shadowsocksrr/shadowsocksr.git

Create a template for the ShadowsocksR configuration file:

cd shadowsocksr
bash initcfg.sh

Edit the template configuration file:

vi user-config.json

Specify your values for the ShadowsocksR port, password, encryption method, protocol, obfuscation method, and redirect. For example:

{
"server": "0.0.0.0",
"server_ipv6": "::",
"server_port": 443,
"local_address": "127.0.0.1",
"local_port": 1080,
"password": "happynewyear2019",
"method": "chacha20",
"protocol": "auth_sha1_v4",
"protocol_param": "",
"obfs": "tls1.2_ticket_auth_compatible",
"obfs_param": "",
"speed_limit_per_con": 0,
"speed_limit_per_user": 0,
"additional_ports" : {},
"additional_ports_only" : false,
"timeout": 120,
"udp_timeout": 60,
"dns_ipv6": false,
"connect_verbose_info": 0,
"redirect": "*:443#127.0.0.1:8443",
"fast_open": false
}

Press Esc if you need to escape from insert or replace mode.

Write the file to disk, and quit the editor:

:wq

Now create the systemd service file:

vi /etc/systemd/system/shadowsocksr.service

Insert contents as follows:

[Unit]
Description=ShadowsocksR server
After=network.target
Wants=network.target
[Service]
Type=forking
PIDFile=/var/run/shadowsocksr.pid
ExecStart=/usr/bin/python /usr/local/shadowsocksr/shadowsocks/server.py --pid-file /var/run/shadowsocksr.pid -c /usr/local/shadowsocksr/user-config.json -d start
ExecStop=/usr/bin/python /usr/local/shadowsocksr/shadowsocks/server.py --pid-file /var/run/shadowsocksr.pid -c /usr/local/shadowsocksr/user-config.json -d stop
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=always
[Install]
WantedBy=multi-user.target

Press Esc if you need to escape from insert or replace mode.

Write the file to disk, and quit the editor:

:wq

Make ShadowocksR start on reboot, and also start it now:

systemctl enable shadowsocksr.service
systemctl start shadowsocksr.service

5. SSR client

If your client is a Windows PC, download the SSR client from https://github.com/shadowsocksrr/shadowsocksr-csharp/releases, and unzip it. For Windows 8 or 10 with .NET 4.0, launch ShadowsocksR-dotnet4.0.exe. For Windows 7 or older with .NET 2.0, launch ShadowsocksR-dotnet2.0.exe.

If your client is an Android phone or tablet, download the SSR client apk file from https://github.com/shadowsocksrr/shadowsocksr-android/releases, and install the SSR Android client app on your device.

When you define the server to the client, the parameters on the client must match those on the server. Some advice from the original article on obfuscation parameters:

这时候为了加强该伪装的作用,还需要客户端混淆插件和混淆参数设置一番。如果你是伪装的 80 端口,请选择 http_simple 混淆插件,混淆参数填写你的域名(示例 toyoo.pw)。如果你是伪装的 443 端口,请选择 tls1.2_ticket_auth 或tls1.2_ticket_fastauth 混淆插件,混淆参数填写你的域名(示例 toyoo.pw)。SSR客户端的服务器地址填写 你的域名(示例 toyoo.pw)。SSR客户端的服务器端口填写 80 或 443 端口(取决于服务端端口)。所以这个就实现了,伪装 ShadowsocksR 服务端流量为 正常海外网站流量的目的,同时也可以说实现了 网站和ShadowsocksR 同端口共存。

In line with this advice, we set up the client parameters with server IP address and obfuscation parameters that match the server website:

  • Server IP www.phoebe2019.cf
  • Server port 443
  • Password happynewyear2019
  • Encryption method chacha20
  • Protocol auth_sha1_v4
  • Protocol parameter blank
  • Obfuscation tls1.2_ticket_auth
  • Obfuscation parameter www.phoebe2019.cf
  • Remarks blank
  • Group Private

Notes:

  1. You can lessen the window for replay attacks by changing the password every 3 days. Obviously, you must change the password on server and client simultaneously.
  2. In Firefox, you can make sure that DNS lookups are sent over the proxy by opening the Options/Preferences menu, and under Network Settings, manually configure the settings to use your SOCKS5 proxy on 127.0.0.1 port 1080, and check the box for Proxy DNS when using SOCKS v5.

6. End-to-end tests

  • Open a browser, and visit https://iplocation.net. Expected result: The IP address is that of your server, and the geolocation data is the location of your server.
  • On Windows, locate the paper airplane icon in the system tray, right-click to bring up the SSR menu, and select Quit. On Android, disconnect and quit. In either case, open a browser, and visit the HTTPS version of your website. In our example, that is https://www.phoebe2019.cf. Expected result: You see your website.