Skip to main content

Set up VPN to bypass censorship (Server)

(As of Jan 2019, this technique does work to bypass the GFW in China - I tested it myself.)

Updated Feb 2021 to move V2ray to Docker

This guide will show you how to set up a VPN server with V2Ray (VMess over WebSockets), WireGuard, SSH tunneling and OpenVPN.

1. Initial Server Setup

Reference: this guide

  • You will need a server with...:
    • At least 512MB RAM
      • Full virtualization (KVM/Xen HVM/Hyper V)
      Ubuntu 20.04, apt upgrade'd
      • A dedicated public IPv4 address (and hopefully IPv6 range)
  • Add:

at the end of /etc/sysctl.conf and then do sysctl -p

  • (Optional) Set network firewall to only allow ports 80/tcp,443/tcp,22/tcp,51820/tcp,51820/udp,1194/tcp if you are willing and able to.

  • Make sure you have a domain you can use for your server.

2. Let's Encrypt (SSL)

(Let's Encrypt is no longer needed with the new, Docker-based v2ray deployment. Yay!)

  • Install Certbot:
apt-get install software-properties-common
add-apt-repository ppa:certbot/certbot # (press enter at the prompt)
apt-get install certbot -y
  • At your DNS provider, set an A/AAAA record that points a domain/subdomain at your server's IP.

  • Get a certificate - certbot certonly --standalone. Enter your email / domain name at the prompts.

  • Add autorenew to crontab - @monthly certbot renew && service v2ray restart

3. V2Ray

Install Docker and Docker-Compose. We will be using the Docker version of V2Ray for a very simple and quick deployment.

Create a new directory (e.g. /opt/v2ray) and place the config.json and docker-compose.yaml files inside it. Be sure to replace the domain, email, and IDs with your own.

Then, run docker-compose up -d. Done!

In almost all cases, V2Ray will be the best at circumventing censorship. This is because it is "obfuscated" as CDN traffic and runs on standard port 443. In other words, it looks exactly the same as regular Websockets traffic to any firewalls in between you and the VPN server. Cool!

4. WireGuard

Install Docker and Docker-Compose. We will be using LinuxServer's Docker container for WireGuard for a very simple and quick deployment.

If your Linux kernel version is below 5.6, install the wireguard package on your host, so the wireguard kernel module is loaded. (Verify this by running the which wireguard command.) DOES NOT WORK ON OPENVZ.

Create a new directory (e.g. /opt/wireguard) and place the docker-compose.yaml file inside it. Edit the PEERS environment variable to reflect the number of peers you want and the SERVERPORT variable (and the port forwarding) as needed.

If you want to use port 53 (like the example shows), you have to stop and disable the systemd-resolved service, remove resolv.conf, create a new resolv.conf, then set a nameserver in resolv.conf.

Then, run docker-compose up -d.

After this, use magic-wormhole or a similar utility to copy the config files (which will be placed in the config directory) to your clients.

You can edit the PEERS environment variable at a later time to automatically generate new configs. 

5. OpenVPN

Note: Not updated

Use Angristan's script!

curl -O chmod +x bash

Make sure you select the first (default) option for the port. You MUST select TCP for protocol (or sslh will not work).

Copy (using a protocol such as scp) the .ovpn files to your client devices.

scp root@your.ip:/root/*.ovpn /local/folder/on/computer

You can run the script again at a later time to create a new user.

6. SSH Tunneling

Note: Not updated

  • SSH tunneling will allow use SSH (over port 22 or port 443) to establish a SOCKS proxy that we can run our traffic through.
  • First, create a new user: adduser tunnel --disabled-password
  • I assume you already generated a new SSH key, or have an existing one. Add the key to the tunnel user:
mkdir /home/tunnel/.ssh
echo "ssh-public-key" > /home/tunnel/.ssh/authorized_keys
chmod go-w /home/tunnel
chmod 700 /home/tunnel/.ssh
chmod 600 /home/tunnel/.ssh/authorized_keys
chown -R tunnel /home/tunnel/.ssh
  • Add this snippet to /etc/ssh/sshd_config to disable shell login for the tunnel group (security reasons):

Then restart ssh: systemctl restart ssh.


Note: Not updated

  • SSLH allows us to have multiple services (in this case, SSH, OpenVPN, and V2ray) sharing the same port.

  • Run apt install sslh --no-install-recommends to install. Select standalone when prompted, and put the following configuration in /etc/default/sslh:

Important note: On clouds like AWS where internal IPs are used, you MUST set the internal IP, not the public IP for "MYPUBLICIP" in sslh config.

Then start sslh: systemctl start sslh && systemctl enable sslh

8. V2Ray CDN

  • Using the CDN of your choice, set the domain of your machine as the origin.
  • The CDN you use MUST support WebSockets. I recommend AWS CloudFront or MaxCDN (now StackPath).
  • I recommend setting the base URL for the CDN as / or blank (this is what the client config is set to use).
  • Make sure caching is disabled.
  • For Cloudfront, there are some steps to follow:
    • Set "Origin Protocol Policy" to HTTPS only
    • Set "Viewer Protocol Policy" to Redirect HTTP to HTTPS
    • Set "Compress Objects Automatically" to Yes
    • Select "Use legacy cache settings" - it does NOT work with the non-legacy settings
    • Change the price class as needed (I would set to US, Canada, and Europe)
    • Leave everything else default

9. Unattended-Upgrades

I would enable unattended-upgrades so you don't have to log into your server all the time to perform manual updates. This is the config I use:

10. Access LAN Resources

  • By default, for security reasons, two discrete subnets are not able to access each other. To allow VPN clients to access resources on the LAN of the VPN server, do some IPTables trickery:
iptables -t nat -A POSTROUTING -s -d -j SNAT --to

Where is the subnet in which VPN clients are allocated IPs, where is the LAN subnet, and where is the LAN IP of the VPN server.

  • To allow clients to access resources in your LAN using OpenVPN, you can add push "route your.lan.ip.range net.mask" to /etc/openvpn/openvpn.conf and then restart OpenVPN.
JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.