The most popular post on my blog is how to set up the Ubuntu Server firewall via ufw, the Uncomplicated Firewall. I recommend UFW for any standard server, but you might want to move to something more advanced to expand your firewall knowledge, to set up a network gateway, router, or firewall, or to conform with other systems on your network. If UFW is for beginners, then Firehol is for intermediate sysadmins, or those wishing to run proxy servers and the like.

Before I started using ufw, I used to use Firehol to set up the iptables firewall. Firewall does the same thing that UFW does, and a lot more, but in a completely different way. That’s because Firehol is not just a script, but a language, for defining firewalls. You write your rules in a configuration file, and Firehol will convert them into iptables commands, and issue them at boot time or on demand. It can only create “drop/reject everything, allow explicitly” type firewalls, but luckily, that’s the most appropriate type of firewall to create most of the time.

Firehol is useful not only for standard file and web servers, but also for routers and gateways, and can set up rules for transparent proxies, NAT, and so on. Home users such as myself have a hardware router for that, and only need to set up firewalls on home servers as a defense-in-depth measure.

I think that Firehol is more flexible than ufw, can implement more advanced features such as transparent proxies better than ufw, but it is a little to a lot harder to set up. This tutorial covers how you would lock down a simple home server that you wish to access via the Internet, but not leave completely open to the outside world.

Installation

Install the firehol package.

$ sudo apt-get install firehol

Enabling Firehol to Start on Boot

Firehol must be enabled before the rules you define will go into effect. To enable it, you must edit a configuration file.

$ sudo nano /etc/default/firehol

The file will look like this after a clean install:

#To enable firehol at startup set START_FIREHOL=YES
START_FIREHOL=NO
#If you want to have firehol wait for an iface to be up add it here
WAIT_FOR_IFACE=""

Simply change the second line to

START_FIREHOL=YES

and save the file. That will enable the firewall upon reboot. What that means is that Firehol will run its bash scripts, generate iptables rules, and then the iptables will be activated. Firehol does not run continuously as a service.

If you wish to disable the firewall, be sure to edit this file again, and reset the START_FIREHOL variable to NO.

Configuring the Firewall Rules

The configuration file containing the firewall rules is located in /etc/firehol.conf. This is what the default configuration file looks like. It will set your server to block everything coming in, and accept everything going out.

#
# $Id: client-all.conf,v 1.2 2002/12/31 15:44:34 ktsaou Exp $
#
# This configuration file will allow all requests originating from the
# local machine to be send through all network interfaces.
#
# No requests are allowed to come from the network. The host will be
# completely stealthed! It will not respond to anything, and it will
# not be pingable, although it will be able to originate anything
# (even pings to other hosts).
#

version 5

# Accept all client traffic on any interface
interface any world
client all accept

You could edit this file and specify your own services, or you could auto-generate a configuration file. I will walk you through auto-generating a confguration file in the next section.

Bear in mind, though, that a fully-working firewall can be made with a configuration file as simple as this:

#!/sbin/firehol
version 5
interface any world
protection strong
server "ssh http samba webmin" allow
client all accept

If you are only running standard services, it’s best to edit the file manually. If you have custom services, or are curious about Firehol’s abilities, read on.

Auto-generating a Configuration File

Firehol can automatically generate a configuration file for you to get you started. The firehol helpme command identifies aany running services on your server and builds a configuration file that will allow all traffic between them, and block all traffic outside those parameters. After the file is generated, you are then expected to review and modify it, to ensure the rules are correct, prior to activating the firewall.

First, use the firehol helpme command to generate a configuration file and put it into the /tmp folder.

$ sudo firehol helpme > /tmp/firehol.conf

Then, review the automatically generated configuration file.

$ nano /tmp/firehol.conf

The automatically generated configuration file is pretty verbose. This is what mine looks like, for a server that runs SSH, Samba, Transmission, Dropbox, and Lighttpd web server (it could be Apache or any other web server, really).

Note that there are two interfaces set up: one for my LAN (10.0.0.0/24) and one for the Internet (i.e, anything outside my router’s subnet). When I reviewed it, I notice that the peer ports for my transmission-daemon service are not all mapped, just the one currently in use. Therefore, you definitely have to tweak this file to suit your needs.

#!/sbin/firehol
# : firehol.sh,v 1.273 2008/07/31 00:46:41 ktsaou Exp $
#
# This config will have the same effect as NO PROTECTION!
# Everything that found to be running, is allowed.
# YOU SHOULD NEVER USE THIS CONFIG AS-IS.
#
# Date: Fri May 14 10:43:37 EDT 2010 on host thor
#
# IMPORTANT:
# The TODOs bellow, are *YOUR* to-dos!
#

# INFO: Processing interface 'eth0'
# INFO: Processing IP 10.0.0.3 of interface 'eth0'
# INFO: Is 10.0.0.3 part of network 10.0.0.0/24? yes

# Interface No 1.
# The purpose of this interface is to control the traffic
# on the eth0 interface with IP 10.0.0.3 (net: "10.0.0.0/24").
# TODO: Change "interface1" to something with meaning to you.
# TODO: Check the optional rule parameters (src/dst).
# TODO: Remove 'dst 10.0.0.3' if this is dynamically assigned.
interface eth0 interface1 src "10.0.0.0/24" dst 10.0.0.3

# The default policy is DROP. You can be more polite with REJECT.
# Prefer to be polite on your own clients to prevent timeouts.
policy drop

# If you don't trust the clients behind eth0 (net "10.0.0.0/24"),
# add something like this.
# > protection strong

# Here are the services listening on eth0.
# TODO: Normally, you will have to remove those not needed.
client dhcp accept
server http accept
server ICMP accept
server ms_ds accept
server ntp accept
server samba accept
server ssh accept
server webmin accept

# The following eth0 services are not known by FireHOL:
# tcp/17500 tcp/20550 tcp/9091 udp/10000 udp/17500 udp/20550

# Custom service definitions for the above unknown services.
server custom if1_tcp_17500 tcp/17500 any accept
server custom if1_tcp_20550 tcp/20550 any accept
server custom if1_tcp_9091 tcp/9091 any accept
server custom if1_udp_10000 udp/10000 any accept
server custom if1_udp_17500 udp/17500 any accept
server custom if1_udp_20550 udp/20550 any accept

# The following means that this machine can REQUEST anything via eth0.
# TODO: On production servers, avoid this and allow only the
#       client services you really need.
client all accept

# INFO: Is 10.0.0.1  part of network 10.0.0.0/24? yes
# INFO: Default gateway 10.0.0.1  is part of network 10.0.0.0/24

# Interface No 2.
# The purpose of this interface is to control the traffic
# from/to unknown networks behind the default gateway 10.0.0.1 .
# TODO: Change "interface2" to something with meaning to you.
# TODO: Check the optional rule parameters (src/dst).
# TODO: Remove 'dst 10.0.0.3' if this is dynamically assigned.
interface eth0 interface2 src not "${UNROUTABLE_IPS} 10.0.0.0/24" dst 10.0.0.3

# The default policy is DROP. You can be more polite with REJECT.
# Prefer to be polite on your own clients to prevent timeouts.
policy drop

# If you don't trust the clients behind eth0 (net not "${UNROUTABLE_IPS} 10.0.0.0/24"),
# add something like this.
# > protection strong

# Here are the services listening on eth0.
# TODO: Normally, you will have to remove those not needed.
client dhcp accept
server http accept
server ICMP accept
server ms_ds accept
server ntp accept
server samba accept
server ssh accept
server webmin accept

# The following eth0 services are not known by FireHOL:
# tcp/17500 tcp/20550 tcp/9091 udp/10000 udp/17500 udp/20550

# Custom service definitions for the above unknown services.
server custom if2_tcp_17500 tcp/17500 any accept
server custom if2_tcp_20550 tcp/20550 any accept
server custom if2_tcp_9091 tcp/9091 any accept
server custom if2_udp_10000 udp/10000 any accept
server custom if2_udp_17500 udp/17500 any accept
server custom if2_udp_20550 udp/20550 any accept

# The following means that this machine can REQUEST anything via eth0.
# TODO: On production servers, avoid this and allow only the
#       client services you really need.
client all accept

# INFO: Processing interface 'wlan0'

# IMPORTANT:
# Ignoring interface 'wlan0' because does not have an IP or route.

# The above 2 interfaces were found active at this moment.
# Add more interfaces that can potentially be activated in the future.
# FireHOL will not complain if you setup a firewall on an interface that is
# not active when you activate the firewall.
# If you don't setup an interface, FireHOL will drop all traffic from or to
# this interface, if and when it becomes available.
# Also, if an interface name dynamically changes (i.e. ppp0 may become ppp1)
# you can use the plus (+) character to match all of them (i.e. ppp+).

# No router statements have been produced, because your server
# is not configured for forwarding traffic.

Customizing the Configuration File

The auto-generated configuration file lists “TODO” items for you to do as you review the file. You can rename the interfaces to something meaningful, such as “lan” and “internet”. You can remove any of the named or unnamed (“custom”) services that it includes rules for. A few more of the rules that Firehol generated for my server bear some explanation:

  • UDP/17500 is used by the Dropbox service to identify other Dropbox clients on the LAN. This rule cannot be removed
  • TCP and UDP/25500 is one of the peer ports I set up for transmission-daemon. This I actually have to change, because I have a port range open for those services.
  • UDP/10000 can be removed, because webmin runs on TCP/10000.

Server vs. Client Rules

Firehol considers all incoming requests “server” requests and all outgoing requests “client” requests. You might see client accept all in a configuration file. That means that client requests from any service are allowed. If you only want to allow certain services to be allowed, you can specify them much like server services are specified.

client http allow

Setting up Custom Services

To clean up custom services—for Transmission or Dropbox in this case—you can either give them names and define them inline…

server custom transmission-daemon tcp/9091 any accept
server custom dropbox-lan-peers udp/17500 any accept
server custom transmission-peers “tcp/20550:20599 udp/20550:20599” any accept

…or define them at the top of the script as variables…

# Transmission front-end
server_txf_ports="tcp/9091"
client_txf_ports="default"

# Transmission peers
server_txp_ports="tcp/20500:20599 udp/20500:20599"
client_txp_ports="default"

# Dropbox-related LAN functions
server_dpbx_ports="udp/17500"
client_dpbx_ports="default"

…and then invoke them very simply:

# custom services
server txf accept
server txp accept
server dpbx accept

To specify a port range, use a colon instead of a dash to indicate “through.” To specify both tcp and udf ports, use a space-delimited list, enclosed in quotation marks.

Different Rules for LAN vs. Internet

If you run Samba for file sharing, you’ll want to allow your LAN users to use Samba file shares, and block Internet users from doing so. (It’s true that the Samba ports should also be blocked on your router/gateway, if you have one, but bear with me.) To do so, you’ll want to include rules to allow Samba on your LAN interface (interface1 in the automatically-generated file above), and not include those Samba-related rules in the Internet interface (interface2, above). You might wish to remove webmin and other services from the Internet-side, too. I do both in my configuration file, which is reproduced below.

My Configuration File

Here is my configuration file. It implements kinder rules for the LAN and stricter rules for the Internet.

#!/sbin/firehol
# -----------------------------------------------
# Set up custom services
# -----------------------------------------------

# Transmission front-end
server_txf_ports="tcp/9091"
client_txf_ports="default"

# Transmission peers
server_txp_ports="tcp/20500:20599 udp/20500:20599"
client_txp_ports="default"

# Dropbox-related LAN functions
server_dpbx_ports="udp/17500"
client_dpbx_ports="default"

# -----------------------------------------------
# Set up interfaces
# -----------------------------------------------

# LAN Interface
# The purpose of this interface is to control the traffic
# on the eth0 interface with IP 10.0.0.3 (net: "10.0.0.0/24").
interface eth0 lan src "10.0.0.0/24" dst 10.0.0.3

	# policies
	policy reject

	# standard services
	server dhcp accept
	server http accept
	server ICMP accept
	server ms_ds accept
	server ntp accept
	server samba accept
	server ssh accept
	server webmin accept

	# custom services
	server txf accept
	server txp accept
	server dpbx accept

	# client section
	client all accept

# Internet Interface
# The purpose of this interface is to control the traffic
# from/to unknown networks behind the default gateway 10.0.0.1.
interface eth0 internet src not "${UNROUTABLE_IPS} 10.0.0.0/24" dst 10.0.0.3

	# policies
	policy drop
	protection strong

	# Here are the services listening on eth0.
	# TODO: Normally, you will have to remove those not needed.
	server http accept
	server ICMP accept
	server ntp accept
	server ssh accept

	# custom services
	server txf accept
	server txp accept

	# client section
	client http accept
	client https accept
	client ICMP accept
	client ntp accept
	client ssh accept
	client txp accept
	client txf accept

Note that I have cleaned it up considerably and defined custom services at the top of the file. This is not the most condensed configuration file I could make, but it is easy to understand.

Testing Your Configuration File

To test the configuration file you have edited, run the firehol test command.

$ sudo firehol test /tmp/firehol.conf

This will do a syntax check of your configuration file, then allow you to commit the changes to the firewall by typing "commit" at a prompt. I recommend that you don't type commit if your configuration file is not in the right place. Let's move the tested, working configuration file there first.

Enabling Your Configuration

Once you have customized and tested your configuration file, copy it to where it belongs.

$ sudo cp /tmp/firehol.conf /etc/firehol/firehol.conf

And then initialize the firewall.

$ sudo /etc/init.d/firehol start

And you're done!