Binding cURL traffic to one outbound interface keeps API checks, webhook tests, and troubleshooting runs on the intended network path. That matters on hosts with multiple uplinks, VPN adapters, tunnels, or mixed IPv4 and IPv6 connectivity where the default route is not always the route a single request should use.
The --interface option binds the transfer socket to a chosen interface name or local address before the connection is made. When an interface name is used, cURL selects an eligible source address from that device. When a specific local address is used, the request is pinned to that exact source IP and the connection family follows that address.
Binding succeeds only when the named interface exists, the selected address is configured locally, and the target is reachable from that source. Current cURL documentation also notes that --interface does not steer DNS lookups, and Windows builds do not support interface names for this option, so address-based binding is the portable fallback there.
Steps to bind cURL to a network interface:
- List the interface names and local addresses that the host can actually use for outbound traffic.
$ ifconfig en0 en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500 inet 192.0.2.24 netmask 0xffffff00 broadcast 192.0.2.255On Linux, ip -brief address provides the same information in a shorter format. Use an interface or address that already has a working route to the target.
On Windows, --interface does not accept interface names. Bind with a configured local IP address or hostname instead.
- Bind the request to an interface name when the route is correct but the transfer must stay on one device.
$ curl --silent --show-error --output /dev/null \ --write-out 'local_ip=%{local_ip}\nhttp_code=%{http_code}\n' \ --interface en0 --ipv4 https://example.com local_ip=192.0.2.24 http_code=200Success is when the request completes and local_ip belongs to the chosen interface. The added --ipv4 keeps this example on one address family; omit it when either family on the interface is acceptable.
Current curl releases also document the explicit selector forms if!en0 and host!192.0.2.24, plus ifhost!en0!192.0.2.24 on curl 8.9.0 or later, for scripts that should fail on an unexpected interface or address match.
- Inspect the verbose connection transcript when a request must prove that the socket was bound before TLS or application data is sent.
$ curl --verbose --silent --show-error --output /dev/null \ --interface en0 --ipv4 https://example.com 2>&1 | \ grep -E '^\* Trying|^\* socket successfully bound|^\* Connected to' * Trying 198.51.100.24:443... * socket successfully bound to interface 'en0' * Connected to example.com (198.51.100.24) port 443
The socket successfully bound line is the decisive proof that cURL attached the client socket to the requested interface.
- Bind to a specific local address when the host has multiple addresses on the same interface or when the request must stay on one IP family.
$ curl --silent --show-error --output /dev/null \ --write-out 'local_ip=%{local_ip}\nhttp_code=%{http_code}\n' \ --interface 192.0.2.24 https://example.com local_ip=192.0.2.24 http_code=200Address binding is the cleanest way to force one exact source IP, especially when the same interface holds both IPv4 and IPv6 addresses.
- Fail fast on an address that is not configured locally before reusing the command in automation.
$ curl --silent --show-error --output /dev/null \ --write-out 'http_code=%{http_code}\n' \ --interface 198.51.100.10 https://example.com curl: (45) bind failed with errno 49: Can't assign requested address http_code=000Error 45 indicates that the requested interface or local address could not be bound. Check the interface name, the local address assignment, and the route from that source before retrying.
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.
