It all started with my previous bad experience when doing VPN hosting myself…
If we host VPN servers on GCP/AWS/DO/Linode, you now have all the devices on local network, but the common problems/downsides are e.g. streaming services like Netflix will block you (so you need to turn off VPN a lot of times…); Google search will often challenge you with recaptcha, etc. So I would like to find a way to workaround it :)
Expectation / Solution
The VPN servers in the cloud usually have bad IPs, but the IP that we are using at home is usually good and not blocked! So if we can somehow redirect all external traffic going out of VPN servers hosted in the cloud to our home IP, we are all set.
But hosting VPN server at home, which is usually a floating IP and behind NAT, is hard. So we need some workaround for it!
Architecture
This is my final setup.
1
2
3
4
5
|
VPN server (on GCP)
/ \
(VPN) (ss + VPN)
/ \
smartphone rpi sitting at home
|
The final solution is actually pretty simple. Client traffic coming from VPN subnet to GCP are redirected through ss tunnel to rpi, then exit to the world from there.
So basically
- Install wireguard and shadowsocks on vpn server and rpi
- Connect vpn server and rpi with wireguard
- Setup shadowsocks server on rpi
- Setup shadowsocks client on vpn server, connect to shadowsocks server on rpi, and forward traffic to shadowsocks server
Install shadowsocks on vpn server and rpi
go get -u -v github.com/shadowsocks/go-shadowsocks2
- manual is here
https://github.com/shadowsocks/go-shadowsocks2
Install wireguard on vpn server and rpi
sudo apt install wireguard
- don’t forget to open the port for connection on cloud computing platforms
- allow ip forwarding on servers
sudo sysctl -w net.ipv4.ip_forward=1
sudo sysctl -p /etc/sysctl.conf
to reload settings
Common commands for wireguard
- generate wireguard keys by
wg genkey | tee wg-private.key | wg pubkey > wg-public.key
- start the wireguard client/server using
sudo wg-quick up wg0
- stop the wireguard client/server using
sudo wg-quick down wg0
- check the wireguard connection using
sudo wg show
- can do
watch -n 1 sudo wg show
Setup wireguard vpn server
- sample config file, assuming file name is
wg0.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
# vpn server
[Interface]
Address = 10.200.200.1/24 # subnet
ListenPort = 12345 # external port for incoming connection
PrivateKey = [vpn server's private key]
# if you use -A, it might get installed after the drop rule + log rule!!
PostUp = iptables -I FORWARD 1 -i %i -j ACCEPT; iptables -I FORWARD 1 -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o [your outgoing interface name] -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o [your outgoing interface name] -j MASQUERADE
[Peer]
# rpi server
PublicKey = [rpi server's public key]
AllowedIPs = 10.200.200.2/32 # peer's ip in subnet
PersistentKeepalive = 30 # good for peers behind NAT
|
- run
sudo wg-quick up ./wg0.conf
in the directory where wg0.conf
is present
Setup rpi and connect to vpn server
1
|
VPN server ---(wireguard connection)--- rpi
|
- sample config file, assuming file name is
wg0.conf
1
2
3
4
5
6
7
8
9
10
11
12
|
# rpi server
[Interface]
Address = 10.200.200.2/24 # subnet ip
PrivateKey = [rpi server's private key]
DNS = 1.1.1.1
[Peer]
PublicKey = [vpn server's public key]
AllowedIPs = 10.200.200.1/32 # add all subnet ips that might have traffic coming in, so the return traffic can go through
Endpoint = [vpn server ip:port]
PersistentKeepalive = 30 # good for peers behind NAT
|
- run
sudo wg-quick up ./wg0.conf
in the directory where wg0.conf
is present
- connection between vpn server and rpi should be made and observable through
wg show
Setup shadowsocks server on rpi
1
|
VPN server ---(wireguard connection)--- rpi(ss server)
|
- run
./go/bin/go-shadowsocks2 -s 'ss://AEAD_CHACHA20_POLY1305:[password]@:[port that server will listen on]' -verbose
to start shadowsocks server on rpi
Setup shadowsocks client on vpn server and connect it to shadowsocks server on rpi
1
|
VPN server (ss client) ---(wireguard connection, ss)--- rpi(ss server)
|
- run
./go/bin/go-shadowsocks2 -c 'ss://AEAD_CHACHA20_POLY1305:[password]@[ss server ip:ss server port]' -redir :[port that redirected traffic should go to] -verbose
to setup shadowsocks client on vpn server for traffic redirection
Setup iptables on vpn server to do port forwarding on the port that shadowsocks client is listening to
1
|
VPN server (ss client) ---(wireguard connection, ss)--- rpi(ss server)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
# list all rules
sudo iptables -L -v && sudo iptables -t nat -L -v
# Create new chain
iptables -t nat -N SHADOWSOCKS
# Ignore your shadowsocks server's addresses
# It's very IMPORTANT, just be careful.
iptables -t nat -A SHADOWSOCKS -d 10.200.200.2 -j RETURN
# Ignore LANs and any other addresses you'd like to bypass the proxy
# See Wikipedia and RFC5735 for full list of reserved networks.
# See ashi009/bestroutetb for a highly optimized CHN route list.
iptables -t nat -A SHADOWSOCKS -d 0.0.0.0/8 -j RETURN
iptables -t nat -A SHADOWSOCKS -d 10.0.0.0/8 -j RETURN
iptables -t nat -A SHADOWSOCKS -d 127.0.0.0/8 -j RETURN
iptables -t nat -A SHADOWSOCKS -d 169.254.0.0/16 -j RETURN
iptables -t nat -A SHADOWSOCKS -d 172.16.0.0/12 -j RETURN
iptables -t nat -A SHADOWSOCKS -d 192.168.0.0/16 -j RETURN
iptables -t nat -A SHADOWSOCKS -d 224.0.0.0/4 -j RETURN
iptables -t nat -A SHADOWSOCKS -d 240.0.0.0/4 -j RETURN
# Anything else should be redirected to shadowsocks's local port
iptables -t nat -A SHADOWSOCKS -p tcp -j REDIRECT --to-ports 8488
# Apply the rules
iptables -t nat -A PREROUTING -p tcp -j SHADOWSOCKS
# allow wg0 traffic
sudo iptables -I INPUT 1 -i wg0 -p tcp --dport 8488 -j ACCEPT
# sudo iptables -D INPUT 1
# list all rules
sudo iptables -L -v && sudo iptables -t nat -L -v
|
Setup clients e.g. iPhones
- gen keys by
wg genkey | tee wg-private.key | wg pubkey > wg-public.key
- create a client config
1
2
3
4
5
6
7
8
9
|
[Interface]
Address = [client ip]/24
PrivateKey = [client's private key]
DNS = 1.1.1.1
[Peer]
PublicKey = [vpn server's public key]
AllowedIPs = 0.0.0.0/0 # for passing all traffic through wireguard
Endpoint = [server ip]:[server port]
|
- add a peer in server config, and
down
then up
the interface
- use
qrencode
to generate qrcode for clients to scan on their wireguard app on phones :)
- generate qrcode by
qrencode -t ansiutf8 < [filename]
- install qrcode by
sudo apt install qrencode
Tried but failed solutions
Actually the main problem is how to preserve the destination IP while re-routing the packet to other places. That’s why I settled with the wireguard + shadowsocks solution.