(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)
- A dedicated public IPv4 address (and hopefully IPv6 range)
- At least 512MB RAM
at the end of
/etc/sysctl.conf and then do
(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!)
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
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!
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.
Note: Not updated
Use Angristan's script!
curl -O https://raw.githubusercontent.com/Angristan/openvpn-install/master/openvpn-install.sh chmod +x openvpn-install.sh bash openvpn-install.sh
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 firstname.lastname@example.org:/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_configto 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.
apt install sslh --no-install-recommendsto install. Select
standalonewhen prompted, and put the following configuration in
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
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 10.8.0.0/24 -d 192.168.0.0/16 -j SNAT --to 192.168.0.106
10.8.0.0 is the subnet in which VPN clients are allocated IPs, where
192.168.0.0 is the LAN subnet, and where
192.168.0.106 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.confand then restart OpenVPN.