# Network side project
## Problem statement / Motivation
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 will 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.
```
VPN server (on GCP)
/ \
(VPN) (ss + VPN)
/ \
smartphone rpi sitting at home
```
The final solution is actually pretty simple. Traffic coming from VPN subnet to GCP are redirected through ss tunnel to rpi.
## Install SS 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
* 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
```
VPN server
```
* sample config file, assuming file name is `wg0.conf`
```
# 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 ens4 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o ens4 -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
```
VPN server ---(wireguard connection)--- rpi
```
* sample config file, assuming file name is `wg0.conf`
```
# 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
## Setup ss server on rpi
```
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`
## Setup ss client on vpn server and connect it to ss server on rpi
```
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 ss client for redirection
## Setup iptables on vpn server to do port forwarding on the port that ss client is listening to $\rightarrow$ have the iPhone connect to it
```
VPN server (ss client) ---(wireguard connection, ss)--- rpi(ss server)
```
* iptables for connecting via ss-client to vpn server
```
# list all rules
sudo iptables -L -v && sudo iptables -t nat -L -v
# Create new chain
# iptables -t nat -N SHADOWSOCKS
# iptables -t mangle -N SHADOWSOCKS
iptables -t nat -F 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
# Add any UDP rules
# ip rule add fwmark 0x01/0x01 table 100
# ip route add local 0.0.0.0/0 dev lo table 100
# iptables -t mangle -A SHADOWSOCKS -p udp --dport 53 -j TPROXY --on-port 8488 --tproxy-mark 0x01/0x01
# Apply the rules
iptables -t nat -A PREROUTING -p tcp -j SHADOWSOCKS
# iptables -t mangle -A PREROUTING -j SHADOWSOCKS
# Start the shadowsocks-redir
# ss-redir -u -c /etc/config/shadowsocks.json -f /var/run/shadowsocks.pid
# 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
```
* notes for [iptables for connecting via wireguard to vpn server](https://manpages.debian.org/testing/shadowsocks-libev/shadowsocks-libev.8.en.html)
# Tried but failed solutions
Actually the main problem here is how to preserve the destination IP while re-routing the packet to other places. That's why I settled with the ss solution.
## iptables packet forwarding
Destination IP retaintion issue