diff --git a/src/content/unix/reverse-proxy.md b/src/content/unix/reverse-proxy.md new file mode 100644 index 0000000..ac257d2 --- /dev/null +++ b/src/content/unix/reverse-proxy.md @@ -0,0 +1,170 @@ +--- +title: 'Bypass Network Lockdowns' +description: 'Reverse Proxies and SDWAN' +updateDate: 'Apr 21 2024' +--- + +# Bypassing Network Lockdowns + +I manage the network infrastructure for a [robotics club](https://arvp.org) on +campus. Unfortunately, the campus network has been heavily locked down for +security. It takes years to get Information Services and Technology (IST) to +agree to forward a port, and it's even harder for student clubs. + +Our club members need access to the robot through the open internet. This is +especially important for new members who aren't able to access the club's room +after hours. + +Due to this, I've put considerable effort into bypassing the restrictions placed +by the university. As it turns out, once you know what you're doing, it's pretty +easy! All you need is *outward* access to the internet, from there you can +easily get *inward* access to any port. + +## ZeroTier One + +The easiest method, and probably recommended for most users, is using Software +Driven WAN (SDWAN). This is similar to a VPN, but unlike Wireguard, ZeroTier One +doesn't [[1]] require a centralized server. + +Advantages: + - Free version is good enough for most small groups + - Very simple setup + - Very fast through UDP hole-punching + +Drawbacks: + - Limit of 25 clients (on the [free + version](https://www.zerotier.com/pricing/)) + - Requires installing separate software on all clients + - Sometimes fails to connect for up to an hour... very hard to debug when it + happens + - Can only be used by clients on the VPN. For example, a public webserver won't + be able to use this + +To use ZeroTier: + 1. Sign up for an account at [zerotier.com](https://www.zerotier.com/) + 2. Under "Networks" create a network and give it a name. Ensure access control + is private. + 3. Install ZeroTier One on all clients you'd like to connect. You can add more + later. + 4. On Linux, start and enable the ZeroTier one daemon with `systemctl enable + --now zerotier-one.service`. + 5. Find your network ID in the online console, then join with `sudo + zerotier-cli join `. + 6. Back in the web console, click the checkmark next to the new client that + joined, and give it a name. + 7. Now `sudo zerotier-cli listnetworks` should say `OK PRIVATE` for your + network. + 8. Repeat steps 3-7 for every new client you add. + +Now you should be able to use the IP listed in the web console for your device. +This will be in the right column under "Managed IPs". For example, if your +server has a zerotier IP of `172.27.100.10` another client would be able to +`ping 172.27.100.10` or with an ssh daemon running `ssh @172.27.100.10`. + +[[1]]: ZeroTier One still requires a centralized server, but they have "root +servers" which are available to the public for free, so no setup required on our +part. + +## Reverse Proxy + +Reverse proxies are a slightly more involved but generally better approach. They +use a second computer to forward information to the internal network. + +Advantages: + - Can be accessed by the public + - No additional software limits + - No client limits + +Drawbacks: + - No UDP hole punching: might have a bit more latency + - Requires a centralized server with a public IP (not necessarily static tho) + +To setup a reverse proxy, you'll need a computer with a public IP, that's +accessible behind the router. You could use your home computer, but it'll need +to always stay on. A more popular approach is grabbing a cheap cloud computer. I +personally use the most basic droplets on [Digital +Ocean](https://www.digitalocean.com/pricing/droplets) for $4/month. Be sure to +choose the closest datacenter possible and ideally in the same country, to +minimize latency. + +I'll be referring to the computer powering the reverse proxy as the "droplet", +but the steps can easily be applied on your own Linux machine. + +Setting up a reverse proxy + 1. Build the [rathole](https://github.com/rapiz1/rathole) binary that's + compatible with your system. The droplet may require a different llvm + target. + 2. Create a client-side rathole configuration on the server. The token can be + any random string. Assuming the IP of the droplet is `172.27.10.10` and + we're using port `9001`, the configuration might look like this: + ```toml + [client] + remote_addr = "172.27.10.10:9001" + + [client.services.ssh] + token = "yNx6KUuG4P-VRIkzr-NWysZSI6-;04IWQs4sG0;a" + local_addr = "127.0.0.1:22" + + [client.services.webserver] + token = "C;KPmX-fYxAb;iGMwXEAl48woaYE;ey-CLapQJHs" + local_addr = "127.0.0.1:80" + + [client.services.forgejo] + token = "-zUbD;Wy6v35KmO;GZLHs;51sws-;7o5bJ-TjSJs" + local_addr = "127.0.0.1:8080" + ``` + 3. Create a systemd service on the server called `rathole_client.service`. + Edit the path of your `rathole` executable, and the argument to the config + file above: + ```systemd + # /etc/systemd/system/rathole_client.service + [Unit] + Wants=network-online.target + After=network-online.target + + [Service] + User=root + Group=root + Type=forking + Restart=on-failure + RestartSec=5s + KillMode=control-group + KillSignal=SIGTERM + ExecStart=/usr/local/bin/rathole /etc/rathole/client.toml + # You MUST edit the line above to point to your rathole binary + + [Install] + WantedBy=multi-user.target + ``` + 4. On the droplet, create a `server.toml`. It might look something like this, + matching the `client.toml` provided in step 2. + ```toml + [server] + bind_addr = "0.0.0.0:9001" # Must match port client is trying to contact + + [server.services.ssh] + token = "yNx6KUuG4P-VRIkzr-NWysZSI6-;04IWQs4sG0;a" + bind_addr = "0.0.0.0:8022" # Doesn't have to match client + + [server.services.webserver] + token = "C;KPmX-fYxAb;iGMwXEAl48woaYE;ey-CLapQJHs" + bind_addr = "127.0.0.1:80" + + [server.services.forgejo] + token = "-zUbD;Wy6v35KmO;GZLHs;51sws-;7o5bJ-TjSJs" + bind_addr = "127.0.0.1:443" + ``` + 5. On the droplet, you can simply start rathole manually in a tmux session with + `./rathole server.toml`. + 6. On the client run `systemctl enable --now rathole_client.service` + +Check the output of both commands (`systemctl status rathole_client.service`) to +make sure there aren't any errors. Assuming it's all good, you should be able to +contract the server through the droplet. For example, if we wanted to ssh into +the `emiliko` user on the server, the above config should allow that through: + +```bash +ssh -p 8022 emiliko@172.27.10.10 +``` + +This will be forwarded to port 22 on the server!