Setting up a home firewall with iptables on a Raspberry Pi

Firewall your home network with a Raspberry Pi

Bees on a hive, connected by dots
Image by :

Subscribe now

Get the highlights in your inbox every week.

Although the Raspberry Pi 3 was recently announced, the Raspberry Pi 2 still has plenty of life and is more than suitable for many interesting and useful tasks.

I have a few Raspberry Pis sitting around that I've been exploring for other interesting projects, one of which is the possibility of replacing a very old single-core 64-bit Intel rackmount server that I use for the primary firewall and router on the edge of my network. But before I disrupt the main firewall and gateway for my network, I wanted to test the Pi a bit and see just what it would take to make this happen.

Replacing a tower

I also have a dual-core Intel tower that I use as a firewall and side door to my network. This computer is extreme overkill for that task, and I can definitely use it in a more appropriate role. Because this computer provides non-critical access to my network, I decided to replace it with a Raspberry Pi 2 Model B as a test.

Power supply

I used Raspberry Pi 2 Model B, but a Raspberry Pi 3 should also work. I powered the Pi from a spare Kindle 5V 1.8A USB power block on a standard household extension cord that I plugged into a UPS to provide consistent power. I used a very short USB to micro-USB cable from the power block to the power connector on the Pi.

KVM switch

I have several of my infrastructure hosts connected to a 16-port KVM switch with VGA and PS/2 inputs. I wanted to use the KVM for the Pi as well. I connected the keyboard and mouse input of the KVM to the Pi with a USB to PS/2 adapter cable. The USB end plugs into the Pi and the connectors from the KVM switch cable plug into the PS/2 connectors on the adapter. I have found in the past that some brands of the USB to PS/2 adapter don't work well.

For the video connection I initially used an HDMI to VGA adapter that is a single, solid unit. This device produced a lot of heat, much of which was transmitted into the Pi through the HDMI connector. I later substituted the single unit for an adapter that has a short length of cable between the HDMI connector and the VGA converter, plus a connector unit that produces and transmits significantly less heat.

Installing CentOS

I use CentOS on my other infrastructure servers, so I wanted to use it on the Pi too. Using my main Linux workstation, I downloaded CentOS Userland 7 32-bit ARM distribution for the Pi 2 from the CentOS wiki site, which contains images for other small board computers as well. If you are using the Raspberry Pi 3, you should use that image instead.

Note that the image name may change as newer images are made available. You should always use the most recent image. I uncompressed the downloaded xz image file (using unxz), and then used the dd command to install the image onto an 8GB microSD card.

dd if=CentOS-Userland-7-armv7hl-Minimal-1511-RaspberryPi2.img of=/dev/sdx

Be sure to specify the correct location of your microSD drive on your machine.

No additional steps are required to make the microSD card bootable. I inserted the card into the microSD card slot on the Pi board. I then plugged the micro-USB connector from the power supply into the power connector on the Pi to boot up to a command line interface login prompt.

Initial configuration

I logged in as root using the default password of "centos" (without the quotes) and immediately changed the root password. I changed the hostname in /etc/hostname and followed the instructions in /root/README to expand the root partition to fill all the available space on the microSD card. This included a reboot.

At this point, I connected the on-board network adapter to my internal network so I could install more software and test the network functionality. I installed various utilities that I find useful, including which, screen, vim, rwhois, mlocate, Midnight Commander (mc), mailx, bind-utils, chrony, and wget.

Some other favorites of mine, such as atop and htop, are not yet available from the CentOS repository. I did not install these all at one time because I was unaware of which ones were missing. Instead, I had to run into the problem that a needed tool was not installed and then install it as I progressed through the other steps of this process. Hopefully, this list will make things a bit easier for you. Of course, you may use some tools that I don't, and they may be missing too.

I use SSH keys for logins from my network, so I copied the SSH public key from my primary internal workstation to the Pi using ssh-copy-id.

A second network interface

Because this Pi is to be used as a firewall, I needed another network adapter. After taking eth0 down, I added an ASIX AX88178 USB Gigabit Ethernet dongle. I disconnected my internal network from the on-board network adapter and connected it to the dongle. I configured the dongle as eth1 with a static address on my internal network and I configured the on-board Ethernet with a static external address and connected it to my ISP's router. Be sure to use the HWADDR= line in the interface configuration files to set the MAC address that the configuration file pertains to. I also added the gateway IP address and at least two name servers to the interface configuration file for the inside adapter.

I brought both network adapters up and used ifconfig and a couple ping commands to verify that the network adapters were bound to the correct IP addresses and working properly. Now I could login to the Pi from a terminal session on my main workstation and continue working from there.

Updates and more configuration

It was now time to install all updates and reboot—which I did. I do find it interesting that both current versions of CentOS for ARM use things like firewalld and systemd, but still use yum instead of dnf for high-level package management.

I have some aliases and startup commands that I always add to my environment when I install a new host. These commands can be added to /etc/bashrc, or better yet, as a separate file, /etc/profile.d/ Any file in /etc/profile.d with a .sh filename extension is sourced by /etc/bashrc during login.

Date and time

This version of CentOS does not have any type of time synchronization installed by default, so I installed chrony and configured chrony.conf with my local NTP time server. I started chronyd, and configured systemctl to start chronyd on boot. I also set the /etc/localtime symlink to point to the desired timezone data file.


The new firewalld is really overkill for my environment, so I installed iptables-services and iptables-utils. I configured a default /etc/sysconfig/iptables file, then, after turning down the external network connection, I stopped firewalld and configured systemd to not start it on boot. I started iptables and configured systemd to start it on boot. I then brought the external network connection back up.


Once you reach this point, the Pi is fully functional as a firewall and side door.

It would be easy to take two more steps and make it into a router. First, set the contents of the file /proc/sys/net/ipv4/ip_forward to "1" and then add or set the following line in /etc/sysctl.conf to "net.ipv4.ip_forward = 1", which makes your computer a router. Then add appropriate lines for source NATing and forwarding to the iptables firewall.

I just received three new Raspberry Pi 3 computers yesterday. I already have one set up with the CentOS-Userland-7-armv7hl-Minimal-1602-RaspberryPi3.img image and will finish configuring it over the next few days to become my primary firewall and router.


IPTables Rules

One person has asked in the comments to see the IPTables rules I used for this project, and I suspect that others are interested as well, so here they are. It is a fairly standard minimal set that only allows SSH inbound.

# Generated by iptables-save v1.4.16.2 on Thu Feb 21 14:51:28 2013
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -i eth0 -j ACCEPT
-A INPUT -p tcp -m conntrack --ctstate NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
# Completed on Thu Feb 21 14:51:28 2013


About the author

David Both - David Both is an Open Source Software and GNU/Linux advocate, trainer, writer, and speaker who lives in Raleigh North Carolina. He is a strong proponent of and evangelist for the "Linux Philosophy." David has been in the IT industry for nearly 50 years. He has taught RHCE classes for Red Hat and has worked at MCI Worldcom, Cisco, and the State of North Carolina. He has been working with Linux and Open Source Software for over 20 years. David prefers to purchase the components and build his...