1. Introduction

In today’s dynamic environment, where fixed public IP addresses are scarce, and it is the norm to have a dynamic IP address assigned to our Internet connection through the service provider, sometimes we need a solution that allows us to configure our firewall on Linux to allow connections from such IP address.

In this tutorial, we will discuss configuring three popular Linux firewalls, UFW, firewalld, and CSF, to allow traffic from a dynamic IP using a Domain Name System (DNS) service that supports Dynamic DNS.

2. What Is Dynamic DNS?

Dynamic DNS (DDNS) automatically updates a name server in the Domain Name System (DNS), often in real-time, with the active DDNS client’s public IP address.

Multiple Dynamic DNS services are available online, paid, and free, for example, DuckDNS, No-IP, and DynDNS.

Once we sign up for any of the above services, typically, we would choose a hostname and install an agent on our client machine, which would periodically update the A DNS record for our hostname to point to our current public IP address.

The result is we would have a hostname such as “mydomain.ddns.net” that always resolves to our changing public IP address.

3*.* UFW

The Uncomplicated Firewall (UFW) is a firewall configuration tool developed to ease iptables firewall configuration. UFW is commonly used on Ubuntu and Debian derivatives but can be installed on most Linux distributions.

Once we have UFW installed and configured, and once we have our Dynamic DNS hostname ready, the next step is to create a bash script and a cron job that would periodically query our DDNS hostname and update UFW to allow connections from the current IP address.

Let’s create the bash script to be used by our cron job:

$ sudo cat /usr/local/bin/ufw_ddns_update.sh

#!/bin/bash
# Bash script to query DDNS service for hostname current IP address and create or update UFW firewall rules
# to allow access to all ports and protocols from the dynamic IP address.
# This script is intended to be run from a cron job with root privileges.
# The script will only update the firewall rules if the IP address has changed.

# Set the DDNS service URL
DDNS_HOSTNAME="mycustomhostname.ddns.net"
# Get the DDNS hostname IP address
DDNS_IP=$(dig +short ${DDNS_HOSTNAME})
# Get the current IP allowed in UFW for this hostname
OLD_IP=$(/usr/sbin/ufw status | grep $DDNS_HOSTNAME | head -n1 | tr -s ' ' | cut -f3 -d ' ')

# Check if the DDNS hostname IP address is valid
if [[ "${DDNS_IP}" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
  # Check if the old IP is valid
  if [[ "${OLD_IP}" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
    # Check if the DDNS service IP address is different from the old IP address
    if [[ "${DDNS_IP}" != "${OLD_IP}" ]]; then
        # Delete the old rule
        /usr/sbin/ufw delete allow from $OLD_IP to any
        # Create a new rule for the new IP address
        /usr/sbin/ufw allow from "${DDNS_IP}" to any comment $DDNS_HOSTNAME
    else
      echo "$0: The IP address is the same, no need to update the firewall rules."
    fi
  else
    # Create a new rule for the new IP address
    /usr/sbin/ufw allow from "${DDNS_IP}" to any comment $DDNS_HOSTNAME
  fi
else
  echo "$0: DDNS IP address is not valid for ${DDNS_HOSTNAME}: ${DDNS_IP}"
fi

We want to update the script and edit DDNS_HOSTNAME to match the hostname we created earlier with our Dynamic DNS service.

We’ll need to install the dig utility for the script to work correctly using apt and yum.

Next, let’s mark the bash script as an executable:

$ sudo chmod +x /usr/local/bin/ufw_ddns_update.sh

Now, let’s create a cron job to execute the script every hour:

$ sudo crontab -e
0 * * * * /usr/local/bin/ufw_ddns_update.sh

We should note this cron job needs to run with root privileges. We can either create the cron job under the root user account or use sudo instead.

4*.* Firewalld

Firewalld is a dynamically managed firewall, and it provides an interface for services and applications to manage firewall rules directly. It’s the default firewall for Red-Hat-based distributions, and we can install it on most Linux distributions.

Let’s create a bash script to resolve our DDNS hostname and update its rules accordingly automatically:

$ sudo cat /usr/local/bin/firewalld_ddns_update.sh

#!/bin/bash
# Bash script to query DDNS service for hostname current IP address and create or update firewalld rules
# to allow access to all ports and protocols from the dynamic IP address.
# This script is intended to be run from a cron job with root privileges.
# The script will only update the firewall rules if the IP address has changed.

# Set the DDNS service URL
DDNS_HOSTNAME="mycustomhostname.ddns.net"
# Get the DDNS hostname IP address
DDNS_IP=$(dig +short ${DDNS_HOSTNAME})
# Get the current IP allowed in UFW for this hostname
OLD_IP=$(/bin/firewall-cmd --direct --get-all-rules | grep $DDNS_HOSTNAME | head -n1 | tr -s ' ' | cut -f6 -d ' ')

# Check if the DDNS hostname IP address is valid
if [[ "${DDNS_IP}" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
  # Check if the old IP is valid
  if [[ "${OLD_IP}" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
    # Check if the DDNS service IP address is different from the old IP address
    if [[ "${DDNS_IP}" != "${OLD_IP}" ]]; then
        # Delete the old rule
        /bin/firewall-cmd --direct --remove-rule ipv4 filter INPUT 0 -s ${OLD_IP} -j ACCEPT -m comment --comment "${DDNS_HOSTNAME}"
        # Create a new rule for the new IP address
        /bin/firewall-cmd --direct --add-rule ipv4 filter INPUT 0 -s ${DDNS_IP} -j ACCEPT -m comment --comment "${DDNS_HOSTNAME}"
    else
      echo "$0: The IP address is the same, no need to update the firewall rules."
    fi
  else
    # Create a new rule for the new IP address
    /bin/firewall-cmd --direct --add-rule ipv4 filter INPUT 0 -s ${DDNS_IP} -j ACCEPT -m comment --comment "${DDNS_HOSTNAME}"
  fi
else
  echo "$0: DDNS IP address is not valid for ${DDNS_HOSTNAME}: ${DDNS_IP}"
fi

Similarly, we need to update the DDNS_HOSTNAME to match our DDNS hostname.

We need to install the dig utility for the script to work correctly. Accordingly, we can install it using apt and yum.

Next, let’s mark the bash script as an executable:

$ sudo chmod +x /usr/local/bin/firewalld_ddns_update.sh

Now, let’s create a cron job to execute the script every hour:

$ sudo crontab -e
0 * * * * /usr/local/bin/firewalld_ddns_update.sh

This cron job will regularly monitor our dynamic IP address and update the firewall configuration accordingly.

5. csf

ConfigServer Security and Firewall (csf) is a free stateful firewall and intrusion prevention system for Linux servers. It is available for most Linux distributions. As well as supports allowing connections from DDNS hostnames.

In the following steps, we will install csf and configure it to allow connections from our Dynamic DNS hostname.

5.1. Installation

Installation is straightforward. To install it, we can download and use the install script:

$ cd /usr/src
$ wget https://download.configserver.com/csf.tgz
$ tar -xzf csf.tgz
$ cd csf
$ sh install.sh

We can find csf configuration files under the path /etc/csf/.

5.2. Configuration

To configure csf to allow connections from our Dynamic DNS hostname, let’s add our hostname to the file /etc/csf/csf.dyndns:

$ cat /etc/csf/csf.dyndns
mycustomhostname.ddns.net

Next, we need to configure csf to enable the Dynamic DNS feature. We can do this by editing the file /etc/csf/csf.conf and adjusting the value of the variable DYNDNS. Basically, a value of 600 means checking for IP updates every 10 minutes.

6. Conclusion

In this article, we have explored different options to configure firewall rules to allow access from a dynamic IP address. We have discussed a solution using a bash script and a cron job when using UFW and Firewalld*.* Additionally, we’ve looked at how to install and configure csf.