As a big fan of Unifi products, I manage multiple Unifi sites from a self-hosted UniFi Network Application across various locations.Sometime after migrating from my UniFi Security Gateway USG-3 to an UniFi UXG Lite and upgrading from UniFi Network Application 7.x.xx to UniFi Network Application 8.x.xx, I suddenly noticed that I could no longer modify existing firewall rules. When trying to modify a rule, I received an error message along the lines of “Unable to save rule xxx due to out of range index number 2xxx.”. I’m not sure if it was caused by switching to the UXG Lite or the software upgrade, but things changed somewhere in this process.

The only option I had was to quickly create a new one and delete the old one. Not very convenient, to say the least. Initially, I didn’t spend any more time on it since I wanted to move on and thought I would delve into it later.

Today, however, I needed to create a Firewall Rule that would be one of the first to be applied. I created a new rule in the usual way, which appeared at the bottom of the list after being created. When I tried to drag it up in the GUI, an error message appeared saying “Firewall rule reorder failed. Please ensure all firewall options have been entered correctly.”

When I took a closer look at my Firewall Rules, two things immediately stood out to me:

  • All my existing rules had an ID in the 2xxx series, while the newly created firewall rule was assigned an ID of 2xxxx.
  • All my existing rules suddenly had an extra row with a lock icon in UniFi Network Application 8.1.113.

This likely explains why I was receiving an “out of range index number” error when trying to modify existing old firewall rules. It strongly appears that UniFi has switched to a different series of index numbers for their firewall rules. Although old rules have been carried over, you can no longer modify them or give newly created firewall rules a higher priority than the old ones.

In my case, and undoubtedly for many others who have extensive firewall rules, this is quite frustrating. To make modifications, they need to be converted to a new index number, meaning you will have to create new firewall rules and then delete the old ones from the 2xxx series. Initially, I started manually replicating all the rules, but I quickly grew tired of that. There has to be a more efficient way to do this.

Although there appears to be an API for the UniFi Network Application, the documentation leaves much to be desired. I could find very little substantial documentation on it.

After some searching, I came across some API documentation on the Ubiquiti Community Wiki, which was useful. By using the URL api/s/{site}, it’s possible to interact with User-defined firewall rules via rest/firewallrule. Using the GET method, you can retrieve existing rules, and theoretically, you should be able to create some rules using the POST method. After some figuring out, I was eventually able to read all existing rules via the API.

The next step was to change the rule_index number from a 2xxx series to a 2xxxx number and then write it back using the API. To my surprise, I was able to modify the cloned firewall rule, which now had a 2xxxx ID, and successfully import the modified rule into the UniFi Network application. I ended up writing a PowerShell script that allowed me to read and modify all existing rules at once. During testing, I encountered some issues, but I was able to automate the resolution using the PowerShell script as well.

By using my script, you can convert all your old, existing Firewall Rules into new Firewall Rules in one go. I’ll share the script with you in the text below. Just make sure to create a good backup of your UniFi configuration before you run the script!!! Don’t forget to adjust the “Configuration Variables” section to suit your environment.

Backup your UniFi Network Application configuration before running the script! Better safe than sorry đŸ˜‰

<#
.SYNOPSIS
This script clones firewall rules within specified index ranges and rulesets to new indices starting from a specified index.

.DESCRIPTION
The script logs into a UniFi Controller, retrieves firewall rules based on user-defined criteria, and clones them to new indices. It is configurable for different sites, ranges, and ruleset types.

.PARAMETERS
- $UnifiControllerSiteID: Site ID for which the rules are managed.
- $UnifiControllerMigrateRuleStartIndex: Start index of the rule range to clone.
- $UnifiControllerMigrateRuleEndIndex: End index of the rule range to clone.
- $UnifiControllerNewRulesStartIndex: Starting index for new cloned rules.
- $UnifiControllerRuleSet: Type of ruleset to filter (e.g., LAN_IN, LAN_OUT).

.EXAMPLE
# To execute the script, simply configure the parameters at the top of the script and run it in a PowerShell environment.

.NOTES
Ensure to test the script in a controlled environment before deploying in production.
#>

# Configuration Variables
$UnifiControllerURL = "https://xxx.xxx.xxx.xxx:8443"    #UniFi Controller IP / Hostname
$UnifiControllerUsername = "admin@unifi.local"          #UniFi Username
$UnifiControllerPassword = "password"                   #UniFi Password
$UnifiControllerSiteID = "default"                      #UniFi SiteID   
$UnifiControllerMigrateRuleStartIndex = 2000            #Start index of the rule range to clone
$UnifiControllerMigrateRuleEndIndex = 2999              #End index of the rule range to clone.
$UnifiControllerNewRulesStartIndex = 20000              #Starting index for new cloned rules.
$UnifiControllerRuleSet = 'LAN_IN'                      #Type of ruleset to filter (e.g., LAN_IN, LAN_OUT).

# Ignore SSL errors if your controller uses a self-signed certificate
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true }

# Start a session and save the cookie
$session = New-Object Microsoft.PowerShell.Commands.WebRequestSession
$loginUri = "$UnifiControllerURL/api/login"
$body = @{ username = $UnifiControllerUsername; password = $UnifiControllerPassword } | ConvertTo-Json

$response = Invoke-RestMethod -Uri $loginUri -Method Post -Body $body -SessionVariable session -ContentType "application/json"

# Constructs the API endpoint URL and retrieves the firewall rules for the specified site ID using an authenticated GET request.
$devicesUri = "$UnifiControllerURL/api/s/$UnifiControllerSiteID/rest/firewallrule"
$devices = Invoke-RestMethod -Uri $devicesUri -WebSession $session -Method Get

# Retrieve firewall rules with rule_index between $UnifiControllerMigrateRuleStartIndex and $UnifiControllerMigrateRuleEndIndex and matching the ruleset
$filteredRules = $devices.data | Where-Object {
    $_.rule_index -ge $UnifiControllerMigrateRuleStartIndex -and $_.rule_index -le $UnifiControllerMigrateRuleEndIndex -and $_.ruleset -eq $UnifiControllerRuleSet
} | Sort-Object rule_index  # Ensure the rules are sorted by their indices

# Initialize the new index starting from $UnifiControllerNewRulesStartIndex
$newIndex = $UnifiControllerNewRulesStartIndex

foreach ($rule in $filteredRules) {
    # Clone the rule
    $newRule = $rule.PSObject.Copy()

    # Assign the new index and increment for the next rule
    $newRule.rule_index = $newIndex++
    
    # It's typical to unset the ID before submitting a new entry
    $newRule._id = $null

    # Convert the modified rule to a JSON payload
    $jsonBody = $newRule | ConvertTo-Json -Depth 5

    # Define the endpoint URI for creating the new rule
    $createRuleUri = "$UnifiControllerURL/api/s/$UnifiControllerSiteID/rest/firewallrule"

    # Send the POST request to create the new rule
    try {
        $newRuleResponse = Invoke-RestMethod -Uri $createRuleUri -WebSession $session -Method Post -Body $jsonBody -ContentType "application/json"
        Write-Host "New rule created successfully with rule_index" -NoNewline -ForegroundColor Green
        Write-Host " $newRule.rule_index" -ForegroundColor Cyan
    }
    catch {
        Write-Host "Failed to create new rule: $_" -ForegroundColor Red
    }
}

After running the script, all firewall rules will appear duplicated within the GUI, and as a final step, you will need to remove the old firewall rules from the 2xxx index series.

At the bottom of the firewall rules, select “Manage,” where you can then select the old firewall rules with a 2xxx number. Finally, click on “Remove” to delete them.