If you want to host a Minecraft server from home, you usually need port forwarding. But what if your ISP uses CGNAT and doesn't support it?
You could use an SSH reverse tunnel, but there's a massive catch: all your players' IP addresses will show up as 127.0.0.1. If you want to run a public server, you can't IP ban griefers.
In this guide, I'll show you how I used a free Oracle Cloud VPS (with only 1GB of RAM), WireGuard, and HAProxy to expose my home Minecraft server to the internet while preserving every player's real IP address.
The Architecture
Here is the magic traffic flow we are building:
Player ➔ Oracle VPS (HAProxy) ➔ WireGuard Tunnel ➔ Home Server (PaperMC)
Because my home server doesn't have port forwarding, it reaches out to the VPS to create a WireGuard tunnel. The VPS then catches public Minecraft traffic, stamps the player's real IP onto it, and sends it through the tunnel to my house.
Prerequisites
- A home Minecraft server running PaperMC (Vanilla won't work for this).
- An Oracle Cloud "Always Free" VPS (Ubuntu 24.04). Note: If you have the 1GB x86 AMD instance like me, do not use a Java proxy like Velocity. We will use HAProxy to save RAM.
- A domain name (optional, but we'll use Cloudflare for this example).
Step 1: Build the WireGuard Tunnel
First, we need a private VPN tunnel between the VPS and your home server.
- VPS WireGuard IP:
10.0.0.1 - Home Server WireGuard IP:
10.0.0.2
Install WireGuard on both machines (sudo apt install wireguard -y) and generate keys (wg genkey | tee private.key | wg pubkey > public.key) on both.
On the VPS (/etc/wireguard/wg0.conf):
[Interface]
PrivateKey = <VPS_PRIVATE_KEY>
Address = 10.0.0.1/24
ListenPort = 51820
[Peer]
PublicKey = <HOME_PUBLIC_KEY>
AllowedIPs = 10.0.0.2/32On the Home Server (
/etc/wireguard/wg0.conf):[Interface]
PrivateKey = <HOME_PRIVATE_KEY>
Address = 10.0.0.2/24
[Peer]
PublicKey = <VPS_PUBLIC_KEY>
Endpoint = <YOUR_VPS_PUBLIC_IP>:51820
AllowedIPs = 10.0.0.1/32
# THIS IS CRUCIAL FOR NO PORT FORWARDING:
PersistentKeepalive = 25
Step 2: The Oracle Cloud iptables Trap (Read This!)
Oracle Cloud has a web dashboard to open ports, but Ubuntu on Oracle also has a strict internal firewall called iptables that blocks everything by default.
Even if you open port 25565 in the dashboard, Minecraft won't connect until you allow it in iptables. You'll also need to allow WireGuard (UDP 51820) and your web traffic if you plan to host a site.
Run these on your VPS:
sudo iptables -I INPUT 4 -p tcp --dport 25565 -j ACCEPT
sudo iptables -I INPUT 4 -p udp --dport 51820 -j ACCEPT
sudo iptables -I INPUT 4 -p tcp --dport 80 -j ACCEPT
sudo iptables -I INPUT 4 -p tcp --dport 443 -j ACCEPT
Make it permanent (or it will break on reboot!):
sudo apt install iptables-persistent -y
sudo netfilter-persistent save
Step 3: Configure HAProxy on the VPS
HAProxy is a tiny, lightning-fast load balancer that uses almost zero RAM. We will use it to intercept connections and inject the player's real IP using the "PROXY Protocol".
Install it on the VPS: sudo apt install haproxy -y
Open the config file (sudo nano /etc/haproxy/haproxy.cfg), delete everything, and paste this:
global
log /dev/log local0
log /dev/log local1 notice
daemon
maxconn 256
defaults
log global
mode tcp
option tcplog
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms
frontend minecraft_front
bind *:25565
default_backend minecraft_back
backend minecraft_back
server home_server 10.0.0.2:25565 send-proxy
(Notice we do not have the word check at the end of the server line. If you add check, HAProxy will try to ping Minecraft, but because Minecraft is expecting a PROXY header, it ignores the ping, HAProxy thinks the server is dead, and drops all players!)
Restart HAProxy: sudo systemctl restart haproxy
Step 4: Tell PaperMC to Read the Real IP
If you join right now, you'll get a "Disconnected" error. Why? Because HAProxy is sending the PROXY header, but PaperMC doesn't know how to read it yet.
On your Home Server, open your Paper config file:
- Minecraft 1.20.5+:
paper-global.yml - Minecraft 1.20.4 or older:
paper.yml
Find the proxies section and change it to exactly this:
proxies:
proxy-protocol: true
bungee-cord: false
velocity:
enabled: false
online-mode: false
secret: ''
Fully restart your Minecraft server. (Do not use /reload).
Note: Because Proxy Protocol is on, you can no longer join your server via localhost or your local LAN IP. You must join via the VPS IP to provide the correct handshake.
Step 5: The Cloudflare DNS Setup
Finally, let's point a clean domain to it. I used mc.mydomain.com.
Go to your Cloudflare DNS settings.
1. Create the A Record:
- Type:
A - Name:
mc - IPv4 Address:
<Your_VPS_Public_IP> - Proxy Status: DNS ONLY (Grey Cloud)
⚠️ CRITICAL: Do NOT click the orange cloud (Proxied). Cloudflare's proxy only understands web traffic (HTTP/HTTPS). If you proxy a Minecraft connection, Cloudflare will silently drop it, and nobody will be able to connect.
2. Delete any SRV Records:
If you previously tried to set up Minecraft and made an _minecraft._tcp SRV record, delete it. Since we are using the default port (25565), a simple A record is all you need. SRV records can actually conflict and break the connection here.
Conclusion
Open Minecraft, add mc.yourdomain.com, and join!
If you check your server console, you will see your real, public IP address. If a griefer joins, you can safely run /ban-ip <their-ip> and they will be blocked at the VPS level before they ever touch your home network.
All of this runs flawlessly on Oracle's free 1GB ARM or AMD instances, giving you a professional-grade reverse proxy setup for zero cost!