How to Set up a Firewall for Redis using ufw

Raspberry Pi firewall
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

Share

5 thoughts on “How to Set up a Firewall for Redis using ufw

Leave a Reply

Your email address will not be published. Required fields are marked *