Skip to main content

Protecting your server with a proxy

If you're hosting a Minecraft server at home, chances are you don't want to expose your home IP. One way to hide it is through a proxy. Setting one up can be a bit tricky though, so if you don't want to do that, I've included some alternatives, too.

How it works

Broadly, a proxy forwards traffic between two or more computers. In this case, the proxy is a server that will live on a VPS outside of your network and forward traffic between the Minecraft server and the clients. Only the proxy knows where the server is, which is how it hides your IP address. Clients connect to the proxy, which then forwards the data on to the server, optionally through a VPN for extra security.

What you'll need

  • A Spigot/Paper or Fabric server running somewhere in your network, port forwarded, and ready to go
  • A domain name (optional, but strongly recommended)
  • A cloud server (VPS)
  • A bit of Linux command-line knowledge

Main steps

Step 1: Getting a server

I use Linode, but you can get a VPS from anywhere. A Velocity proxy is super lightweight, so the server doesn't need much power. 1 vCPU and a gigabyte of RAM should work fine. Here are detailed steps for Linode:

  1. Sign up for Linode. There are referral codes that can get you $100 free trial credit for 60 days, but I don't have one here.
  2. Click the "Create Linode" button to create a server.
  3. Create a server with the following settings:
    • Image: Debian 12
    • Region: Any region close to you (a location central to your users is a good choice)
    • Linode Plan: First choose "Shared CPU," then "Nanode 1 GB"
    • Details: Name it whatever you want. You don't need any tags
    • Root Password: Set a strong password here. Don't forget it!
  4. Click "Create Linode"

Step 2: Preparing the server

Step 2.1: Adding a new user

Now that you have your server, it's time to set it up. SSH into your server using your root password.

ssh root@<yourip>

Now, let's create a new user.

adduser <username>

Enter a password for the new user and press enter. You can leave the next fields blank. Just press enter for each one. Once that finishes, we need to give the user sudo permissions.

usermod -aG sudo <username>

Now log out by typing exit. Log back in the same way you did before. Now, let's test if the new user is part of the sudo group. Switch to your new user.

su <username>

And we'll check if sudo works.

sudo whoami

If you get a response saying "root," you're good to go! Now we'll secure the server.

Step 2.2: Restricting SSH access

Now that you have a new user, let's secure the server by preventing the root user from logging in. First, switch back to your root user by typing exit. Then, edit the SSH server config file.

nano /etc/ssh/sshd_config

Find the line that says #PermitRootLogin yes. Uncomment the line by deleting the # and change it to say PermitRootLogin no. Save and exit ('Ctrl+X' then 'y' then 'enter'), then restart the service.

systemctl restart sshd

Now log out and SSH in as your new user.

Step 3: Setting up Velocity

Assuming you're logged into your non-root user, let's go to its home directory, make a new directory within it, and then enter it.

cd ~
mkdir proxy
cd proxy

You'll need Java for the proxy to work.

sudo apt-get update
sudo apt install openjdk-17-jdk

Press Y and enter when prompted. Once that finishes, check that the installation worked.

java -v

If you get an output listing the installed version, your Java installed correctly. Now we need to download the Velocity proxy. Go to https://papermc.io/downloads/velocity, right click the big blue button, and copy the link address. That's the jar file we need to run the server. Download it to your proxy server using wget.

wget <url>

When that completes, you should see the file when you list the contents of the directory using ls. Take note of the file name. Now, we'll run the proxy!

java -Xms1G -Xmx1G -jar <velocity-filename.jar>

The proxy is running! There's a problem, though. If you leave this console, the proxy will stop. We can solve this problem using a tool called "screen." Let's install it. First, stop your proxy with 'Ctrl+c'. Then install screen.

sudo apt install screen

Press Y and enter when prompted. We'll use screen to keep the proxy open in what's called a "screen session." First, create a session.

screen -S proxy

This creates a screen session and brings you into it. This is where we'll run the proxy. Make sure you're in the correct directory, then run the same command as before.

java -Xms1G -Xmx1G -jar <velocity-filename.jar>

The proxy is now running inside a screen session. To leave the session, type 'Ctrl+a', then type 'd'. This will detach you from the screen session and put you back where you were. The proxy is still running in the background. To reconnect, use screen -r proxy. Now we have to connect the proxy to your server.

Step 4: Connecting Velocity to your Minecraft server

Reconnect to the screen session, stop your proxy, and then detach from the session. Edit the velocity config, velocity.toml.

nano velocity.toml

Where it says bind = "0.0.0.0:25567", change it to bind = "0.0.0.0:25565". Set player-info-forwarding-mode = "modern". Under [servers], replace the default servers with main = "<homeip>:25567", swapping <homeip> with the public IP of your Minecraft server. Below that, in try = [ ], set it to "main". Finally, under [forced-hosts], set it to "<subdomain>.example.com" = [ "main" ], swapping <subdomain> for your subdomain if you're using one. See the sample below for formatting.

Sample velocity.toml file
velocity.toml
# Config version. Do not change this
config-version = "2.7"

# What port should the proxy be bound to? By default, we'll bind to all addresses on port 25577.
bind = "0.0.0.0:25565"

# What should be the MOTD? This gets displayed when the player adds your server to
# their server list. Only MiniMessage format is accepted.
motd = "<#09add3>A Velocity Server"

# What should we display for the maximum number of players? (Velocity does not support a cap
# on the number of players online.)
show-max-players = 500

# Should we authenticate players with Mojang? By default, this is on.
online-mode = true

# Should the proxy enforce the new public key security standard? By default, this is on.
force-key-authentication = true

# If client's ISP/AS sent from this proxy is different from the one from Mojang's
# authentication server, the player is kicked. This disallows some VPN and proxy
# connections but is a weak form of protection.
prevent-client-proxy-connections = false

# Should we forward IP addresses and other data to backend servers?
# Available options:
# - "none": No forwarding will be done. All players will appear to be connecting
# from the proxy and will have offline-mode UUIDs.
# - "legacy": Forward player IPs and UUIDs in a BungeeCord-compatible format. Use this
# if you run servers using Minecraft 1.12 or lower.
# - "bungeeguard": Forward player IPs and UUIDs in a format supported by the BungeeGuard
# plugin. Use this if you run servers using Minecraft 1.12 or lower, and are
# unable to implement network level firewalling (on a shared host).
# - "modern": Forward player IPs and UUIDs as part of the login process using
# Velocity's native forwarding. Only applicable for Minecraft 1.13 or higher.
player-info-forwarding-mode = "modern"

# If you are using modern or BungeeGuard IP forwarding, configure a file that contains a unique secret here.
# The file is expected to be UTF-8 encoded and not empty.
forwarding-secret-file = "forwarding.secret"

# Announce whether or not your server supports Forge. If you run a modded server, we
# suggest turning this on.
#
# If your network runs one modpack consistently, consider using ping-passthrough = "mods"
# instead for a nicer display in the server list.
announce-forge = false

# If enabled (default is false) and the proxy is in online mode, Velocity will kick
# any existing player who is online if a duplicate connection attempt is made.
kick-existing-players = false

# Should Velocity pass server list ping requests to a backend server?
# Available options:
# - "disabled": No pass-through will be done. The velocity.toml and server-icon.png
# will determine the initial server list ping response.
# - "mods": Passes only the mod list from your backend server into the response.
# The first server in your try list (or forced host) with a mod list will be
# used. If no backend servers can be contacted, Velocity won't display any
# mod information.
# - "description": Uses the description and mod list from the backend server. The first
# server in the try (or forced host) list that responds is used for the
# description and mod list.
# - "all": Uses the backend server's response as the proxy response. The Velocity
# configuration is used if no servers could be contacted.
ping-passthrough = "DISABLED"

# If not enabled (default is true) player IP addresses will be replaced by <ip address withheld> in logs
enable-player-address-logging = true

[servers]
# Configure your servers here. Each key represents the server's name, and the value
# represents the IP address of the server to connect to.
main = "<homeip>:25567"

# In what order we should try servers when a player logs in or is kicked from a server.
try = [
"main"
]

[forced-hosts]
# Configure your forced hosts here.
"<subdomain>.example.com" = [
"main"
]

[advanced]
# How large a Minecraft packet has to be before we compress it. Setting this to zero will
# compress all packets, and setting it to -1 will disable compression entirely.
compression-threshold = 256

# How much compression should be done (from 0-9). The default is -1, which uses the
# default level of 6.
compression-level = -1

# How fast (in milliseconds) are clients allowed to connect after the last connection? By
# default, this is three seconds. Disable this by setting this to 0.
login-ratelimit = 3000

# Specify a custom timeout for connection timeouts here. The default is five seconds.
connection-timeout = 5000

# Specify a read timeout for connections here. The default is 30 seconds.
read-timeout = 30000

# Enables compatibility with HAProxy's PROXY protocol. If you don't know what this is for, then
# don't enable it.
haproxy-protocol = false

# Enables TCP fast open support on the proxy. Requires the proxy to run on Linux.
tcp-fast-open = false

# Enables BungeeCord plugin messaging channel support on Velocity.
bungee-plugin-message-channel = true

# Shows ping requests to the proxy from clients.
show-ping-requests = false

# By default, Velocity will attempt to gracefully handle situations where the user unexpectedly
# loses connection to the server without an explicit disconnect message by attempting to fall the
# user back, except in the case of read timeouts. BungeeCord will disconnect the user instead. You
# can disable this setting to use the BungeeCord behavior.
failover-on-unexpected-server-disconnect = true

# Declares the proxy commands to 1.13+ clients.
announce-proxy-commands = true

# Enables the logging of commands
log-command-executions = false

# Enables logging of player connections when connecting to the proxy, switching servers
# and disconnecting from the proxy.
log-player-connections = true

# Allows players transferred from other hosts via the
# Transfer packet (Minecraft 1.20.5) to be received.
accepts-transfers = false

[query]
# Whether to enable responding to GameSpy 4 query responses or not.
enabled = false

# If query is enabled, on what port should the query protocol listen on?
port = 25577

# This is the map name that is reported to the query services.
map = "Velocity"

# Whether plugins should be shown in query response by default or not
show-plugins = false

Now you need to configure your server. Stop your server and then edit the server.properties file. Change server-port to equal 25567 and online-mode to equal false.

server.properties
online-mode=false
server-port=25568
important

Since your server is now running on port 25567, make sure to port forward that instead of 25565. If possible, for added security, restrict it in your firewall configuration to only accept connections from your proxy's IP.

Save server.properties. Now edit config/paper-global.yml. Under Proxies, then under Velocity, set enabled: true, online-mode-true, and secret: <secret>. You can find the secret in the forwarding.secret file on your proxy server.

paper-global.yml
  velocity:
enabled: true
online-mode: true
secret: <secret>

Save paper-global.yml. Start your server and the proxy, and you should be good to go! Either connect to your server using your proxy's ip, or follow the next step to add a domain!

Step 5: Connecting a domain

There are two methods you can use to point a domain to your proxy. In most cases, you can just use an A record, since the proxy should be running on port 25565, the default minecraft port. If it's not, though, you can use an SRV record.

Using an A record

Go to wherever you manage your DNS records and add an A record for a subdomain that points to your proxy's IP address. It's that simple.

Using an SRV record

Using an SRV record is a bit more complicated, and you should only need it if your proxy isn't accepting connections on port 25565. If that's the case, you probably know how to set it up, but here's an overview:

  1. Create an A record that points to the proxy.
  2. Create an SRV record that targets the address you set up with the A record. The name of the SRV record should be something like _minecraft._tcp.<subdomain>. The port will be the port your proxy is accepting connections on.

To add more security to your setup, you can encrypt the backend connection between your proxy and Minecraft server. This helps prevent people from trying to connect directly to the server without going through the proxy. This isn't a huge deal, since Velocity uses a secret to only allow proxy traffic, but it's good practice.

To secure the backend, we'll use WireGuard, a free, fast, and open source VPN.

info

This section is incomplete. Here is a good guide from DigitalOcean describing how to set WireGuard up on Debian 11, but it will work on Debian 12 as well: https://www.digitalocean.com/community/tutorials/how-to-set-up-wireguard-on-debian-11

You should be able to skip steps 4 and 5 in that guide since you're only going to tunnel some of the traffic. You also probably don't have to worry about IPv6.

If you set up the VPN, note that instead of setting your public IP in your velocity.toml, you'll set the IP of your server through your VPN. If you followed the guide above, that'll likely be 10.8.0.1 for you if you have the Minecraft server set up as the VPN server and the proxy set up as the client.

Alternatives

If you don't want to host your own proxy, here are some alternatives you can try:

  • playit.gg is a simple, user-friendly proxy service that can hide your IP. There's a free tier, but you can pay $3/mo to get features like the ability to use your own domain.
  • TCPShield is a Minecraft DDoS protection and proxying service. It's used by a few large servers, and it seems to have a comprehensive free tier.
  • zrok is an open-source tunneling service. It's more complicated to set up than playit.gg or TCPShield, but it might be less of a hassle than setting up your own proxy.
  • Tailscale is another tunneling service, but unlike zrok, it's not open-source. It's widely used, however, so support should be good.

Please note that we are not responsible for any of the above websites