Unix: add reverse proxy blog

This commit is contained in:
Akemi Izuko 2024-04-21 21:00:53 -06:00
parent 9373a15b90
commit 7ec3d37186
Signed by: akemi
GPG key ID: 8DE0764E1809E9FC

View file

@ -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 <network-id>`.
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 <user>@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!