Rathole Tunnel: Securely and Cheaply Expose Local Palworld Server
Why?
The biggest reason I needed to run a reverse tunnel was to get around NAT issues, but there are several benefits:
- I wanted to run a multiplayer game server for a recently popular game called Palworld
- I wanted to run the Palworld server on my local, beefy gaming maching
- I had an issue with NAT at my router
- I was not able to access my game server from within my local network using its public IP. This is a common issue with NAT, and not all routers support the feature to get around this issue. The router feature is called “NAT loopback” or “NAT hairpinning”, but my xfinity router did not support it.
- Here are some links to get a better understanding of the issue:
- ultimately, I could still access my server using its local IP, but I was using port forwards to give my friends access. Not the most secure
- I was not able to access my game server from within my local network using its public IP. This is a common issue with NAT, and not all routers support the feature to get around this issue. The router feature is called “NAT loopback” or “NAT hairpinning”, but my xfinity router did not support it.
- I did not want to expose my local machine to the internet via port forwarding or DMZ
- I did not want to pay more than $5/month for a solution
How?
- local Palworld server
- Ubuntu 22.04 via WSL2 on my Windows gaming machine
- palworld-server-docker
- Rathole tunnel
- Rathole is a reverse tunneling tool that allows you to easily expose local services to the internet. It’s written in Rust and very fast. It’s similar to
localtunnel
orngrok
, but it’s open source and you run your own server. - Rathole server running on a remote VPS
- I went with the cheapest DigitalOcean droplet, ~$4/month
- My goal was to get a publicly accesible box up quickly. You could probably run Rathole on a Raspberry Pi, and this could be a good solution if you already have an rpi running at home and exposed publicly to the internet.
- Rathole client running on my local machine
- Rathole is a reverse tunneling tool that allows you to easily expose local services to the internet. It’s written in Rust and very fast. It’s similar to
Final Solution
Rathole Server
- Create new droplet on Digital Ocean (DO)
I am using Digital Ocean because I am familiar with it, but any cheap VPS should work. We’re only running a tunnel on this box, not the game server itself.
- Create a new project if you do not already have a DO project
- Create a new droplet
- Choose a region that is a decent middle ground between you and your friends or expected server members.
- Leave the default datacenter (unless you have other plans for this droplet and need specific features that are only available in certain datacenters)
- I always choose the most recent LTS (long term support) version of Ubuntu, “22.04 (LTS) x64” at time of writing.
- Droplet type should be “shared cpu”
- CPU options > Regular, Disk Type: SSD
- Then choose the cheapest, $4/month option
- No need to add a volume
- Add your ssh key
- Can change hostname to whatever you like, I went with
rathole
- Can use any tags you want, e.g.
rathole
,reverse-tunnel
,palworld
, etc
- Once the droplet has finished provisioning, ssh into it. The droplet IP will be shown on the droplets dashboard on the DO website
ssh root@<droplet-ip>
- you’ll be authenticated via the ssh key you added to the droplet- generally a good idea to upgrade the system after first login
sudo apt update && sudo apt upgrade -y
- probably want to reboot after
sudo reboot
(note: you’ll lose connection and need to ssh back in!)
- Install Docker
- Some linux distributions come with unofficial docker packages, but it’s recommended to install from the official docker repository
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16# add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
# Add the repository to Apt sources:
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
# Install docker and related packages
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
- Some linux distributions come with unofficial docker packages, but it’s recommended to install from the official docker repository
- Create a project directory and necessary files
- Create directory and files
1
2
3
4
5mkdir ~/rathole-palworld
# docker-compose configuration
touch ~/rathole-palworld/docker-compose.yaml
# rathole server configuration
touch ~/rathole-palworld/server.toml - Populate
docker-compose.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13# docker-compose.yaml
services:
palworld-rathole-server:
restart: unless-stopped
container_name: palworld-rathole-server
image: rapiz1/rathole
command: ["--server", "/app/server.toml"]
ports:
- 2333:2333 # for rathole communication
- 8211:8211/udp # for palworld communication
- 27015:27015/udp # for steam client communication
volumes:
- ./server.toml:/app/server.toml - Populate
server.toml
1
2
3
4
5
6
7
8
9
10
11
12
13
14# server.toml
[server]
bind_addr = "0.0.0.0:2333" # `2333` specifies the port that rathole listens for clients
default_token = "use_a_secret_that_only_you_know"
[server.services.palworld]
type = "udp"
bind_addr = "0.0.0.0:8211"
nodelay = true
[server.services.palworld2]
type = "udp"
bind_addr = "0.0.0.0:27015"
nodelay = true
- Create directory and files
- Run Rathole server via docker compose
1
2# starts the rathole server in the foreground
docker compose up- Helpful docker-compose commands
docker compose up -d
- start the server in the backgrounddocker compose down
- stop the serverdocker compose logs -f
- view the server logsdocker compose logs -f palworld-rathole-server
- view the server logs by container name
- Helpful docker-compose commands
Rathole Client
NOTE: We are now going to be running a client on the same machine as the game server! So you’ll be running commands in a WSL/Ubuntu terminal session that’s running on your local machine now.
- Create directory and files for Rathole client
1
2
3
4
5mkdir ~/rathole-palworld
# docker-compose configuration
touch ~/rathole-palworld/docker-compose.yaml
# rathole server configuration
touch ~/rathole-palworld/client.toml - Populate
docker-compose.yaml
1
2
3
4
5
6
7
8
9services:
palworld-rathole-client:
restart: unless-stopped
container_name: palworld-rathole-client
image: rapiz1/rathole
command: ["--client", "/app/client.toml"]
network_mode: host
volumes:
- ./client.toml:/app/client.toml - Populate
client.toml
- make sure to replaceyour.digital.ocean.ip
with the IP of your droplet! And thedefault_token
needs to match thedefault_token
in your Rathole server’sserver.toml
NOTE: 2024/2/16 - Added
client.transport
andclient.transport.tcp
sections. This helped A LOT with some users’ connection issues. There is some issue with the udp packets not being received correctly and causing the tunnel to terminate, but this setting mostly fixed the issue.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22# client.toml
[client]
remote_addr = "your.digital.ocean.ip:2333" # The address of the server. The port must be the same with the port in `server.bind_addr`
default_token = "use_a_secret_that_only_you_know"
retry_interval = 1
[client.transport] # The whole block is optional. Specify which transport to use
type = "tcp" # Optional. Possible values: ["tcp", "tls", "noise"]. Default: "tcp"
[client.transport.tcp]
keepalive_secs = 5 # Optional. Specify `tcp_keepalive_time` in `tcp(7)`, if applicable. Default: 20 seconds
keepalive_interval = 2 # Optional. Specify `tcp_keepalive_intvl` in `tcp(7)`, if applicable. Default: 8 seconds
[client.services.palworld]
local_addr = "127.0.0.1:8211"
type = "udp"
nodelay = true
[client.services.palworld2]
local_addr = "127.0.0.1:27015"
type = "udp"
nodelay = true - Run Rathole client via docker compose
1
2# starts the rathole client in the foreground
docker compose up - Test connection
- You should now be able to connect to your Palworld server using the IP of your DigitalOcean droplet. In the Palworld mulitplayer server page, you will input something that looks like
123.123.123.90:8211
, where the left side of the colon is the IP address of your DigitalOcean droplet.
- You should now be able to connect to your Palworld server using the IP of your DigitalOcean droplet. In the Palworld mulitplayer server page, you will input something that looks like
Final Notes
This solution works well to get around NAT issues and expose a local game server to the internet without exposing anything else. It’s more secure than port forwarding or DMZ, and it’s still quite cheap. It’s been working well for my friends and I, and I hope it works well for you. I created a Github repository to help you get started with this solution. You can find it here.
You can leave an issue on the repo, or you can find out how to contact me on my Github profile if you need any help or have any questions! You can also leave a comment on this blog post if you are logged into Github.
Thanks for taking the time to read this post, and I hope it helps you out!
Palworld things I’m working on: