How to set up a firewall on your Arch Linux VPS

Updated 18 Nov 2013

iptables * Tables, chains and rules * Getting started



A firewall is a software- or hardware-based network security system that controls the incoming and outgoing network traffic by analyzing the data packets and determining whether they should be allowed through or not, based on a rule set.

iptables is a powerful firewall built into Linux. It can be configured directly, or by using one of many available front ends. These front ends are supposed to make administering firewalls a breeze, but most, if not all, utilize iptables as their back end anyway. (iptables is itself a Linux user-space front end for netfilter, the kernel-space back end.) It's very important to understand exactly what you are doing when configuring your firewall as this will affect all incoming and outgoing traffic to your server. You should learn to configure the iptables rule set directly and not rely on any front end software.


Tables, chains and rules

Tables are areas where a chain of rules can apply. There are five pre-defined tables in iptables. Tables contain chains, which are lists of rules to be followed in order. Chains may be built-in or user-defined.

With the iptables command you can configure the tables of the IPv4 Linux kernel packet filter. The only table of concern right now is called filter. This table is always used by default (i.e. when you are not using the parameter -t with the iptables command). The filter table contains three built-in chains: INPUT, OUTPUT and FORWARD.

Each chain contains a list of rules and each rule specifies what to do with a packet that matches the criteria of this rule. Each packet will be checked against the first rule of the list. If it doesn’t match the criteria it will be checked against the second, and so on until it reaches the end of the list or it matches the criteria of a rule. Only the first rule that matches the current request applies, so it's important to get the order right.


Getting started

List the current rule set using this command:

sudo iptables -L

You should get the following output:

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 policy of all three chains is currently to ACCEPT all traffic with no exceptions. In other words, not much in the way of firewalling is being done. You can remedy this by defining policies and creating rules, remembering that the order in which you create rules is very important.

Unless you want your VPS to function as a router, there is no need to write a rule set for the FORWARD chain. Simply change the default policy (using option -P) on the FORWARD chain from ACCEPT to DROP all traffic.

sudo iptables -P FORWARD DROP

In most setups it is reasonable to assume that outbound traffic generated by your server is clean. You can leave the OUTPUT chain with ACCEPT as the default policy.


Standard rules

The INPUT chain however will require specific rules depending on your requirements. There are some standard rules that you should implement first. Configure your first rule on the INPUT chain:

sudo iptables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

This rule tells iptables to immediately allow packets from existing or related connections. This is a pretty powerful shortcut in that once an approved, accepted connection is up, the process need go no further than this first rule. iptables therefore does not have to put every packet from every host through the rule set every time. Here is a breakdown of the command:

-A INPUT means append to the INPUT chain.

-m conntrack tells iptables to match on the state that is defined directly afterwards by --ctstate as RELATED or ESTABLISHED. This means only sockets that are related to existing connections or sockets that already exist.

j stands for "jump to target". This specifies what needs to happen to the packet that matches this firewall rule. Possible values are ACCEPT, DROP, QUEUE, RETURN or send to another user-defined chain.

A second standard rule is to allow all packets through that come from the localhost interface, lo. This is so the machine can talk to itself, which it does a lot. Append this rule to iptables with the command:

sudo iptables -A INPUT -i lo -j ACCEPT

-i is for "input interface".

Indicates the interface through which the incoming packets are coming through the INPUT, FORWARD, and PREROUTING chain. For example: -i eth0 indicates that this rule should consider the incoming packets coming through the interface eth0. If you don’t specify -i option, all available interfaces on the system will be considered for input packets.

The next rule you need is to allow SSH connections, so that you can to continue to remotely administer the server. This is an important step that you must get right if you don't want to get yourself locked out unexpectedly.

Remember that SSH isn't always on the standard port 22. If you changed the SSH port to 3456 as per the instructions here, then you must allow traffic through that port, otherwise you will find yourself locked out of your server as soon as you enable the firewall.

-A INPUT -p tcp --dport 3456 -m state --state NEW,ESTABLISHED -j ACCEPT

A fourth standard rule to implement is to allow ping requests to your VPS.

sudo iptables -A INPUT -p icmp --icmp-type echo-request -m limit --limit 10/second -j ACCEPT

Finally, drop everything else:


Because the default policy of the INPUT chain is ACCEPT, this rule is required so that iptables drops any packets that do not match any of the preceding rules. Make sure that this is the last rule in the chain.


Save the rule set to file

Before going any further, save the rule set to a file called iptables.rules or something of your own choosing. The following command unfortunately won't work (unless you're logged in as the root user, which you shouldn't be):

sudo iptables-save > /etc/iptables/iptables.rules

The nature of sudo is that it runs the iptables-save command as root, but then pipes the result as your regular user to the /etc/iptables.rules file. However, your regular user shouldn't have permission to create a new file in the restricted /etc directory. So try this instead:

sudo bash -c "iptables-save > /etc/iptables/iptables.rules"

The file iptables.rules has now been created inside the /etc/iptables directory and contains the rule set you configured above. Subsequent configuration can be done using a text editor:

sudo nano /etc/iptables/iptables.rules

Save any changes and exit, then apply the changes to iptables:

sudo iptables-restore < /etc/iptables/iptables.rules


Application-specific rules

Here are some rules you may want to use:

-A INPUT -p tcp --dport 80 -j ACCEPT
-A INPUT -p tcp --dport 443 -j ACCEPT
#SMTP and Submission ports for STARTTLS
-A INPUT -p tcp --dport 25 -j ACCEPT
#-A INPUT -p tcp --dport 465 -j ACCEPT
-A INPUT -p tcp --dport 587 -j ACCEPT
#POP3 no, POP3S yes
#-A INPUT -p tcp --dport 110 -j ACCEPT
-A INPUT -p tcp --dport 995 -j ACCEPT
#IMAP no, IMAPS yes
#-A INPUT -p tcp --dport 143 -j ACCEPT
-A INPUT -p tcp --dport 993 -j ACCEPT
#ping is ok
-A INPUT -p icmp -m icmp --icmp-type 8 -m limit --limit 10/sec -j ACCEPT
-A INPUT -p udp --sport 53 --dport 1024:65535 -j ACCEPT


#block null packets
-A INPUT -p tcp --tcp-flags ALL NONE -j DROP
#reject SYN-flood attacks
-A INPUT -p tcp ! --syn -m conntrack --ctstate NEW -j DROP
#reject XMAS
-A INPUT -p tcp --tcp-flags ALL ALL -j DROP

-p is for protocol Indicates the protocol for the rule. Possible values are tcp, udp, icmp Use “all” to allow all protocols. When you don’t specify -p, by default “all” protocols will be used. It is not a good practice to use “all”, and always specify a protocol. Use either the name (for example: tcp), or the number (for example: 6 for tcp) for protocol. /etc/protocols file contains all allowed protocol name and number. -s is for source Indicates the source of the packet. This can be ip address, or network address, or hostname For example: -s indicates a specific ip address For network mask use /mask. For example: “-s″ represents a network mask of for that network. This matches 192.168.1.x network. When you don’t specify a source, it matches all source. -d is for destination Indicates the destination of the packet. This is same as “-s” (except this represents destination host, or ip-address, or network) -j is target j stands for “jump to target” This specifies what needs to happen to the packet that matches this firewall rule. Possible values are ACCEPT, DROP, QUEUE, RETURN You can also specify other user defined chain as target value. –sport is for source port (for -p tcp, or -p udp) By default all source ports are matched. You can specify either the port number or the name. For example, to use SSH port in your firewall rule, use either “–sport 22″ or “–sport ssh”. /etc/services file contains all allowed port name and number. Using port number in the rule is better (for performance) than using port name. To match range of ports, use colon. For example, 22:100 matches port number from 22 until 100. –dport is for destination port (for -p tcp, or -p udp) Everything is same as –sport, except this is for destination ports. INPUT and dport combination will be applicable to packets destined for port 443 of your system. INPUT and sport combination stands for those packets arriving to the system and originating from port 443 of remote system. OUTPUT and dport combination stands for those packets leaving the system and destined for port 443 of remote system. OUTPUT and sport combination will be applicable for those packets leaving port 443 of your system. –tcp-flags is for TCP flags (for -p tcp) This can contain multiple values separated by comma. Possible values are: SYN, ACK, FIN, RST, URG, PSH. You can also use ALL or NONE –icmp-type is for ICMP Type (for -p icmp) When you use icmp protocol “-p icmp”, you can also specify the ICMP type using “–icmp-type” parameter. For example: use “–icmp-type 0″ for “Echo Reply”, and “–icmp-type 8″ for “Echo”.