Debug Mission Log #1 - OPNsense reply-to Breaking SSH Return Path

Debug Mission Log #1 ๐Ÿ› ๏ธ

OPNsense reply-to Breaking SSH Return Path

Environment: Proxmox homelab ยท OPNsense 25.1 ยท HP Z440
Symptom: SSH and RDP from home network into lab VMs failing silently
Root Cause: OPNsense reply-to directive misrouting return traffic
Status: โœ… Resolved


The Setup

At this point in the lab build, the network looked like this:

  • XFlow_Machine (192.168.0.51) โ€” main workstation on home network
  • OPNsense WAN (192.168.0.207) โ€” firewall sitting on the same home subnet
  • Lab VMs (172.16.0.x) โ€” isolated behind OPNsense LAN
  • Static route on XFlow: 172.16.0.0/24 โ†’ 192.168.0.207

OPNsense had internet access, VMs were reachable from inside the lab, and everything looked correct on paper.


The Symptom

Attempting SSH from XFlow into Ubuntu Server:

ssh alphax@172.16.0.10

Connection would hang and time out. No error โ€” just silence. RDP into Windows Server (172.16.0.30) behaved the same way.

Packets were clearly leaving XFlow and the static route was correct. Something was happening on the return path.


Diagnosing the Return Path

The key diagnostic clue came from OPNsense itself. Running this from the OPNsense shell temporarily disabled packet filtering:

pfctl -d

After disabling filtering, SSH worked immediately. Re-enabling filtering broke it again:

pfctl -e

That told the story clearly โ€” the problem wasn’t routing, it wasn’t the VMs, it wasn’t the static route. The problem was inside OPNsense’s firewall rule compilation.


Root Cause: reply-to

OPNsense automatically compiles WAN firewall rules with a reply-to directive:

reply-to (vtnet0 192.168.0.1)

This directive tells OPNsense to force all return traffic back toward the WAN gateway โ€” in this case, the TP-Link GE650 at 192.168.0.1.

Why this breaks the lab setup:

In a standard ISP-facing deployment, reply-to makes sense. If traffic arrives on the WAN from the internet, replies should go back out the WAN. But in this lab, OPNsense WAN sits on a private subnet (192.168.0.x) โ€” the same subnet as XFlow_Machine. When XFlow sends SSH traffic to 172.16.0.10, the packets enter through OPNsense WAN. The reply-to rule then forces return traffic toward the GE650 gateway instead of back to XFlow directly, breaking the return path.

The traffic flow looked like this:

XFlow (192.168.0.51)
  โ†’ OPNsense WAN (192.168.0.207)
    โ†’ Ubuntu (172.16.0.10)
      โ†’ return traffic forced to GE650 (192.168.0.1)  โŒ

Instead of:

XFlow (192.168.0.51)
  โ†’ OPNsense WAN (192.168.0.207)
    โ†’ Ubuntu (172.16.0.10)
      โ†’ return traffic back to XFlow (192.168.0.51)   โœ…

The Fix

OPNsense Web GUI:

Firewall โ†’ Settings โ†’ Advanced โ†’ Disable reply-to โ†’ โœ… Enable

Save and apply. Then flush existing connection states and re-enable filtering from the OPNsense shell:

pfctl -F states
pfctl -e

pfctl -F states clears any stale connections that were built with the old reply-to behavior. Without this step, existing sessions may continue to misbehave even after the setting change.


Result

ssh alphax@172.16.0.10
# Connected โœ…

ping 172.16.0.10
# 0% packet loss โœ…

RDP into Windows Server (172.16.0.30) also working.


What I Learned

reply-to is designed for ISP-facing WAN interfaces. When OPNsense WAN lives on a private subnet and you’re routing between two RFC 1918 networks, reply-to actively breaks the return path by introducing an unnecessary hop through the upstream gateway.

pfctl -d is a powerful diagnostic tool. Temporarily disabling the firewall to isolate whether a connectivity issue is routing-related or firewall-related is a fast way to narrow down the problem. If things work with filtering disabled, the firewall rules are your problem.

State tables persist after rule changes. Always flush states with pfctl -F states after significant firewall configuration changes. Old sessions carry the old rule behavior.


Environment Reference

Component Detail
Hypervisor Proxmox VE 8.4
Firewall OPNsense 25.1
OPNsense WAN vtnet0 โ†’ vmbr0 โ†’ 192.168.0.207
OPNsense LAN vtnet1 โ†’ vmbr1 โ†’ 172.16.0.1
XFlow_Machine 192.168.0.51
Ubuntu Server 172.16.0.10
Static Route 172.16.0.0/24 via 192.168.0.207