How to Bind Rsync to a Specific Network Interface Like SCP’s BindAddress Option


2 views

When dealing with multi-homed systems (servers with multiple network interfaces), we often need to control which interface our transfers use. While scp makes this straightforward with its -oBindAddress parameter, rsync presents a more complex scenario.

The --address option in rsync doesn't actually bind to a local interface - it only specifies which IP address to advertise to the remote server. This explains why your traffic still goes through eth0 despite setting --address=192.168.100.1.

1. Using SSH as Transport with BindAddress

Since rsync often uses SSH as transport, we can leverage SSH's binding capability:

rsync -e 'ssh -o BindAddress=192.168.100.1' source destination

2. Network Namespace Approach

For more complex scenarios, Linux network namespaces provide isolation:

# Create namespace
ip netns add rsync-ns

# Move interface to namespace
ip link set eth1 netns rsync-ns

# Execute rsync in namespace
ip netns exec rsync-ns rsync [options]

3. Route-based Solution

Add a specific route for your destination:

ip route add [remote-ip] dev eth1 src 192.168.100.1

Always verify your binding works:

tcpdump -i eth1 host [remote-ip] and port 873

When running rsync as a daemon, you can bind to specific interfaces:

rsync --daemon --address=192.168.100.1

This actually works because the daemon mode properly binds to the specified address.


When dealing with multi-homed systems (servers with multiple network interfaces), there are situations where you need to explicitly control which network interface a transfer uses. While scp provides the convenient -oBindAddress option, rsync presents a more complex scenario.

The --address parameter in rsync doesn't work the same way as scp's binding option. Rsync's --address only specifies which IP to advertise to the remote server, not which local interface to bind to.


# This won't actually bind to the interface:
rsync --address=192.168.100.1 /local/path user@remote:/remote/path

Method 1: Using SSH as Transport with BindAddress

Since rsync often uses SSH as transport, you can leverage SSH's binding capability:


rsync -e "ssh -o BindAddress=192.168.100.1" /local/path user@remote:/remote/path

Method 2: Network Namespace Approach

For more advanced control, create a network namespace that only sees your desired interface:


# Create namespace
sudo ip netns add rsync-ns

# Move interface to namespace
sudo ip link set eth1 netns rsync-ns

# Execute rsync within namespace
sudo ip netns exec rsync-ns rsync /local/path user@remote:/remote/path

Method 3: Routing Table Manipulation

Add specific routes to force traffic through your desired interface:


# Add route for remote server
sudo ip route add remote.server.ip via 192.168.100.1 dev eth1

# Then run normal rsync
rsync /local/path user@remote:/remote/path

Verify your binding with tcpdump on both interfaces:


# On interface you want to use
sudo tcpdump -i eth1 host remote.server.ip

# On interface you want to avoid
sudo tcpdump -i eth0 host remote.server.ip

For direct rsync connections (not over SSH), create a wrapper:


#!/bin/bash
socat TCP4-LISTEN:873,bind=192.168.100.1,fork TCP4:remote.server.ip:873

Then point rsync to your local wrapper:


rsync --port=873 localhost::module/path /local/destination