Question

ufw port forwarding

Posted January 2, 2020 1k views
UbuntuFirewallDigitalOcean Cloud Firewalls

Hi there,

I’ve been following https://crosstalksolutions.com/definitive-guide-to-hosted-unifi/ in order to setup the unifi controller on DO. It works perfectly, but my ISP supplies me with a dynamic IP address. We have a lot of work going on at the moment which means throughout the day, the power goes off for a while and we power up, I get a new IP. Is there anyway to handle this with firewall rules to I don’t have to keep manually logging in and allowing my new ip through? At the moment I’m having to load the console from the DO account page and login as root to unblock myself.

These answers are provided by our Community. If you find them useful, show some love by clicking the heart. If you run into issues leave a comment, or add your own answer to help others.

×
4 answers

Hi

ufw allows you to define IP ranges using CIDR, though the downside, in this case, would be that you’d be casting a wide net and anyone on the range would be able to access the login page for Unifi.

Example

ufw allow from 10.1.1.0/24 to any port 8443

This will allow any IP from 10.1.1.0 to 10.1.1.255. You can cast it wider by moving up to a /16 (replacing the /24), allowing access from 10.1.0.0 to 10.1.255.255

ufw allow from 10.1.0.0/16 to any port 8443

This will reduce the chances of you having to change the IP, though it won’t eliminate it–especially if your IP changes the entire range and you’re not aware of all ranges in use.

The better solution would be to use a shell script locally which pushes the change to your remote Droplet with the UniFi Controller installed. You’d need CRON and Bash locally to set this up. This could be done on a small raspberry pi or even a VM if you can run on locally.

Local Shell Script

This will be used to pull your current IP and pass it to the remote server so ufw allows the correct IP through.

ipupdate-local.sh

#!/usr/bin/env bash

ipAddress=$(curl -s icanhazip.com)

ssh root@1.1.1.1 "/opt/ipupdate-remote.sh ${ipAddress}"

You’ll want to update the IP above (1.1.1.1) to match your Droplet IP and then give the above script execution permissions using chmod +x ipupdate-local.sh. This script can then be executed via CRON every N minutes using:

*/5 * * * * /path/to/ipupdate-local.sh

Remote Shell Script

This will be used to reset ufw so that it uses the new IP passed through by ipupdate-local.sh. If no IP is provided, it will exit (so the firewall rules aren’t reset and you’re not locked out).

/opt/ipupdate-remote.sh

#!/usr/bin/env bash

#+----------------------------------------------------------------------------+
#+ Define IP Address
#+----------------------------------------------------------------------------+
ipAddress="${1}"

#+----------------------------------------------------------------------------+
#+ Check for IP Address Argument (exit if no IP is provided)
#+----------------------------------------------------------------------------+
if [ -z "${ipAddress}" ]; then
    echo "No IP Provided."
    exit 1
fi

#+----------------------------------------------------------------------------+
#+ Temporarily Disable ufw
#+----------------------------------------------------------------------------+
sudo ufw --force disable

#+----------------------------------------------------------------------------+
#+ Reset the Firewall Rules for ufw (clears all active rules)
#+----------------------------------------------------------------------------+
sudo ufw --force reset

#+----------------------------------------------------------------------------+
#+ Set Defaults for ufw
#+----------------------------------------------------------------------------+
#+ We'll deny all incoming (except those we explicitly define below) and allow
#+ all outgoing connections.
#+----------------------------------------------------------------------------+
sudo ufw default deny incoming
sudo ufw default allow outgoing

#+----------------------------------------------------------------------------+
#+ Define Default ufw Rules
#+----------------------------------------------------------------------------+
sudo ufw allow from "${ipAddress}" to any port 22           # Only allow SSH access to your IP
sudo ufw allow from "${ipAddress}" to any port 8443         # UniFi access on Port 443 to your IP

#+----------------------------------------------------------------------------+
#+ Define Additional ufw Rules (any others you may need)
#+----------------------------------------------------------------------------+
#+ These are commented, so won't be active unless you remove the #
#+----------------------------------------------------------------------------+
# sudo ufw allow from 80/tcp
# sudo ufw allow from 443/tcp
# .... etc

#+----------------------------------------------------------------------------+
#+ Enable ufw
#+----------------------------------------------------------------------------+
sudo ufw --force enable

You’ll also want to give this execution permissions by running chmod +x /opt/ipupdate-remote.sh.

In the script above you’ll see Define Additional ufw Rules (any others you may need), this is where you can define any additional rules that you may need. By default, the above limits access to 22 (SSH) and 8443 (the default controller port).

If you accidentally lock yourself out, the console can be used to regain access since it operates over VNC (thus a block on port 22 will not lock you out of console).

All the best,

Jonathan Tittle
Manager, Support

Wow thank you for such an awesome reply. I do have an old RP licking sround, though it’s quite old but might be well suited to this. I’ll give it a crack, though I will no doubt be asking further questions.

Thank you again

I have them both setup (the local via a linux vm on windows 10). I can see it’s running but it’s not working and I have a feeling it’s to do with the local. How does the cron task access the server via the ssh login if no password is given in the script?

Also if my ip is now blocked from ssh access, surely the cron task can’t access the server?

  • Hi @Geriko ,

    The best way to connect would be to use a passwordless SSH key and pass that to the ssh command in ipupdate-local.sh

    I’ll use name-of-key in the examples below. Please replace instances of name-of-key with the name you’d like to set for your key (it can be anything you’d like).

    For example, on the local server, generate a new SSH key using the command below:

    ssh-keygen -a 1000 \
               -C "" \
               -E sha256 \
               -f ${HOME}/.ssh/name-of-key \
               -o \
               -q \
               -t ed25519
    

    When prompted for a password, hit enter and then run:

    cat ${HOME}/.ssh/name-of-key.pub
    

    You should see a string prefixed with ssh-ed25519 which we’ll use next.

    On the Droplet, add the public key you just created to the authorized_keys file. This allows the local machine to login to the Droplet without a password using key-based authentication instead of a password.

    nano /root/.ssh/authorized_keys
    

    Add the full string output from the cat command you ran on the local machine and save the changes. For the sake of ensuring permissions are correct, run the following command:

    chmod 644 /root/.ssh/authorized_keys
    

    Now that your keys are setup, you’ll need to modify the ssh command in ipupdate-local.sh.

    Change:

    ssh root@1.1.1.1 "/opt/ipupdate-remote.sh ${ipAddress}"
    

    to:

    ssh root@1.1.1.1 -i ${HOME}/.ssh/name-of-key "/opt/ipupdate-remote.sh ${ipAddress}"
    

    Additionally, I would recommend one other change that slipped my mind. Since your IP is always changing, it would be best to not limit access on port 22. If you limit it to one IP and then the IP changes, you’re locked out (and would need to use the console).

    In /opt/ipupdate-remote.sh, I would recommend changing

    sudo ufw allow from "${ipAddress}" to any port 22           # Only allow SSH access to your IP
    

    to:

    sudo ufw allow 22/tcp
    

    All the best,

    Jonathan Tittle
    Manager, Support

Hi Jon,

I stayed up late last night going over your OP and I came to the same conclusions. I now have a passwordless key and have allowed my custom ssh port to be accessed. I have adjusted the script, however I get the error:

"sudo: no tty present and no askpass program specified"

I can confirm that I can ssh from the VM to the server without needing a password by sshing manually.

Submit an Answer