Securing your Ubuntu/Debian based VPS using IPTABLES/Netfilter firewall

securing-your-ubuntu-based-vps-using-iptables-firewallIn the following article we will show you how you can secure and protect your Ubuntu or Debian based virtual server using a firewall application, called iptables.

What is iptables?

It is is a user space application program that allows a system administrator to configure the tables provided by the Linux kernel firewall (implemented as different Netfilter modules) and the chains and rules it stores.

In order to keep down the number of attempted break-ins and to filter the ports opened on your virtual server, it is necessary to properly configure your firewall.

To make the management of your server’s firewall rules easier, we will provide a simple shell script that will help with the management of the firewall rules. Basically, whenever you need to change your firewall rules, you would use this script to add/remove the desired rule(s).


Before wrapping the rules in a script, let’s split it in sections so you can know the design of the firewall and what rules will be in place.


The firewall rules can be flushed using the following commands:

## iptables --flush
## iptables --delete-chain
## iptables --table nat --flush
## iptables --table nat --delete-chain


You have to know what services you have exposed to the public so you can set appropriate rules for them. One way to find what services are listening on what ports is to use the netstat or ss commands as in:

## netstat -tunlp


## ss -tunlp

for example, we are using one of our Ubuntu 12.04 LTS virtual servers and the following is the output of the netstat command:

## netstat -tunlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0*               LISTEN      296/mysqld
tcp        0      0   *               LISTEN      449/sendmail: MTA:
tcp        0      0   *               LISTEN      261/dovecot
tcp        0      0   *               LISTEN      261/dovecot
tcp        0      0    *               LISTEN      590/apache2
tcp        0      0*               LISTEN      353/named
tcp        0      0  *               LISTEN      353/named
tcp        0      0    *               LISTEN      173/vsftpd
tcp        0      0  *               LISTEN      630/sshd
tcp        0      0    *               LISTEN      449/sendmail: MTA:
tcp        0      0 *               LISTEN      353/named
tcp        0      0   *               LISTEN      590/apache2
tcp        0      0   *               LISTEN      261/dovecot
tcp        0      0   *               LISTEN      261/dovecot
udp        0      0*                           353/named
udp        0      0  *                           353/named

so this means that we have the following ports opened to the public:

  • 25 (smtp)
  • 587 (smtp submission)
  • 110 (pop3)
  • 143 (imap)
  • 993 (imap ssl)
  • 995 (pop3 ssl)
  • 80 (http)
  • 443 (https)
  • 53 (dns)
  • 21 (ftp)
  • 5622 (ssh)


ok, so now we can set-up our firewall’s policies to DROP everything in the INPUT and FORWARD chains and allow traffic in the OUTPUT chain.

the default table filter contains three built-in chain:

  1. Inbound traffic addressed to the machine itself hits the INPUT chain.
  2. Outbound, locally-generated traffic hits the OUTPUT chain.
  3. Routed traffic which should not be delivered locally hits the FORWARD chain.

check man 8 iptables for more information on this

default policies can be applied using the following commands:

## iptables -P INPUT DROP # <- do not run this over ssh as it will lock you out
## iptables -P FORWARD DROP
## iptables -P OUTPUT ACCEPT


Next thing to do is to actually set-up the firewall rules for our services. As the INPUT chain is DROPPED, we will need to white-list the services which are listening on public ports, so:

the first thing is to enable free use of the loopback interfaces, to ensure all TCP sessions should begin with SYN and to allow established and related packets:

## iptables -A INPUT -i lo -j ACCEPT
## iptables -A OUTPUT -o lo -j ACCEPT
## iptables -A INPUT -p tcp ! --syn -m state --state NEW -j DROP
## iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

next, let’s open our service ports by using firewall rules like:

### SSH
## iptables -A INPUT -p tcp --dport 5622  -m state --state NEW -j ACCEPT

### HTTP
## iptables -A INPUT -p tcp --dport 80  -m state --state NEW -j ACCEPT

### SMTP
## iptables -A INPUT -p tcp -m state --state NEW -m tcp --dport 25 -j ACCEPT

and so on. Once all the services are white-listed, it is a good idea to allow ICMP packets and to LOG and DROP everything else in the INPUT chain.

## iptables -A INPUT -p ICMP --icmp-type 8 -j ACCEPT
## iptables -A INPUT -j LOG
## iptables -A INPUT -j DROP


Firewall rules are not persistent by default, which means they will be lost if you reboot your virtual server for example. To save your current firewall in /etc/fwall.rules you would use something like:

## iptables-save > /etc/fwall.rules

and to restore the saved rules, you would use something like:

## iptables-restore -c /etc/fwall.rules

to make the rules automatically restored on system start-up, you would either have to use a package named iptables-persistent or you can simply create a script in /etc/network/if-pre-up.d which will load the rules saved in /etc/fwall.rules, for example:

## vim /etc/network/if-pre-up.d/iptables

test -e /etc/fwall.rules && iptables-restore -c /etc/fwall.rules

## chmod +x /etc/network/if-pre-up.d/iptables


save the script in /usr/local/bin/fwall-rules and make it executable



echo " * flushing old rules"
${IPTABLES} --flush
${IPTABLES} --delete-chain
${IPTABLES} --table nat --flush
${IPTABLES} --table nat --delete-chain

echo " * setting default policies"

echo " * allowing loopback devices"

${IPTABLES} -A INPUT -p tcp ! --syn -m state --state NEW -j DROP

#echo " * BLACKLIST"

echo " * allowing ssh on port 5622"
${IPTABLES} -A INPUT -p tcp --dport 5622  -m state --state NEW -j ACCEPT

echo " * allowing ftp on port 21"
${IPTABLES} -A INPUT -p tcp --dport 21  -m state --state NEW -j ACCEPT

echo " * allowing dns on port 53 udp"
${IPTABLES} -A INPUT -p udp -m udp --dport 53 -j ACCEPT

echo " * allowing dns on port 53 tcp"
${IPTABLES} -A INPUT -p tcp -m tcp --dport 53 -j ACCEPT

echo " * allowing http on port 80"
${IPTABLES} -A INPUT -p tcp --dport 80  -m state --state NEW -j ACCEPT

echo " * allowing https on port 443"
${IPTABLES} -A INPUT -p tcp --dport 443 -m state --state NEW -j ACCEPT

echo " * allowing smtp on port 25"
${IPTABLES} -A INPUT -p tcp -m state --state NEW -m tcp --dport 25 -j ACCEPT

echo " * allowing submission on port 587"
${IPTABLES} -A INPUT -p tcp -m state --state NEW -m tcp --dport 587 -j ACCEPT

echo " * allowing imaps on port 993"
${IPTABLES} -A INPUT -p tcp -m state --state NEW -m tcp --dport 993 -j ACCEPT

echo " * allowing pop3s on port 995"
${IPTABLES} -A INPUT -p tcp -m state --state NEW -m tcp --dport 995 -j ACCEPT

echo " * allowing imap on port 143"
${IPTABLES} -A INPUT -p tcp -m state --state NEW -m tcp --dport 143 -j ACCEPT

echo " * allowing pop3 on port 110"
${IPTABLES} -A INPUT -p tcp -m state --state NEW -m tcp --dport 110 -j ACCEPT

echo " * allowing ping responses"
${IPTABLES} -A INPUT -p ICMP --icmp-type 8 -j ACCEPT

# DROP everything else and Log it

# Save settings
echo " * SAVING RULES"

if [[ -d /etc/network/if-pre-up.d ]]; then
    if [[ ! -f /etc/network/if-pre-up.d/iptables ]]; then
        echo -e "#!/bin/bash" > /etc/network/if-pre-up.d/iptables
        echo -e "test -e /etc/iptables.rules && iptables-restore -c /etc/iptables.rules" >> /etc/network/if-pre-up.d/iptables
        chmod +x /etc/network/if-pre-up.d/iptables

iptables-save > /etc/fwall.rules
iptables-restore -c /etc/fwall.rules
## chmod +x /usr/local/bin/fwall-rules

to activate the rules you’ve prepared in the script, just execute

## fwall-rules

from the command line. To add or remove a rule, you just need to to open the script, add or remove your desired rule, save and run it again, for example:

## fwall-rules
 * flushing old rules
 * setting default policies
 * allowing loopback devices
 * allowing ssh on port 5622
 * allowing ftp on port 21
 * allowing dns on port 53 udp
 * allowing dns on port 53 tcp
 * allowing http on port 80
 * allowing https on port 443
 * allowing smtp on port 25
 * allowing submission on port 587
 * allowing imaps on port 993
 * allowing pop3s on port 995
 * allowing imap on port 143
 * allowing pop3 on port 110
 * allowing ping responses

Of course you don’t have to do any of this if you use one of our Linux VPS hosting services, in which case you can simply ask our expert linux admins to do this for you. They are available 24×7 and will take care of your request immediately.

PS. If you liked this post please share it with your friends on the social networks using the buttons on the left or simply leave a reply below. Thanks.

Install PrestaShop on Debian Wheezy VPS with PHP-FPM and Nginx
How to install Elefant CMS on Ubuntu 16.04
How to install PrestaShop on an Ubuntu 14.04 VPS
  • Frank Wilde

    Do you know any options to use now that “state” isn’t available any longer under ubuntu 14.04?
    I cannot access or install conntrack there I ain’t got no kernel access and state isn’t available any longer for iptables.
    So what do?
    Fucking Linux. Now I remember why I moved to BSD…