Over the weekend I have upgraded my OPNsense system from 25.7_11 to 26.1_4 and everything is working except inbound port forwarding (aka "Destination NAT").
I am trying to configure Asterisk IAX2 (UDP/4569) from my Work firwall to my home firewall.
I have host aliases for the work firewall (single IPv4) and the home PBX. I have a port alias "iax2_port" = 4569.
I go to Firewall > NAT > Destination NAT and use "+" to add a new rule:
Interface:
Interface: WAN
Version: IPv4
Protocol: UDP
Source (advanced):
Invert Source: (unchecked)
Source Address: thorcom_gate <- alias with correct IPv4 source
Source Port: iax_port
Destination:
Invert Destination: (unchecked)
Destination Address: WAN address (from drop down)
Destination Port: iax_port
Translation:
Redirect Target IP: tubby_pbs <- alias with correct host IP for my internal PBX
Redirect Taget Port: iax_port
When I save the rule I get the error "Danger: Unexpected error, check log for details", but there's nothing visible in the logs accessible from the UI?
It appears that all of my inbound DNATs (formerly "port forwards") have disappeared/failed to be migrated as I have also lost the rules for my NVD/DVR and for my SDR - all of which were working fine under 25.7_11
How do I get inbound DNAT/port forwarding to work again?
Mike
System: Firmware: Reporter should have logs. Better paste the PHP errors here than submitting them (it's a bit difficult to find them out of context).
Cheers,
Franco
Hi Franco,
User-Agent Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36
FreeBSD 14.3-RELEASE-p7 stable/26.1-n271965-1bab7230df71 SMP amd64
OPNsense 26.1_4 889098cfa
Time Mon, 02 Feb 2026 17:00:14 +0000
OpenSSL 3.0.18
Python 3.11.14
PHP 8.3.28
Each time I attempt to add a Destination NAT I get a PHP stack trace:
[02-Feb-2026 14:25:40 Europe/London] TypeError: dom_import_simplexml(): Argument #1 ($node) must be of type object, null given in /usr/local/opnsense/mvc/app/models/OPNsense/Base/BaseModel.php:755
Stack trace:
#0 /usr/local/opnsense/mvc/app/models/OPNsense/Base/BaseModel.php(755): dom_import_simplexml(NULL)
#1 /usr/local/opnsense/mvc/app/models/OPNsense/Base/BaseModel.php(822): OPNsense\Base\BaseModel->internalSerializeToConfig()
#2 /usr/local/opnsense/mvc/app/controllers/OPNsense/Base/ApiMutableModelControllerBase.php(327): OPNsense\Base\BaseModel->serializeToConfig(false, true)
#3 /usr/local/opnsense/mvc/app/controllers/OPNsense/Base/ApiMutableModelControllerBase.php(498): OPNsense\Base\ApiMutableModelControllerBase->save(false, true)
#4 /usr/local/opnsense/mvc/app/controllers/OPNsense/Firewall/Api/DNatController.php(122): OPNsense\Base\ApiMutableModelControllerBase->addBase('rule', 'rule')
#5 /usr/local/opnsense/mvc/app/library/OPNsense/Mvc/Dispatcher.php(166): OPNsense\Firewall\Api\DNatController->addRuleAction()
#6 /usr/local/opnsense/mvc/app/library/OPNsense/Mvc/Router.php(156): OPNsense\Mvc\Dispatcher->dispatch(Object(OPNsense\Mvc\Request), Object(OPNsense\Mvc\Response), Object(OPNsense\Mvc\Session))
#7 /usr/local/opnsense/mvc/app/library/OPNsense/Mvc/Router.php(139): OPNsense\Mvc\Router->performRequest(Object(OPNsense\Mvc\Dispatcher))
#8 /usr/local/opnsense/www/api.php(36): OPNsense\Mvc\Router->routeRequest('/api/firewall/d...', Array)
#9 {main}
[02-Feb-2026 15:15:06 Europe/London] TypeError: dom_import_simplexml(): Argument #1 ($node) must be of type object, null given in /usr/local/opnsense/mvc/app/models/OPNsense/Base/BaseModel.php:755
Stack trace:
#0 /usr/local/opnsense/mvc/app/models/OPNsense/Base/BaseModel.php(755): dom_import_simplexml(NULL)
#1 /usr/local/opnsense/mvc/app/models/OPNsense/Base/BaseModel.php(822): OPNsense\Base\BaseModel->internalSerializeToConfig()
#2 /usr/local/opnsense/mvc/app/controllers/OPNsense/Base/ApiMutableModelControllerBase.php(327): OPNsense\Base\BaseModel->serializeToConfig(false, true)
#3 /usr/local/opnsense/mvc/app/controllers/OPNsense/Base/ApiMutableModelControllerBase.php(498): OPNsense\Base\ApiMutableModelControllerBase->save(false, true)
#4 /usr/local/opnsense/mvc/app/controllers/OPNsense/Firewall/Api/DNatController.php(122): OPNsense\Base\ApiMutableModelControllerBase->addBase('rule', 'rule')
#5 /usr/local/opnsense/mvc/app/library/OPNsense/Mvc/Dispatcher.php(166): OPNsense\Firewall\Api\DNatController->addRuleAction()
#6 /usr/local/opnsense/mvc/app/library/OPNsense/Mvc/Router.php(156): OPNsense\Mvc\Dispatcher->dispatch(Object(OPNsense\Mvc\Request), Object(OPNsense\Mvc\Response), Object(OPNsense\Mvc\Session))
#7 /usr/local/opnsense/mvc/app/library/OPNsense/Mvc/Router.php(139): OPNsense\Mvc\Router->performRequest(Object(OPNsense\Mvc\Dispatcher))
#8 /usr/local/opnsense/www/api.php(36): OPNsense\Mvc\Router->routeRequest('/api/firewall/d...', Array)
#9 {main}
[02-Feb-2026 15:21:43 Europe/London] TypeError: dom_import_simplexml(): Argument #1 ($node) must be of type object, null given in /usr/local/opnsense/mvc/app/models/OPNsense/Base/BaseModel.php:755
Stack trace:
#0 /usr/local/opnsense/mvc/app/models/OPNsense/Base/BaseModel.php(755): dom_import_simplexml(NULL)
#1 /usr/local/opnsense/mvc/app/models/OPNsense/Base/BaseModel.php(822): OPNsense\Base\BaseModel->internalSerializeToConfig()
#2 /usr/local/opnsense/mvc/app/controllers/OPNsense/Base/ApiMutableModelControllerBase.php(327): OPNsense\Base\BaseModel->serializeToConfig(false, true)
#3 /usr/local/opnsense/mvc/app/controllers/OPNsense/Base/ApiMutableModelControllerBase.php(498): OPNsense\Base\ApiMutableModelControllerBase->save(false, true)
#4 /usr/local/opnsense/mvc/app/controllers/OPNsense/Firewall/Api/DNatController.php(122): OPNsense\Base\ApiMutableModelControllerBase->addBase('rule', 'rule')
#5 /usr/local/opnsense/mvc/app/library/OPNsense/Mvc/Dispatcher.php(166): OPNsense\Firewall\Api\DNatController->addRuleAction()
#6 /usr/local/opnsense/mvc/app/library/OPNsense/Mvc/Router.php(156): OPNsense\Mvc\Dispatcher->dispatch(Object(OPNsense\Mvc\Request), Object(OPNsense\Mvc\Response), Object(OPNsense\Mvc\Session))
#7 /usr/local/opnsense/mvc/app/library/OPNsense/Mvc/Router.php(139): OPNsense\Mvc\Router->performRequest(Object(OPNsense\Mvc\Dispatcher))
#8 /usr/local/opnsense/www/api.php(36): OPNsense\Mvc\Router->routeRequest('/api/firewall/d...', Array)
#9 {main}
Regards
Mike
Can you do a health check and/or reinstall the "opnsense" package from the firmware packages tab?
It looks like a damaged file on disk.
Cheers,
Franco
Here's the result of:
System > Firmware > Status > Run Audit > Health
***GOT REQUEST TO AUDIT HEALTH***
Currently running OPNsense 26.1_4 (amd64) at Mon Feb 2 17:34:21 GMT 2026
>>> Root file system: /dev/gpt/rootfs
>>> Check installed kernel version
Version 26.1 is correct.
>>> Check for missing or altered kernel files
No problems detected.
>>> Check installed base version
Version 26.1 is correct.
>>> Check for missing or altered base files
No problems detected.
>>> Check installed repositories
OPNsense (Priority: 11)
>>> Check installed plugins
No plugins found.
>>> Check locked packages
No locks found.
>>> Check for missing package dependencies
Checking all packages: .......... done
>>> Check for missing or altered package files
Checking all packages: .......... done
>>> Check for core packages consistency
Core package "opnsense" at 26.1_4 has 67 dependencies to check.
Checking packages: .................................................................... done
***DONE***
Regards
Mike
Re-installation pf "opnsense 26.1_4" package performed:
***GOT REQUEST TO REINSTALL***
Currently running OPNsense 26.1_4 (amd64) at Mon Feb 2 18:23:36 GMT 2026
Updating OPNsense repository catalogue...
OPNsense repository is up to date.
All repositories are up to date.
The following packages will be fetched:
New packages to be FETCHED:
opnsense: 26.1_4 (6 MiB: 100.00% of the 6 MiB to download)
Number of packages to be fetched: 1
The process will require 6 MiB more space.
6 MiB to be downloaded.
Fetching opnsense-26.1_4.pkg: .......... done
opnsense-26.1_4: already unlocked
Updating OPNsense repository catalogue...
OPNsense repository is up to date.
All repositories are up to date.
Checking integrity... done (0 conflicting)
The following 1 package(s) will be affected (of 0 checked):
Installed packages to be REINSTALLED:
opnsense-26.1_4
Number of packages to be reinstalled: 1
[1/1] Reinstalling opnsense-26.1_4...
[1/1] Extracting opnsense-26.1_4: .......... done
Stopping configd...done
Resetting root shell
Updating /etc/shells
Unhooking from /etc/rc
Unhooking from /etc/rc.shutdown
Updating /etc/shells
Registering root shell
Hooking into /etc/rc
Hooking into /etc/rc.shutdown
Starting configd.
>>> Invoking update script 'refresh.sh'
Flushing all caches...done.
Writing firmware settings: FreeBSD OPNsense
Writing trust files...done.
Scanning /usr/share/certs/untrusted for certificates...
Scanning /usr/share/certs/trusted for certificates...
Scanning /usr/local/share/certs for certificates...
certctl: No changes to trust store were made.
Writing trust bundles...done.
Configuring login behaviour...done.
Configuring cron...done.
Configuring system logging...done.
=====
Message from opnsense-26.1_4:
--
One step ahead, one step behind it, now you gotta run to get even
Checking integrity... done (0 conflicting)
Nothing to do.
***DONE***
I will now re-boot and try the DNAT configuration again.
Regards
Mike
Quote from: franco on February 02, 2026, 05:35:13 PMSystem: Firmware: Reporter should have logs. Better paste the PHP errors here than submitting them (it's a bit difficult to find them out of context).
Cheers,
Franco
Hi Franco,
I have run the health check (no problems) and re-installed the opnsense 26.1 package and upgraded to 26.1_4 and rebooted.
I still see the same problem when I try to add the Destination NAT with this PHP stack-trace:
[03-Feb-2026 12:29:19 Europe/London] TypeError: dom_import_simplexml(): Argument #1 ($node) must be of type object, null given in /usr/local/opnsense/mvc/app/models/OPNsense/Base/BaseModel.php:755
Stack trace:
#0 /usr/local/opnsense/mvc/app/models/OPNsense/Base/BaseModel.php(755): dom_import_simplexml(NULL)
#1 /usr/local/opnsense/mvc/app/models/OPNsense/Base/BaseModel.php(822): OPNsense\Base\BaseModel->internalSerializeToConfig()
#2 /usr/local/opnsense/mvc/app/controllers/OPNsense/Base/ApiMutableModelControllerBase.php(327): OPNsense\Base\BaseModel->serializeToConfig(false, true)
#3 /usr/local/opnsense/mvc/app/controllers/OPNsense/Base/ApiMutableModelControllerBase.php(498): OPNsense\Base\ApiMutableModelControllerBase->save(false, true)
#4 /usr/local/opnsense/mvc/app/controllers/OPNsense/Firewall/Api/DNatController.php(122): OPNsense\Base\ApiMutableModelControllerBase->addBase('rule', 'rule')
#5 /usr/local/opnsense/mvc/app/library/OPNsense/Mvc/Dispatcher.php(166): OPNsense\Firewall\Api\DNatController->addRuleAction()
#6 /usr/local/opnsense/mvc/app/library/OPNsense/Mvc/Router.php(156): OPNsense\Mvc\Dispatcher->dispatch(Object(OPNsense\Mvc\Request), Object(OPNsense\Mvc\Response), Object(OPNsense\Mvc\Session))
#7 /usr/local/opnsense/mvc/app/library/OPNsense/Mvc/Router.php(139): OPNsense\Mvc\Router->performRequest(Object(OPNsense\Mvc\Dispatcher))
#8 /usr/local/opnsense/www/api.php(36): OPNsense\Mvc\Router->routeRequest('/api/firewall/d...', Array)
#9 {main}
What to try next?
Regards
Mike
This is strange. Maybe there's something wrong in the initial data?
# pluginctl -v
Ignore some of the noise. We want to find DNat-specific complaints.
The rules aren't gone since they were not migrated, which could also point to the fact that the model doesn't like something in the initial data.
A full dump can be done with
# pluginctl -g nat
but don't paste it here. Just see if your hidden rules are still there and maybe we can find out why they are different.
Cheers,
Franco
Hi Franco,
Pluginctl -v results in a message per interface in the form:
root@gate:~ # pluginctl -v
OPNsense\Firewall\Alias.aliases.alias.__wan_network.name => The name must start with a letter or single underscore, be less than 32 characters and only consist of alphanumeric characters or underscores.
and pluginctl -g nat results in an empy set:
root@gate:~ # pluginctl -g nat
root@gate:~ #
... does that help?
Regards
Mike
Thanks, I think we can reproduce this now.
The question is why your nat section has gone. You should find it being dropped under System: Configuration: History and perhaps restore it manually ( I wouldn't advise reverting to that configuration).
Cheers,
Franco
The following should fix the write on your end without any prior data, but again not why it was lost.
# opnsense-patch https://github.com/opnsense/core/commit/40cb82128d
Cheers,
Franco
Hi Franco,
Thanks, patch applied and I am now able to add DNAT rules ;-)
I don't know where my previous NAT rules went... this is what I did:
1. Existing Server, working system (25.7_11) ... Backed up config
2. New (temp) server, installed 26.1, imported backup, upgraded to 26.1_4. Didn't explicitly test DNAT but everything seemed to be working.
3. Flattened exiting server, installed 26.1. Backed up temp server, imported to existing server. Upgraded to 26.1_4
Found that DNAT wasn't working. I guess somewhere along the way it broke...
All is good now. Thanks for the help. Have sent €50,00 donation.
Regards
Mike
Hi Mike,
Thank you. That's very kind. :)
We'll ship the change in 26.1.1 and likely issue new images (for assorted reasons) so that other users won't run into this.
Cheers,
Franco
I had the same problem here, and it worked.