Chiisana from /r/admincraft has a really nice write-up about basic DDOS protection here, so rather than rehashing it I'll just write a brief summary and then continue to extend the ideas a little, covering GRE Tunnels, Zabbix monitoring, and DNS automation with Cloudflare.

Basic Idea

When dealing with a Denial of Service by sheer bandwidth, by the time the traffic hits our server it's already too late: no amount of shaping or blocking will change the fact that our link is saturated. To protect it, we sit a few cheap VPS's between the players and the server and limit the bandwidth before it hits our server. The players are distributed between VPS's using round robin DNS, and if attackers saturate one VPS link, the others will still remain up.

Adding GRE Tunnels

Rather than using tcptunnel, I'm using GRE tunnels, so that the minecraft server gets the IP of the player connecting, and not the VPS IP.

The BuyVM guide is a good start for setting up a GRE tunnel, but it mixes up the VPS and server commands a little, and doesn't really explain what the commands are doing.

VPS commands:

echo 'net.ipv4.ip_forward=1' >> /etc/sysctl.conf

iptunnel add gre1 mode gre local VPS_GLOBAL_IP remote MC_GLOBAL_IP ttl 255

ip addr add 192.168.10.2/30 dev gre1
ip link set gre1 up

iptables -t nat -A POSTROUTING -s 192.168.10.0/30 -j SNAT --to-source VPS_GLOBAL_IP
iptables -t nat -A PREROUTING -p tcp -d VPS_GLOBAL_IP --dport 25565 -j DNAT --to-destination 192.168.10.1:25565
iptables -A FORWARD -p tcp -d 192.168.1.1 --dport 25565 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT

Breakdown

  • echo 'net.ipv4.ip_forward=1' >> /etc/sysctl.conf

This enables IP forwarding, and only needs to be run once.

  • iptunnel add gre1 mode gre local VPS_GLOBAL_IP remote MC_GLOBAL_IP ttl 255

This creates a new tunnel interface with the name "gre1", with type set to "gre",  local and remote IP's defining the tunnel endpoints.

  • ip addr add 192.168.10.2/30 dev gre1

We then give the interface a private IP address used to communicate with the interface on the other end of the tunnel.

  • ip link set gre1 up

Bring the interface up, it should now be listed when running "ifconfig"

  • iptables -t nat -A POSTROUTING -s 192.168.10.0/30 -j SNAT --to-source VPS_GLOBAL_IP

Re-write the source IP of all packets coming from our tunnel out to the players to the global IP of the VPS

  • iptables -t nat -A PREROUTING -p tcp -d VPS_GLOBAL_IP --dport 25565 -j DNAT --to-destination 192.168.10.1:25565

Change the destination port and IP of the packets incoming from the VPS's global IP to the other end of the tunnel

  • iptables -A FORWARD -p tcp -d 192.168.10.1 --dport 25565 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT

Finally we re-route the traffic down our GRE tunnel to the MC server.

MC Server commands:

iptunnel add gre1 mode gre local MC_GLOBAL_IP remote VPS_GLOBAL_IP ttl 255
ip addr add 192.168.10.1/30 dev gre1
ip link set gre1 up

echo '101 ATGRE' >> /etc/iproute2/rt_tables
ip rule add from 192.168.10.0/30 table ATGRE
ip route add default via 192.168.10.2 table ATGRE

Breakdown

The first block is just the same as for the VPS except the IP's are swapped round; remember not to use a subnet that conflicts with your LAN subnet.

  • echo '101 GRETUN' >> /etc/iproute2/rt_tables

Linux has a pretty powerful set of routing features, in this case allowing us to define multiple routing tables so that we can define some source routing policies. This command adds a new routing table into rt_tables, that we can use to add some rules specific to our tunnel.

  • ip rule add from 192.168.10.0/30 table GRETUN

Tell our system that all traffic from 192.168.10.0/30 will be dealt with by our "GRETUN" routing table.

  • ip route add default via 192.168.10.2 table ATGRE

Send any traffic from our 192.168.10.0/30 subnet (that we have no route for) to the other end of our tunnel, the VPS.

Once your happy with your config, you can add it to /etc/rc.local so that it runs each time the system boots. This means you can change it easily simply by restarting.

Notes:

  • If your MC server is sitting behind a firewall and has no global IP, you can use 0.0.0.0 as the MC IP in the MC server config, point your VPS's tunnel to your firewall's global IP, and set up the firewall to pass gre traffic through to your MC server.
  • For any other services sitting on the same machine as the MC server, you can simply duplicate the iptables rules on the VPS, replacing the ports and protocol with that of your other service.
  • Since my website sits on a different machine behind the firewall, I'm going to use Cloudflare to mask it's IP, which I'll cover later on.