Basic firewalling on your VPS

By default we do not filter traffic. However, if you have a VPS, you maybe want to block unwanted traffic or you would like to only allow traffic from specific sources. This blog explains a bit the basics of firewall configuration on a Greenhost VPS. This document assumes a Debian or Ubuntu based system, however, the basics are similar on all Linux based operating systems

What is a firewall

A firewall controls traffic flowing into, leaving or going through your VPS. This manual will discuss only traffic going into your VPS and does not focus on filtering outgoing or forwarding/routing traffic.

If someone is requesting a resource on your VPS (for example, visiting a website), the visitor will send a request to your server on a specific port (for web this is usually on port 80 or 443). Your server will send back the requested data from this port to the client IP. You can use a firewall to block (or allow) traffic based on specific rules. This way, you can control which services are available, not available, or only available for certain IP-addresses.

The INPUT chain

Linux by default has three chains in it's firewall. The INPUT, OUTPUT and FORWARD. The OUTPUT and FORWARD chain are not discussed in this document.

The INPUT chain controls traffic coming from any destination towards your server. This is the most important chain to configure correctly. It is important to understand that if your server is requesting data (for example when it is downloading an update, or doing a DNS query), the INPUT chain is also involved, as depending on the request, it is likely that you will afterwards receive data from the remote server.

The OUTPUT chain controls traffic leaving your system. Most people do not add limitation to this, as they 'trust' the applications and users on the system. It can however be interesting to block certain outgoing traffic for an extra secure setup.

The FORWARD chain controls traffic which is routed though your VPS. This can be relevant if, for example, your VPS acts like a VPN endpoint or if it is doing traffic routing

Using iptables-persistent to survive reboots

The firewall is configured with the tool iptables. However, if you make changes with this tool, those changes do not persist after a reboot. So the iptables just adjust the behaviour on a running system.
To make sure the same rules are applied after a reboot, the tool iptables-persistent can be used. This will store your configuration in some files and loads the rules again at boot time

To start, make sure all relevant software is installed

1
2
sudo apt-get update
sudo apt-get install iptables-persistent iptables

Listing firewall content

The possibilities for iptables are quite extensive, but the basic set of commands is not very complex. If you need a more complex setup use the command man iptables or iptables -help or you favourite search engine to find examples and additional documentation.

The iptables -L command (-L stands for list) will list the current configuration. Below configuration shows an empty list. Listed are the three chains, and their contents.

1
2
3
4
5
6
7
8
9
$ sudo iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination

Chain FORWARD (policy ACCEPT)
target prot opt source destination

Chain OUTPUT (policy ACCEPT)
target prot opt source destination

The Chain INPUT (policy ACCEPT), is a header to indicate that below that line the contents of the INPUT chain will follow. The policy ACCEPT, means that the default policy is to accept traffic. Per chain it is possible to set a default ACCEPT or DROP policy.

With other words, above firewall will accept all traffic on on chains.

Configuring a basic firewall

To add definitions, iptables -A {CHAIN} can be used. This will add a rule to a specific chain. The order of rules in the chain is relevant, as the Linux will try to match every rule until it found a match, or is at the end of the list (and in that case the default policy will be applied). If you are not familiar with iptables or a firewall in general, we advise you to start with at least two basic rules and some ACCEPT rules on ports on the INPUT chain. When you get more acquainted, more complex setups can be created.

The first advices rule to add is:

1
sudo iptables -A INPUT -i lo -j ACCEPT

This will add (-A) a rule to the INPUT chain. The rule itself is -i lo , which means, match traffic coming from interface lo, -j ACCEPT, this means, ACCEPT the traffic if it matches the rule (it actually means, jump-to ACCEPT, by default you can jump to ACCEPT, REJECT or DROP. Jumping to other places can be useful in a more complex setup and is out of the scope of this guide)

The lo interface is the loopback interface. It actually means that all traffic from the system itself is accepted. This rule is handy to do run in unexpected behaviour on the system itself.

The second rule we advise to add is:

1
sudo iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT

This looks a bit more complex, but it is a very important rule. It tells the firewall, to accept traffic from already related or established connections. To clarify: when the VPS is requesting data from a remote server (for example downloading an update from some place on the internet), this remote server will respond with the requested data. However, as that data is coming from a remote place to the VPS, this ends up in the INPUT chain. As we requested the data ourself, we want to accept this. This rule will tell the firewall to keep track of connections, and if an outgoing connection results in traffic coming in, this is accepted (this is called "connection tracking", or "conntrack" for short).

Without this rule, unexpected behaviour can happen. And we strongly advise to add this rule, unless you know what you are doing.

At this stage some basic fire-walling is in place. But we didn't allow for any specific traffic yet. Let assume you want to offer 3 services on your VPS,

  • HTTP, this is running on port 80, TCP protocol
  • HTTPS, this is running on port 443, TCP protocol
  • SSH, this is running on port 22, TCP protocol

This will basically allow us to run a web server, and access the VPS over SSH.

To allow those three types of traffic, we can add those rules:

1
2
3
sudo iptables -A INPUT -m state --state NEW -p tcp --dport 80 -j ACCEPT
sudo iptables -A INPUT -m state --state NEW -p tcp --dport 443 -j ACCEPT
sudo iptables -A INPUT -m state --state NEW -p tcp --dport 22 -j ACCEPT

Well, once this is completed, let's list the whole firewall:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ sudo iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
ACCEPT all -- anywhere anywhere
ACCEPT all -- anywhere anywhere state RELATED,ESTABLISHED

ACCEPT tcp -- anywhere anywhere state NEW tcp dpt:http

ACCEPT tcp -- anywhere anywhere state NEW tcp dpt:https
ACCEPT tcp -- anywhere anywhere state NEW tcp dpt:ssh

Chain FORWARD (policy ACCEPT)
target prot opt source destination

Chain OUTPUT (policy ACCEPT)
target prot opt source destination

As seen above, 5 rules are added to the INPUT chain. Most are clear, but the first one is a bit vague, it state ACCEPT all -- anywhere anywhere, so it looks like all traffic is accepted. However, this not true, this is the first rule which is added, and only applies to "interface lo", the loopback interface. iptables -L only shows a compact version. So sometimes it is useful to be a bit more verbose and request additional information. This can be done with iptables -L -v (-v for verbose)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ sudo iptables -L -v

Chain INPUT (policy ACCEPT 9 packets, 765 bytes)
pkts bytes target prot opt in out source destination
0 0 ACCEPT all -- lo any anywhere anywhere
4 561 ACCEPT all -- any any anywhere anywhere state RELATED,ESTABLISHED

1 40 ACCEPT tcp -- any any anywhere anywhere state NEW tcp dpt:http
0 0 ACCEPT tcp -- any any anywhere anywhere state NEW tcp dpt:https
0 0 ACCEPT tcp -- any any anywhere anywhere state NEW tcp dpt:ssh

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination

Chain OUTPUT (policy ACCEPT 56 packets, 7864 bytes)
pkts bytes target prot opt in out source destinatio

Now the interface is shown (lo) in the first rule. OK! The basic firewall is complete, but we forgot one very important thing. We only added ACCEPT rules, so only stuff we want to be able. However, the default policy of the INPUT chain is also ACCEPT, so this set has no effect. We have to change the default policy, so that all other traffic is denied (or dropped). We can do this as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ sudo iptables -P INPUT DROP

$ sudo iptables -L -v

Chain INPUT (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
0 0 ACCEPT all -- lo any anywhere anywhere
6 831 ACCEPT all -- any any anywhere anywhere state RELATED,ESTABLISHED
1 40 ACCEPT tcp -- any any anywhere anywhere state NEW tcp dpt:http
0 0 ACCEPT tcp -- any any anywhere anywhere state NEW tcp dpt:https
0 0 ACCEPT tcp -- any any anywhere anywhere state NEW tcp dpt:ssh

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination

Chain OUTPUT (policy ACCEPT 23 packets, 3336 bytes)
pkts bytes target prot opt in out source destination

If we are happy, and you can still access your system as expected (please try to logout and login again), we can save our rule set, so it will survive a reboot.

1
sudo netfilter-persistent save

This will save the iptables rule set, and store it in /etc/iptables/rules.v4 (and rules.v6 for IPv6).

We hope this blog is helpful to understand the very basics of firewalling on your VPS. As mentioned before, many many people have written a lot about iptables, so searching the Internet will quickly get you further in mastering this powerful tool.