ASA DHCP relay over a site-to-site VPN: a walkthrough
Walk the three legs of an ASA DHCP relay over a site-to-site VPN: the client interface, tunnel policy for relay traffic, and the reply to giaddr.
The relay works in three legs, and only the middle one crosses the VPN. A client broadcasts on the branch segment, the ASA turns that broadcast into a unicast request to the DHCP server, and the server answers the relay address rather than the client. Walk the legs in that order and most "relay is broken" cases resolve to a missing policy or a misread setroute line.
Leg one: enable relay on the client-facing interface
On the branch ASA, relay is a property of the interface that faces the clients. The server can be declared globally with its reachable interface, or under that client-facing interface so the routing table picks the egress. Those two forms are not interchangeable, and copying the wrong one is the first place a walkthrough goes sideways.
Check the running config before you change anything: which interface has relay enabled, which server form is present, and whether setroute is attached to the client interface. If the ASA also runs a DHCP server for another segment, stop and read the restriction list; server and relay cannot both be enabled on the same box.
The relay puts its own client-facing address into the gateway-address field. That address is what the server will answer, so it has to be reachable from the far site over the tunnel, not just locally.
Leg two: carry ASA-generated traffic over the tunnel
This is the step people skip. A policy-based site-to-site VPN is usually built for traffic between subnets, and the relay request is generated by the ASA itself. If the tunnel's access list and the crypto map only match branch-host-to-server-subnet flows, the relay packet may never enter the tunnel. Check the access list in both directions, not just the branch-to-server line.
Confirm the interesting traffic covers the ASA's relay source and the server address, and that the return direction is permitted as well. On a VTI-based design the routing decision is simpler, but relay support over VTI arrived in a specific release; the ASA DHCP guide identifies 9.14(1), so check the image before you copy a VTI example onto an older appliance.
A ping from the ASA to the server proves little on its own. It can succeed through a different path, with a different source address, or under a policy that the relay's packets do not match.
Leg three: read the reply and the setroute option
RFC 2131 says the server sends its reply to the address in giaddr when that field is nonzero. So the return path must route to the relay address, and the tunnel policy must permit the server-to-relay direction. If the request crossed but the offer never arrives, this is where to look.
Then separate two things that sound alike. The setroute keyword changes or adds the default-router option that the ASA hands to the client. It does not install a route on the ASA and it does not create VPN policy. A client that gets an address but cannot reach anything is often a setroute or scope problem, not a tunnel problem. Test it with a client that has no static gateway and watch which default router appears in the offer.
Read the offer end to end: offered address, mask, default router, DNS, and lease time. Then let the lease renew. A relay that works once and fails at renewal usually has a scope, lease, or return-path issue that the first exchange hid.
What I check before calling it fixed
Start from the client and capture the broadcast, then confirm the ASA relayed it with its own address as giaddr. On the far side, confirm the server saw that request and selected a scope that matches the branch. Back at the branch, confirm the client accepted the offer and can reach its gateway.
If any leg is silent, check the matching policy or route rather than adding another relay statement. The relay configuration is usually right by the time someone escalates; the tunnel policy or the return route is what changed.
Write the three legs into the change record: client-facing interface, VPN policy covering relay traffic, and the server's route back to giaddr. That record is what makes the next branch build a repeatable job instead of a debugging session. It also tells the next engineer which command output to collect first.