Here's the scenario: we have a Redis server running on a Raspberry Pi and we want to make it available to other machines on a network rather than just using the Redis server in a localhost context. We have already added a password to the Redis server instance; however, due to the high-performance capabilities of Redis, it is possible for outside systems to barrage it with massive number of passwords in parallel to break in. It's time for a firewall.
In this tutorial, we will learn how to set up a firewall for Redis using ufw. The steps we describe will be useful for any Debian-based distribution such as Debian, Ubuntu, or Raspbian, and will equip you to create firewall rules for other applications too.
Article contents
Introduction
We will use ufw
, the uncomplicated firewall, to accomplish our goal. When we create a firewall using ufw
, we are actually using iptables
, a more powerful (and more complicated) tool for controlling the Linux kernel firewall capabilities, behind the scenes. I'm all about "uncomplicated" π and (as you'll soon find out) ufw
will suffice for a majority the firewall objectives that us common people are seeking to achieve.
Install ufw
To start, determine if ufw
is already installed on our system:
$ which ufw
This command comes back with nothing so let's install ufw
:
$ sudo app install ufw
Next, check the firewall status to ensure it's alive:
$ sudo ufw status
Status: inactive
Looks good - ufw
starts in an inactive
state which is good since we want to apply and review our firewall rules before activating.
Configure firewall defaults
By default, we want to deny all incoming traffic and allow all outgoing traffic. ufw
typically ships with these defaults, but we want to make sure.
$ sudo ufw default deny incoming
$ sudo ufw default allow outgoing
Allow connections to common services
ssh
We want to allow ssh connections to our machine (TCP port 22). In fact, I am currently remoted into my machine using an ssh client, and I most certainly don't want to cut off the branch I'm standing on when I enable the firewall.π
We have three options for allowing ssh connections to machines:
Option 1 - Allow any machine to connect to our machine via ssh:
$ sudo ufw allow 22/tcp
Option 2 - Limit ssh access to only a certain range of IP addresses
$ sudo ufw allow from 192.168.0.0/16 to any port 22 proto tcp
ufw
utilizes CIDR notation to specify the group of IP addresses to grant (or deny) access. Here are a couple of examples:
- 192.168.0.0/16 β 192.168.*.* where * is any integer from 0 to 255
- 192.168.1.0/24 β 192.168.*.* where * is any integer from 0 to 255
Option 3 - Limit ssh access to a specific IP address
$ sudo ufw allow from 192.168.1.5 to any port 22 proto tcp
I'm choosing option 2 to restrict access to a certain range of IP addresses.
http
Likewise, we'll let traffic through for http (web server) we have running on our system (running on port 80):
$ sudo ufw allow from 192.168.0.0/16 to any port 80 proto tcp
Allow connections to Samba
I'm running Samba on my Raspberry Pi to host file shares and to make it easier for Windows machines on my network to discover the Pi system. See my Solution for Can't Ping Raspberry Pi Hostname on the Network article for more information.
Samba requires the following ports to be open: UDP 137, UDP 138, TCP 139, TCP 445
That looks like a lot of work to add all those ports to ufw
. Is there an easier way? Why yes, I'm glad you asked.π
ufw
includes a feature called application profiles that helps further ease firewall maintenance. You provide a profile name rather than specific port numbers to configure the firewall. You can also create your own custom application profiles which we will discuss in a few minutes.
Let's see what ufw
application profiles exist on our system:
$ sudo ufw app list
Available applications:
Samba
Socks
VNC
WWW
I have trimmed my list for brevity, but you get the idea.
Next, gather more information on the Samba
application profile (note that "Samba" is case sensitive):
$ sudo ufw app info Samba
Profile: Samba
Title: LanManager-like file and printer server for Unix
Description: The Samba software suite is a collection of programs that
implements the SMB/CIFS protocol for unix systems, allowing you to serve
files and printers to Windows, NT, OS/2 and DOS clients. This protocol is
sometimes also referred to as the LanManager or NetBIOS protocol.
Ports:
137,138/udp
139,445/tcp
Excellent - we see that the Samba profile is configured to utilize 2 UDP ports and 2 TCP ports.
Use the Samba application profile in our firewall configuration:
$ sudo ufw allow from 192.168.0.0/16 to any app Samba
Notice that we use the word "app" in the command above in lieu of "port" which is used when specifying port numbers.
Activate the firewall
We're ready to review the rules we added and confirm it all looks good before we activate the firewall:
$ sudo ufw show added
Added user rules (see 'ufw status' for running firewall):
ufw allow from 192.168.0.0/16 to any port 22 proto tcp
ufw allow from 192.168.0.0/16 to any port 80 proto tcp
ufw allow from 192.168.0.0/16 to any app Samba
We must use this command because sudo ufw status
will not yield any useful information when the firewall is not active.
Our rules look solid. I double check once again π to verify ssh (port 22) will be open since I want to continue using my ssh client after I hit enter on the command to activate the firewall.
Let's activate the firewall:
$ sudo ufw enable
Firewall is active and enabled on system startup
Very good - our firewall is active and will continue to be active when we reboot our system. Also, I'm still able to enter commands through my ssh client so something is working correctly!
Next, review the firewall status now that it is active:
$ sudo ufw status
Status: active
To Action From
-- ------ ----
22/tcp ALLOW 192.168.0.0/16
80/tcp ALLOW 192.168.0.0/16
Samba ALLOW 192.168.0.0/16
We can also use the verbose
option to review our default rules and the port numbers associated with the Samba
application profile:
$ sudo ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), deny (routed)
New profiles: skip
To Action From
-- ------ ----
22/tcp ALLOW IN 192.168.0.0/16
80/tcp ALLOW IN 192.168.0.0/16
137,138/udp (Samba) ALLOW IN 192.168.0.0/16
139,445/tcp (Samba) ALLOW IN 192.168.0.0/16
Test the firewall (optional)
For testing, we can use the venerable nmap
port scanner to discover the open ports on our firewall as another sanity check to verify our firewall is configured correctly. We'll also run these commands from another machine on our network called host2
to test our firewall.
[host2]$ sudo apt install nmap
Assuming our system has an IP address of 192.168.1.7, we run this command from another host on our network:
[host2]$ nmap 192.168.1.7
Starting Nmap 7.60 ( https://nmap.org ) at 2018-11-21 11:59 PST
Nmap scan report for raspi (192.168.1.7)
Host is up (0.0034s latency).
Not shown: 996 filtered ports
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
139/tcp open netbios-ssn
445/tcp open microsoft-ds
Nmap done: 1 IP address (1 host up) scanned in 4.67 seconds
Very good - it looks like we're not exposing any other ports than the ports we specified.
To give ourselves further assurance, we can open a random TCP port on our system using nc
(Netcat) and confirm that an nmap scan from an outside host is not able to see the open port:
[host2]$ nc -l 7000
That "-l" is a lower case "L" and instructs Netcat to listen on TCP port 7000.
By repeating the nmap scan from another host on our network, we see that port 7000 is not exposed:
[host2]$ nmap 192.168.1.7
Starting Nmap 7.60 ( https://nmap.org ) at 2018-11-21 11:59 PST
Nmap scan report for raspi (192.168.1.7)
Host is up (0.0034s latency).
Not shown: 996 filtered ports
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
139/tcp open netbios-ssn
445/tcp open microsoft-ds
Nmap done: 1 IP address (1 host up) scanned in 4.67 seconds
Everything is looking good!
Allow connections to Redis Server
Redis is often used as a cache/database that is only available to internal processes on localhost, but sometimes there is a need to allow connections from the outside.
Redis listens on TCP port 6379. To allow external Redis access, we can accomplish the goal in one of two ways:
Option 1 - Add Redis port directly
$ sudo ufw allow from 192.168.0.0/16 to any port 6379 proto tcp
We're done, and there are no drawbacks to this solution. You can obviously tailor the IP addresses to your context.
Option 2 - Create Redis ufw application profile
For those who want to understand ufw
application profiles deeper, venture on. We'll create our own ufw
application profile for Redis. Why? Because we can.π
The ufw
application profiles (INI file format) reside in the following directory: /etc/ufw/applications.d
First, create a new profile for Redis:
$ sudo nano /etc/ufw/applications.d/redis
Add the following contents:
[Redis]
title=Persistent key-value database with network interface
description=Redis is a key-value database in a similar vein to memcache but the dataset is non-volatile.
ports=6379/tcp
After saving this file, the application profile should magically become available. We can verify it now exists:
$ sudo ufw app list | grep -i redis
Redis
If the application profile is not there, we can force an update:
$ sudo ufw app update Redis
Next, we can review the new Redis profile that was added:
$ sudo ufw app info Redis
Profile: Redis
Title: Persistent key-value database with network interface
Description: Redis is a key-value database in a similar vein to memcache
but the dataset is non-volatile.
Port:
6379/tcp
Fabulous! We are ready to use our new Redis
application profile:
$ sudo ufw allow from 192.168.0.0/16 to any app Redis
Test Redis firewall connection
Let's review our complete firewall status using the verbose
option to see the complete details:
$ sudo ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), deny (routed)
New profiles: skip
To Action From
-- ------ ----
22/tcp ALLOW IN 192.168.0.0/16
80/tcp ALLOW IN 192.168.0.0/16
137,138/udp (Samba) ALLOW IN 192.168.0.0/16
139,445/tcp (Samba) ALLOW IN 192.168.0.0/16
6379/tcp (Redis) ALLOW IN 192.168.0.0/16
Redis is in there and we are ready for our final test!
Finally, use the redis-cli
to connect from a different machine (called host2
in our example):
[host2]$ redis-cli -h 192.168.1.7
192.168.1.7:6379>
Hooray! We can connect to the Redis server from a different machine on our network!
How to make additional changes
If we need to make additional changes, we can review the rules by number and delete as needed:
$ sudo ufw status numbered
Status: active
To Action From
-- ------ ----
[ 1] 22/tcp ALLOW IN 192.168.0.0/16
[ 2] 80/tcp ALLOW IN 192.168.0.0/16
[ 3] Samba ALLOW IN 192.168.0.0/16
[ 4] Redis ALLOW IN 192.168.0.0/16
For example, I can delete rule #4 for Redis:
$ sudo ufw delete 4
I can also add a new rule in position 2 for https traffic (port 443)
$ sudo ufw insert 2 allow from 192.168.0.0/16 to any port 443 proto tcp
...and review the result
$ sudo ufw status numbered
Status: active
To Action From
-- ------ ----
[ 1] 22/tcp ALLOW IN 192.168.0.0/16
[ 2] 443/tcp ALLOW IN 192.168.0.0/16
[ 3] 80/tcp ALLOW IN 192.168.0.0/16
[ 4] Samba ALLOW IN 192.168.0.0/16
Let's take rule 2 back out and put Redis back in:
$ sudo ufw delete 2
$ sudo ufw allow from 192.168.0.0/16 to any app Redis
... and review the new results:
$ sudo ufw status numbered
Status: active
To Action From
-- ------ ----
[ 1] 22/tcp ALLOW IN 192.168.0.0/16
[ 2] 80/tcp ALLOW IN 192.168.0.0/16
[ 3] Samba ALLOW IN 192.168.0.0/16
[ 4] Redis ALLOW IN 192.168.0.0/16
Everything looks great and we have victory!
Miscellaneous tips
The order of the ufw
firewall rules matter. We used a default deny policy, but we could have specifically added deny
rules in addition to allow
rules. In most scenarios, your deny
rules should be listed first since once a rule is matched, other rules that might also match are not evaluated. Here's an example from the Ubuntu Community Help Wiki:
Scenario: You want to block access to port 22 from 192.168.0.1 and 192.168.0.7 but allow all other 192.168.0.x IPs to have access to port 22 using tcp
$ sudo ufw deny from 192.168.0.1 to any port 22
$ sudo ufw deny from 192.168.0.7 to any port 22
$ sudo ufw allow from 192.168.0.0/24 to any port 22 proto tcp
The specific deny rules are placed first for good reason. If the allow
rule (listed third) were first, the other two deny
rules would be ignored because a match would have already been achieved for the IP address/port/protocol when the allow
rule was processed first.
As a second tip, the user defined ufw
rules are located the following location (along with a bunch of other rule files in this directory):
/etc/ufw/user.rules
- ipv4 rules/etc/ufw/user6.rules
- ipv6 rules
I don't recommend editing these rule files, but this can help you understand what ufw
is doing behind the scenes as it creates iptables
equivalent commands in the background.
Conclusion
We successfully learned how to set up an Ubuntu/Raspbian firewall for Redis and other applications using ufw
βand we hopefully had fun in the process.
The ufw
(uncomplicated firewall) program is quite elegant and easy to use. It also offers flexibility to accomplish a variety of packet filtering scenarios. If you need to go deeper, check out iptables
which is the technology behind ufw
. Go build something awesome!
Follow @thisDaveJ (Dave Johnson) on Twitter to stay up to date with the latest tutorials and tech articles.
Additional articles
Guide to Installing Node.js on a Raspberry Pi
Guide to Using Redis with Node.js
Debian apt Command Cheat Sheet
Solution for Can't Ping Raspberry Pi Hostname on the Network
Create a Lightweight Raspberry Pi with Raspbian Lite
Last updated Dec 07 2018
5 thoughts on “How to Set up a Firewall for Redis using ufw”