I had set this issue aside while I was dealing with bigger things, but with OPNSense 26.7.2 this is now resolved via Endpoint-independent NAT.
That's it, no UPnP necessary.
- Gaming device IPs added to a firewall alias ("GamingHosts").
- Source NAT set to hybrid mode.
- Add a Source NAT rule:
- Interface: WAN/IPv4/UDP
- Source address: GamingHosts
- Endpoint independent: Checked
- I had previously set up a Static Port rule. Not sure if it's still necessary but I kept it for TCP and just removed UDP to avoid conflict:
- Interface: WAN/IPv4/TCP
- Source address: GamingHosts
- Static-port: Checked
That's it, no UPnP necessary.
"