Self-hosting: Setting up a reverse proxy on a single VPS with multiple IPs

This blog post describes how to set up Rathole, a secure and efficient tunnel program, alongside a VPS, to achieve multiple static IPs for your self-hosted projects. This approach offers a cost-effective alternative to renting individual servers while providing greater flexibility and control over your network.

Requirements:

  • VPS: Choose a provider with good reputation, low latency, multiple static IP support, unmetered bandwidth, and a liberal hosting policy. The code snippets in this tutorial work on Ubuntu 20.04.
  • Decent Home Internet: Aim for at least 30mbps upload speed.
  • Low-powered Machine: An old laptop, NUC, or Raspberry Pi can suffice.
  • Network Isolation: Consider using VLANs or firewalls to separate your servers from other devices.

Overview:

  1. Install Rathole:
    • Download and compile the source code for Rathole on your VPS.
    • Copy the binary to all servers and configure them as services.
    • Use a script to generate separate configuration files for each public IP.
  2. Test the Tunnel:
    • Verify that ports 80 and 443 forward traffic properly.
    • Confirm that the public IPs work while the local servers remain inaccessible.
  3. Make it Permanent:
    • Install Rathole as a systemd service on each server.
    • Repeat the setup process for each static IP and local server pair.
    • Test that each IP routes separately.
  4. Troubleshooting:
    • Check Rathole logs for errors on both the VPS and client machines.

Additional Notes:

Benefits:

  • Gain three static IPs for under $30 per month.
  • Achieve greater control and flexibility compared to dynamic IPs.
  • Securely tunnel traffic through your VPS.
  • Enjoy the freedom to host various self-hosted projects.

Set up RatHole

This setup demonstrates how Rathole and a VPS can provide multiple static IPs for self-hosting enthusiasts on a budget. By following the steps and taking into account the additional notes, you can unlock a world of possibilities for your personal server projects.

Build the latest from source

https://github.com/rapiz1/rathole has generic instructions for setting up the tunnel. I took these steps to build it on an Ubuntu 20.04 machine.

# Essentials
apt install -y curl git build-essentials libssl-dev 

# Install Rust -- follow the prompts
curl https://sh.rustup.rs -sSf | sh
source "$HOME/.cargo/env"

# Clone the repo into a temp working directory
rm -rf /tmp/rathole
mkdir -p /tmp/rathole
cd /tmp/rathole
git clone https://github.com/rapiz1/rathole . 

# Build the binary and install
cargo build --release 
mv target/release/rathole /usr/bin/rathole
chmod +x /usr/bin/rathole

# Test that it works
rathole -v

# Clean up (optional)
rm -rf /tmp/rathole
# apt remove curl .... if you so wish

Install Rathole on server and clients

Assuming you are running the same OS/architecture, you can copy the generated binary from the previous step to /usr/bin/rathole on all the nodes.

The config files are set to tunnel ports 80, 443, 3000

Make sure you can execute the command on each node by running

rathole -v 

On the server:

curl https://raw.githubusercontent.com/rapiz1/rathole/main/examples/systemd/rathole%40.service --output /etc/systemd/system/[email protected]


On each of the clients:

curl https://raw.githubusercontent.com/rapiz1/rathole/main/examples/systemd/ratholec.service --output /etc/systemd/system/ratholec.service

Configure Rathole on the server

The GitHub repo has adequate examples of toml files. I used a bash script to generate a separate config for each of my public facing IP addresses.

#!/bin/bash

# Get IP addresses
ip_list=$(ip -f inet addr show eth0 | sed -En -e 's/.*inet ([0-9.]+).*/\1/p')
IFS=',' read -r -a ips <<< "$ip_list"

# Loop through each IP address
for ip in "${ips[@]}"; do
  # Generate random token for tunnel security
  token=$(echo $RANDOM | md5sum | head -c 30; echo)

  # Create server-side config file
  cat > "/etc/rathole/${ip}.toml" <<EOF
[server]
bind_addr = "${ip}:2333"
default_token = "${token}"

[server.services.http]
bind_addr = "${ip}:80"
type = "tcp"

[server.services.https]
bind_addr = "${ip}:443"
type = "tcp"
EOF

  # Create systemd service file for server
  file="ratholes@${ip}"
  systemctl enable "$file"
  systemctl start "$file"

  # Generate client-side config file
  client_toml_file="client_${ip}.toml"
  cat > "$client_toml_file" <<EOF
[client]
remote_addr = "${ip}:2333"
default_token = "${token}"
heartbeat_timeout = 40
retry_interval = 1

[client.services.http]
type = "tcp"
local_addr = "127.0.0.1:80"

[client.services.https]
type = "tcp"
local_addr = "127.0.0.1:443"
EOF

done

Reboot and test

Reboot your machine and test that the Rathole service accepts connections on all IPs

telnet 123.456.4.16 2333
telnet 123.456.4.17 2333
telnet 123.456.4.18 2333

Once connected, check that ports 80,443 forward traffic properly

On any machine inside your network (even your local), test each of the client files.

Run a temporary web server locally, install nginx, caddy, (anything that works on ports 80/443)

You can re-use the same binary from earlier if the platform is the same. If not, compile a new binary by repeating the earlier step on the client (necessary for Raspberry Pi or M1)

# Verify your local server responds
curl -v localhost:80
curl -Iv localhost:443

# Verify that the public IP DOES NOT work
curl -v 123.456.4.16:80
curl -Iv 123.456.4.16:443


rathole -c client_123.456.4.16.toml &

# Verify that the public IP WORKS
curl -v 123.456.4.16:80
curl -v 123.456.4.16:443

# Verify that the other 2 public IP DO NOT WORK
curl -v 123.456.4.17:80
curl -v 123.456.4.17:443

# Verify that the other 2 public IP DO NOT WORK
curl -v 123.456.4.18:80
curl -v 123.456.4.18:443

# Kill the process
pkill rathole

Configure Rathole on the clients

curl https://raw.githubusercontent.com/rapiz1/rathole/main/examples/systemd/ratholec.service --output /etc/systemd/system/ratholec.service

mkdir /etc/rathole
mv client_123.456.4.16.toml /etc/rathole/rathole.toml

# Enable rathole service
systemctl enable ratholec
systemctl start  ratholec
systemctl status ratholec

Repeat the above for each static IP – local server pair

Test Tunneling

Test that each IP routes separately

You can change the index.html for nginx or put a unique file in each one. We want to make sure that the traffic does not crossover.

Final check

  1. Restart the public VPS
  2. Restart each of the local servers
  3. Do the public IPs work after everything is booted up?

Troubleshooting

Forwarding not working

Make sure the services are running on the server:

journalctl -u [email protected] -b

journalctl -u [email protected] -b

journalctl -u [email protected] -b

Beyond the Basics:


Now that you have your Rathole tunnels up and running, let’s explore some additional possibilities:

Multiple Domains on a Single IP:

  • Install Nginx Proxy Manager to manage multiple domains on a single static IP. This allows you to host various websites and applications without needing additional IP addresses.
  • Let’s Encrypt integrates seamlessly with Nginx Proxy Manager, providing free and automatic SSL certificates for your domains.

Self-Hosted Heroku:

  • Use CapRover as a self-hosted platform for deploying and managing applications. This allows you to develop and run applications in a Docker container environment, similar to Heroku.
  • Forward a root domain (e.g., *.myapps.myname.com) to your CapRover server, providing a custom subdomain for each hosted application.

Run Your Own Local Cloud:

  • Explore Sandstorm, an open-source platform that allows you to self-host various applications like email, calendars, and file sharing.
  • This provides greater privacy and control over your data compared to traditional cloud services.

Circumvent Email Restrictions (Advanced):

  • Set up your own mail server and bypass your ISP’s email restrictions (without their knowledge).
  • Be sure to check with your VPS provider regarding any restrictions on mail server usage.

Open-Source Software Galore:

  • Discover a vast world of self-hosted applications on GitHub’s Awesome Self-Hosted list.
  • Explore various tools and services for self-hosting your own email, file storage, communication platforms, and much more.

Additional Notes:

  • Consider mesh networks for fine-grained control over your network rules.
  • Implement network isolation (DMZ, VLANs, firewall rules) to prevent your servers from accessing your home network.
  • Place your servers closest to the modem to minimize latency.
  • Monitor your host’s reliability with UptimeRobot.
  • If you have capped internet, consider CloudFlare caching to reduce bandwidth usage for static assets.

Additional Resources

https://github.com/davrodpin/mole
https://en.wikipedia.org/wiki/Hole_punching_(networking)

Unlock the full potential of self-hosting with Rathole and a VPS!