Published on

Using Traefik + Wireguard as a Reverse Proxy for a Minecraft Server

Authors

A little background

I love playing Minecraft with my friends, whether it's on a vanilla server or a heavily modded one. However, I don't like the idea of committing to a monthly payment for a server when I can host it myself. I've tried hosting a Minecraft server on AWS using ECS Spot instances, with a functionality that allows me to start and stop the server on demand using a Discord bot.

Mini PC
Enter my new Mini PC (Beelink Mini S12 Pro), replacing my Raspberry Pi 4B.

However, since I've bought a Mini PC that I can use as a home server, I thought it would be a better idea to host the server at home. This way, I can have more control over the server and save some money in the long run.

Problem

The problem with hosting a Minecraft server at home is that you should expose your server to the internet. This means you have to set up port forwarding on your router, which can be a security risk. I've done this before with my Raspberry Pi, and it worked fine for a while. But I don't want to do it again with my new mini PC.

I don't want people connecting directly to my mini PC directly, revealing my IP address of my router, just in case someone was bored and decided to DDoS my server. One workaround is to use a VPN, but I don't want to have to connect to a VPN every time I want to play. As for reverse proxy, I've used Cloudflare Tunnel for my other services, but it doesn't support tunneling TCP/UDP traffic, which is required for a Minecraft server. I've also tried ngrok and LocalXpose, but they cost up to $15/month to use a custom domain.

Solution

I decided to set up a reverse proxy on AWS using the cheapest EC2 instance available. This is because I don't need to commit to a monthly payment, and I can easily configure a custom domain for that proxy server. I will only be charged per running hour of the instance, and I can shut it down whenever I want.

How it works

Wireguard will act as a bridge between the mini PC and the proxy server. The proxy server runs Wireguard server, and the mini PC will connect to the proxy server using a Wireguard client. The proxy server will then use Traefik to route the incoming TCP and UDP traffic to the Minecraft server running on the mini PC.

Traefik + Wireguard
Illustration of how Traefik and Wireguard work together.

Every player will connect to the proxy server, and the traffic will be routed to the mini PC. This way, the mini PC doesn't have to reveal its public IP address. The proxy server can be easily switched off when it's not needed anymore (when we're done with Minecraft).

Choosing the right EC2 instance

For this use case, I don't need a powerful EC2 instance because it will only be used as a reverse proxy. I just need an instance that can run Traefik and Wireguard, and that can handle the incoming TCP and UDP traffic. I also need an instance that is cheap, because I don't want to spend a lot of money on it.

t4g pricing

I went with t4g.nano because it's got an ARM chip and that makes it super cheap. For linking the proxy server to my mini PC, I picked Wireguard since it's free, fast, and secure. And to sort out the incoming TCP traffic the Minecraft server, I went for Traefik. This setup means I don't have to mess with port forwarding or reveal my public IP. Plus, I can use a custom domain for the proxy server.

Setting up the proxy server

I won't go into detail about setting up an EC2 instance, but I will show you how to set up Traefik and Wireguard on it. First, you need to install Docker and Docker Compose on the instance. Then, create a docker-compose.yml file with the following content:

version: '3'

services:
  proxy:
    image: traefik:latest
    container_name: proxy
    network_mode: host
    volumes:
      - ./:/etc/traefik

This is a simple docker-compose.yml file that will run Traefik on the host network. The volumes section is used to mount the current directory to the /etc/traefik directory inside the container. This is where we will put the Traefik configuration file.

Next, create a traefik.yml file with the following content:

accessLog:
  filePath: /etc/traefik/access.log
log:
  level: DEBUG
api:
  dashboard: true
  insecure: true
providers:
  file:
    filename: /etc/traefik/dynamic_conf.yml
    watch: true
entryPoints:
  mc-java:
    address: ":25565"
  mc-bedrock:
    address: ":19132/udp"

This is the Traefik configuration file. It tells Traefik to listen on two entry points: mc-java and mc-bedrock. The mc-java entry point is for the Java edition of Minecraft, and the mc-bedrock entry point is for the Bedrock edition. The providers section tells Traefik to use a file provider to read the dynamic configuration from the dynamic_conf.yml file. The api section enables the Traefik dashboard.

Now, create a dynamic_conf.yml file with the following content:

tcp:
  routers:
    mc-java:
      rule: HostSNI(`*`)
      service: mc-java
      entryPoints:
        - mc-java
  services:
    mc-java:
      loadBalancer:
        servers:
          - address: "10.10.0.2:25565"

udp:
  routers:
    mc-bedrock:
      service: mc-bedrock
      entryPoints:
        - mc-bedrock
  services:
    mc-bedrock:
      loadBalancer:
        servers:
          - address: "10.10.0.2:19132"

This is the dynamic configuration file. It tells Traefik to route TCP traffic from the mc-java entry point to the mc-java service, and UDP traffic from the mc-bedrock entry point to the mc-bedrock service. The loadBalancer section specifies the address of the Minecraft server.

Now, assuming you already have docker compose installed, you can start the Traefik container by running the following command:

docker-compose up -d

This will start the Traefik container in the background. You can access the Traefik dashboard by going to http://<your-ec2-instance-ip>:8080. Don't forget to open the ports 8080, 25565, and 19132/udp in the security group of your EC2 instance.

Setting up the Wireguard server

Now that the proxy server is set up, you need to set up the Wireguard server on the proxy server. First, install Wireguard on the EC2 instance by following the instructions here. Then, generate a private key and a public key for the Wireguard server

wg genkey | tee privatekey | wg pubkey > publickey

This will generate a private key and a public key for the Wireguard server. Next, create a wg0.conf file with the following content:

[Interface]
Address = 10.10.0.1/24
PrivateKey = <proxy-server-private-key>
ListenPort = 51820

[Peer]
PublicKey = <home-server-public-key>
AllowedIPs = 10.10.0.2/32

This is the Wireguard configuration file. It tells Wireguard to listen on port 51820 and assign the IP address 10.10.0.1 to the Wireguard server. The AllowedIPs section specifies the IP address of the home server. Replace <proxy-server-private-key> with the private key of the proxy server and <home-server-public-key> with the public key of the home server.

Notice that we're using a private IP address range 10.10.0.1/24 for the Wireguard connection. The Wireguard server will act as a bridge between the home server and the proxy server, and it uses the defined IP address range to identify devices in the private network. We can use any private IP address range, but I chose 10.10.0.1/24 arbitrarily.

The AllowedIPs section defines the IP addresses that can connect to the Wireguard server. In this case, we're only allowing the home server to connect to the Wireguard server. I specified the IP address 10.10.0.2 for the home server, but you can use any IP address as long as it's in the 10.10.0.1/24 range.

In the ListenPort section, we specify the port that the Wireguard server will listen on. This is the port that the home server will use to connect to the Wireguard server. We can use any port, but I chose 51820 following Wireguard's default port. Having this set up, make sure you open port 51820 in the security group of your EC2 instance.

After creating the wg0.conf file, you can start the Wireguard server by running the following command:

wg-quick up wg0

Setting up the Wireguard client

Now that the Wireguard server is set up, you need to set up the Wireguard client on the home server. First, install Wireguard on the home server. Then, generate a private key and a public key for the Wireguard client, just like we did for the Wireguard server.

wg genkey | tee privatekey | wg pubkey > publickey

This will generate a private key and a public key for the Wireguard client. Next, create a wg0.conf file with the following content:

[Interface]
Address = 10.10.0.2/24
PrivateKey = <home-server-private-key>

[Peer]
PublicKey = <proxy-server-private-key>
Endpoint = <ec2-instance-ip>:51820
AllowedIPs = 10.10.0.1/32
PersistentKeepalive = 25

It's the same as the Wireguard server configuration file, but with the Address and PrivateKey sections changed. The Address section specifies the IP address of the home server, AllowedIPs specifies the IP address of the proxy server. Since we're setting up a Wireguard client, we don't need to specify the ListenPort section, but we need the Endpoint section to define the address of the proxy server.

The PersistentKeepalive section specifies the interval at which the home server will send keepalive or heartbeat packets to the proxy server. This is necessary to keep the Wireguard connection alive, especially if the home server is behind a NAT. I chose 25 seconds, but you can use any value that you want.

After creating the wg0.conf file, you can start the Wireguard client by running the following command:

wg-quick up wg0

Setting up a custom domain

Finally, now that the Wireguard server and client are set up, you can set up a custom domain for the proxy server if you have your own domain. This is optional, but it's a good idea to have a custom domain so that you can easily switch the proxy server off when you don't need it. Your Minecraft server address will also be easily remembered by your friends.

For this step, you just need to set up a DNS record for your domain that points to the public IP address of your EC2 instance. You can do this by going to your domain registrar's website and adding an A record that points to the public IP address of your EC2 instance. If you're using Cloudflare, you can follow the instructions here.

Afterword

That's it! You've set up a reverse proxy for your Minecraft server using Traefik and Wireguard. Now, you can connect to your Minecraft server using your custom domain, and you don't have to reveal your public IP address. You can also easily switch the proxy server off when you don't need it. You might be wondering about the cost of running the EC2 instance, but it's super cheap. I've been running the t4g.nano instance for 20 days, and this is the cost breakdown:

EC2 cost
Cost of running t4g.nano for 20 days.

It may not reflect the actual cost of running the instance for a month because I used other services on the same account. But you can see that it's super cheap. I hope this guide helps you set up a reverse proxy for your Minecraft server, or at least gives you some learnings. If you have any questions or need help, feel free to reach me out on Mastodon or Email me. Happy self-hosting!