← Back to blog

Secure your servers using iptables

| Linux

This article was published over 2 years ago. Some information may be outdated.

Secure your servers using iptables

iptables is a firewall utility for Linux that lets you define rules for incoming and outgoing connections. You can restrict traffic to specific ports like 80, 443, and 22, and drop everything else.

You can also allow or deny connections from specific IP addresses.

Installation

Install iptables on Ubuntu:

sudo apt-get install -y iptables iptables-persistent

By default, iptables rules live in RAM and are lost on reboot. The iptables-persistent package solves that (covered later).

Understanding the basics

iptables organizes rules into chains. Three chains exist by default:

  • INPUT: Traffic inbound to the server.
  • FORWARD: Traffic forwarded (routed) to other locations.
  • OUTPUT: Traffic outbound from the server.

To allow port 80, you append a rule to the INPUT chain telling iptables to accept traffic on that port.

List all current rules:

sudo iptables -L -v

Expected output on a fresh system:

Chain INPUT (policy ACCEPT 9 packets, 636 bytes)
 pkts bytes target     prot opt in     out     source               destination

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

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

No rules are defined yet. The default policy is ACCEPT for all chains.

iptables uses two policies:

  • ACCEPT: allow the connection.
  • DROP: silently discard the connection.

The default policy determines what happens when traffic matches no rules. If you have allowed ports 80, 443, and 22, and someone connects on port 8800, the default policy decides the outcome.

The default ACCEPT policy means any port is open unless explicitly blocked. That is insecure. Switching to DROP inverts the model: everything is blocked unless you explicitly allow it.

Avoid self-blocking

This is critical. If you change the default policy to DROP without first allowing established connections, you will be locked out of the server immediately.

If you persist those rules, there is no way to reconnect. Follow the commands in this post in order.

Allow established and related connections before doing anything else:

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

sudo iptables -A OUTPUT -m conntrack --ctstate ESTABLISHED -j ACCEPT

Your current SSH session (and any other active connections) will now survive policy changes.

Loopback Network

Allow loopback traffic so the server can communicate with itself on 127.0.0.1:

sudo iptables -A INPUT -i lo -j ACCEPT
sudo iptables -A OUTPUT -o lo -j ACCEPT

This is necessary for services running on the same machine -- MySQL, Redis, and anything else bound to localhost.

By default, MySQL uses 127.0.0.1 in the bind-address flag to determine where it listens for connections. Read more about bind-address here.

Breaking down the flags:

  • -A INPUT: append a rule to the INPUT chain.
  • -i lo: match the loopback network interface.
  • -j ACCEPT: accept the connection.

Allowing Specific Ports

Open the ports you actually need:

## Accept connections from port 22 (SSH)
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT

## Accept connections from port 80 (HTTP)
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT

## Accept connections from port 443 (HTTPS)
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT

You can also block specific IP addresses using the -s flag:

## Block an IP address
sudo iptables -A INPUT -s 210.10.85.65 -j DROP

Now that the necessary ports are open, drop everything else:

sudo iptables -A INPUT -j DROP

Persist the rules so they survive reboots:

sudo service netfilter-persistent save
sudo service netfilter-persistent restart

Flushing

Remove all rules from every chain:

sudo iptables -F INPUT
sudo iptables -F OUTPUT
sudo iptables -F FORWARD

Where to go from here?

For more on iptables, read: Iptables Essentials: Common Firewall Rules and Commands | DigitalOcean

Summary

  • Always allow established connections first -- changing the default policy to DROP without this step locks you out of the server permanently.
  • Switch the default policy to DROP so that only explicitly allowed ports are accessible, rather than blocking ports one by one.
  • Allow loopback traffic for services like MySQL and Redis that bind to 127.0.0.1.
  • Use iptables-persistent to save rules across reboots -- without it, your firewall configuration is lost on restart.
  • Order matters -- follow the sequence in this post to avoid self-blocking.
Share