Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# macOS
.DS_Store

# Windows
Thumbs.db

# Editor settings
.idea/
.vscode/

# Editor temp files
*.swp
*.swo
*~
159 changes: 94 additions & 65 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,119 +1,148 @@
# IPTables-Rules - Basic
Basic IPTables Rules for a Minecraft Server
# iptables Rules - Basic
Basic `iptables` rules for a Minecraft server

In this guide you will find basic IPTables rules useful for a Minecraft server!
In this guide you will find a basic `iptables` ruleset that can be useful for a Minecraft server.

---

## What we need

1. Full root access (via su) to your machine (this guide won't work for Panels like Pterodactyl or Multicraft.
2. IPTables package.
3. NeTFilter Persistent package.
4. IPSET package (optional).
1. Full root access to your machine (this guide is not intended for panels such as Pterodactyl or Multicraft).
2. The `iptables` package.
3. The `iptables-persistent` package.
4. The `ipset` and `ipset-persistent` packages (optional).

---

## Installing the packages (root required)
`$ sudo apt update`
#### IPTables
#### iptables
`$ sudo apt install iptables`
#### IPTables Persistent
#### iptables persistence
`$ sudo apt install iptables-persistent`
#### IPSET (optional, read below)
`$ sudo apt install ipset` (optional, read below)
#### Enable the processes on systemd
#### ipset (optional, read below)
`$ sudo apt install ipset ipset-persistent`
#### Enable persistence with systemd
```
$ sudo systemctl enable iptables
$ sudo systemctl enable netfilter-persistent
$ sudo systemctl enable ipset
$ sudo systemctl enable netfilter-persistent
```

On modern Debian-family systems, `nftables` is the replacement framework for `iptables`, and `iptables` often works as the nft-compatible frontend. This guide still uses `iptables` syntax intentionally.

---

## Applying the Rules and Basic Concepts
If you are reading this guide, is probabily because you don't have a good knowledge about firewalling your server and secure the processes running on it.
It is **highly recommended** to run all the services in localhost (127.0.0.1) like MySQL or Backend Servers (Spigot servers not Proxy BungeeGuard/Velocity) and to not install webservices like Apache or NGINX.
If you are reading this guide, you probably want a simple starting point for firewalling your server and protecting the services running on it.
It is **highly recommended** to bind internal services to `127.0.0.1` whenever possible, such as MySQL or backend servers. Avoid exposing unnecessary web services such as Apache or NGINX unless you actually need them.

If IPv6 is enabled on your host, use an equivalent `ip6tables` ruleset such as the example shown below. If you are not going to filter IPv6, disable it intentionally rather than leaving it unmanaged.

If you are applying firewall changes over SSH on a remote host, consider using `iptables-apply`. It can roll back the rules automatically if the new ruleset disconnects your session.

#### SSH Tips
Run SSH using **Keys** and not Password! It is very important because we will avoid SSH Bruteforces attempts and we can better manage the access to our server generating SSH Keys for our trusted members.
For even further protection, we can use ipset and create an **IP List of trusted IPS** that can attempt a connection to the SSH Port.
Use SSH keys instead of passwords. This helps reduce brute-force attempts and makes it easier to manage access for trusted users.
For additional protection, you can use `ipset` to create a list of trusted IPs that are allowed to connect to the SSH port.

Note that you can change your SSH port by editing the `sshd_config` file, if you've done so, don't forget to change `22` to your new port in the below-mentioned commands examples.
Note that you can change your SSH port by editing `sshd_config`. If you do, replace `22` in the examples below with your custom port.

#### Basic Users Management
All the exposed services(for exposed I mean **externally accessible services**, like your Minecraft server) they should always be **RUNNED ONLY on a NON sudo User.**
Do not ever and ever use root or any sudo user to run externally accessible services.
All externally accessible services, such as your Minecraft server, should run only under a non-`sudo` user.
Do not run externally accessible services as `root` or as any user with `sudo` privileges.

#### Basic Rules
We aim to prevent your server from being bypassed by **UUID Spoofing.**
We aim to prevent your server from being bypassed by **UUID spoofing**.

**Minecraft Servers**
Set every Minecraft Backend server(spigot servers) to run in 127.0.0.1 in server.properties(server-ip).
Set only the ProxyServer(Bungee/Waterfall/Velocity) to run in 0.0.0.0 in config.yml(host: 0.0.0.0:25565).
Set also in the Proxy config.yml the servers with 127.0.0.0.1 address.
Set every Minecraft backend server (Spigot servers) to bind to `127.0.0.1` in `server.properties` (`server-ip`).
Set only the proxy server (Bungee/Waterfall/Velocity) to bind to `0.0.0.0` in `config.yml` (`host: 0.0.0.0:25565`).
In the proxy `config.yml`, set backend server addresses to `127.0.0.1`.
For example:
```yaml
servers:
hub:
motd: 'Hub Server'
address: 127.0.0.1:25566
restricted: false
servers:
hub:
motd: 'Hub Server'
address: 127.0.0.1:25566
restricted: false
```
**Policies**
We aim with this guide to have a **DROP Policy** on INPUT and FORWARD chains.
By defaults these chains policies are on ACCEPT, meaning that **all the connections** towards every port are accepted.
Changing the policies to DROP, we will only grant access to the ports we want and so to the services we want.
**Policies**
This guide uses a `DROP` policy on the `INPUT` and `FORWARD` chains.
By default, these chain policies are usually set to `ACCEPT`, which means incoming traffic is allowed unless a rule says otherwise.
After changing the policy to `DROP`, only traffic that matches the rules you add will be accepted.

**Ports**
I assume that you have only installed SSH and Minecraft Servers on your server so we will open only the necessary ports to let these services work without problems.
Remember to respect the order of the rules and commands!
**Ports**
I assume that you only want to expose SSH and the required service ports on your server, so we will open only the ports that are needed.
The order of the rules matters because `iptables` evaluates chains from top to bottom, so add them in the same order shown below.

`$ sudo iptables -A INPUT -i lo -j ACCEPT`
*( The loopback interface is also used if you configure your application server to connect to a database server with a localhost address. As such, you will want to be sure that your firewall is allowing these connections.)*
*(The loopback interface is also used if your application server connects to a database or another local service through `localhost`, so it should usually be allowed.)*

**READ CAREFULLY**
```
To allow return traffic for outgoing connections initiated by the server itself we can add this rule but if
you are having problems with DDoS attack filling quickly the
conntrack table, you can switch to option number 2.
Option 1:
$ sudo iptables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
Option 2:
To allow return traffic for outgoing connections initiated by the server itself, we can add this rule, but if
you are having problems with a DDoS attack quickly filling the conntrack table,
you can switch to option number 2.

Option 1:
$ sudo iptables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

Option 2:
$ sudo cat /proc/sys/net/ipv4/ip_local_port_range
This will prompt the kernel range ports that we have to allow to let the kernel works without problems.
Note please: `A1` is the First Number, and `A2` is the Second Number.
This will show the kernel port range that we have to allow to let the kernel work without problems.
Note: `A1` is the first number, and `A2` is the second number.

$ sudo iptables -A INPUT -p tcp -m tcp --dport A1:A2 -j ACCEPT
$ sudo iptables -A INPUT -p udp -m udp --dport A1:A2 -j ACCEPT
(Replace A1 and A2 with the ports numbers displayed with the cat command executed above.)
(Replace `A1` and `A2` with the port numbers displayed by the `cat` command above.)
```

`$ sudo iptables -A INPUT -m conntrack --ctstate INVALID -j DROP`
*(Sometimes it can be useful to log this type of packet but often it is fine to drop them.)*
*(Sometimes it can be useful to log this type of packet, but dropping it is often fine.)*

`$ sudo iptables -A INPUT -p tcp -m tcp --dport 22 -j ACCEPT`
*(This rule will allow the traffic towards SSH, change the port from 22 to another if you don't use 22)*


*(This rule allows traffic to SSH. Change `22` if you use a different SSH port.)*

`$ sudo iptables -A INPUT -p tcp -m tcp --dport 25565 -j ACCEPT`
*(Replace if necessary 25565 with the port used by the Proxy server)*
It is usually a good practice to limit per second the connections per IP, so we can limit and reduce some bot attacks specifically some very **poor designed** bot attacks.
`$ sudo iptables -A INPUT -p tcp --syn --dport 25565 -m connlimit --connlimit-above 3 -j REJECT`
*(This rule will limit to 3connections/sec from the same IP towards port 25565)*
If you want to rate-limit new connection attempts per source IP, use `hashlimit` rather than `connlimit`.
`$ sudo iptables -A INPUT -p tcp --syn --dport 25565 -m hashlimit --hashlimit-name input_rate --hashlimit-mode srcip --hashlimit-upto 3/second --hashlimit-burst 3 -j ACCEPT`
`$ sudo iptables -A INPUT -p tcp --syn --dport 25565 -j DROP`
*(This example allows up to 3 new connection attempts per second per source IP, with a burst of 3.)*

`$ sudo iptables -A INPUT -p icmp -m icmp --icmp-type 8 -m limit --limit 1/sec --limit-burst 1 -j ACCEPT`
*(OPTIONAL - This rule will allow icmp requests with a limit of 1/sec)*
*(OPTIONAL - This rule will allow ICMP echo requests with a limit of 1/sec.)*
```
$ sudo iptables -P INPUT DROP
$ sudo iptables -P FORWARD DROP
```
*(As stated above, we have now configured our firewall to accept connections only towards ports/services we want.
Changing the policy to DROP, will DROP all the connections that we have not defined.)*

`$ netfilter-persistent save`
*(This command is used to save the rules of IPTables and make them persistent, otherwise after a server rebooting, the rules will have been resetted)*
*(As stated above, we have now configured the firewall to accept connections only to the ports and services we want.
Changing the policy to `DROP` will drop all connections that are not explicitly allowed.)*

**IPv6 Example**
If IPv6 is enabled on your host, apply an equivalent `ip6tables` ruleset as well.
This example keeps stateful traffic, SSH, the service port, and essential ICMPv6 traffic working:

```bash
$ sudo ip6tables -A INPUT -i lo -j ACCEPT
$ sudo ip6tables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
$ sudo ip6tables -A INPUT -m conntrack --ctstate INVALID -j DROP

$ sudo ip6tables -A INPUT -p icmpv6 --icmpv6-type destination-unreachable -j ACCEPT
$ sudo ip6tables -A INPUT -p icmpv6 --icmpv6-type packet-too-big -j ACCEPT
$ sudo ip6tables -A INPUT -p icmpv6 --icmpv6-type time-exceeded -j ACCEPT
$ sudo ip6tables -A INPUT -p icmpv6 --icmpv6-type parameter-problem -j ACCEPT
$ sudo ip6tables -A INPUT -p icmpv6 --icmpv6-type router-solicitation -j ACCEPT
$ sudo ip6tables -A INPUT -p icmpv6 --icmpv6-type router-advertisement -j ACCEPT
$ sudo ip6tables -A INPUT -p icmpv6 --icmpv6-type neighbour-solicitation -j ACCEPT
$ sudo ip6tables -A INPUT -p icmpv6 --icmpv6-type neighbour-advertisement -j ACCEPT

$ sudo ip6tables -A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
$ sudo ip6tables -A INPUT -p tcp --syn --dport 25565 -m hashlimit --hashlimit-name input_rate_v6 --hashlimit-mode srcip --hashlimit-upto 3/second --hashlimit-burst 3 -j ACCEPT
$ sudo ip6tables -A INPUT -p tcp --syn --dport 25565 -j DROP

$ sudo ip6tables -A INPUT -p icmpv6 --icmpv6-type echo-request -m limit --limit 1/sec --limit-burst 1 -j ACCEPT

$ sudo ip6tables -P INPUT DROP
$ sudo ip6tables -P FORWARD DROP
```
*(ICMPv6 is more important to IPv6 operation than ICMP is to IPv4, so do not treat it as optional in the same way.)*

`$ sudo netfilter-persistent save`
*(This command saves the current `iptables` and `ip6tables` rules and makes them persistent so they are restored after a reboot.)*