Troubleshooting SCP File Transfer Stalls Over VPN Connections


3 views

When transferring files via SCP over VPN, many developers encounter mysterious stalls where the transfer suddenly stops progressing. The debug output typically shows repeated rcvd adjust messages without actual data transfer:

debug2: channel 0: rcvd adjust 131072
debug2: channel 0: rcvd adjust 131072

From my experience working with remote servers, these are the most frequent culprits:

  • VPN connection instability or MTU issues
  • TCP window scaling problems
  • SSH connection keepalive timeout
  • Network congestion control algorithms

Here are the most effective fixes I've found through trial and error:

1. Adjust SSH Configuration

Add these parameters to your /etc/ssh/ssh_config or ~/.ssh/config:

Host *
    ServerAliveInterval 60
    TCPKeepAlive yes
    Compression no
    IPQoS throughput

2. Use Alternative Transfer Methods

When SCP fails consistently, consider these alternatives:

Rsync with partial transfers:

rsync -avz --partial --progress -e ssh user@remote:/path/to/files /local/path

Tar over SSH:

ssh user@remote "tar czf - /path/to/files" | tar xzvf - -C /local/path

3. Network-Level Optimizations

Try adjusting MTU size and TCP parameters:

# Set MTU (adjust size based on your VPN)
ifconfig eth0 mtu 1400

# Optimize TCP stack
sysctl -w net.ipv4.tcp_window_scaling=1
sysctl -w net.ipv4.tcp_sack=1

For scheduled nightly transfers, implement a retry mechanism:

#!/bin/bash

MAX_RETRIES=3
RETRY_DELAY=60

for ((i=1; i<=$MAX_RETRIES; i++)); do
    scp -o ConnectTimeout=30 -o ServerAliveInterval=60 user@remote:/remote/path /local/path
    if [ $? -eq 0 ]; then
        echo "Transfer completed successfully"
        exit 0
    fi
    echo "Attempt $i failed, retrying in $RETRY_DELAY seconds..."
    sleep $RETRY_DELAY
done

echo "All transfer attempts failed"
exit 1

Implement proper logging to diagnose persistent issues:

{
    "timestamp": "$(date +%Y-%m-%dT%H:%M:%S)",
    "transfer_size": "$(du -sh /local/path | cut -f1)",
    "duration": "$SECONDS seconds",
    "status": "$([ $? -eq 0 ] && echo "success" || echo "failed")",
    "network_stats": "$(ping -c 4 remote.server | grep 'packet loss')"
}

When transferring small to medium-sized files (typically tens of megabytes) via SCP over VPN connections, many administrators encounter unexplained stalls. The transfer begins normally but halts after a few seconds, showing repeated debug messages about channel adjustments:

debug2: channel 0: rcvd adjust 131072
debug2: channel 0: rcvd adjust 131072

The "rcvd adjust" messages indicate SSH flow control adjustments where the receiving end is trying to throttle the data flow. This typically happens when there's:

  • Network latency spikes
  • VPN packet fragmentation issues
  • MTU mismatches
  • TCP window scaling problems

Here are proven solutions ranked by effectiveness:

# Solution 1: Use rsync with compression and partial transfers
rsync -avz --partial --progress /local/path/ user@remote:/remote/path/

# Solution 2: Force SCP to use older cipher
scp -c aes128-cbc -oIPQoS=throughput file.txt user@host:/path/

# Solution 3: Adjust TCP parameters
echo "net.ipv4.tcp_window_scaling = 0" >> /etc/sysctl.conf
sysctl -p

For persistent cases, modify your SSH config:

Host *
    IPQoS throughput
    ServerAliveInterval 60
    Compression yes
    Ciphers aes128-ctr,aes192-ctr,aes256-ctr
    MACs hmac-sha1

If you're using OpenVPN, add these to your config:

tun-mtu 1500
mssfix 1460
fragment 0
link-mtu 1500

When SCP simply won't cooperate:

# Using lftp for resilient transfers
lftp -e "mirror -R /local/path /remote/path" sftp://user:password@host

# Using tar over ssh
tar czf - /local/path | ssh user@host "tar xzf - -C /remote/path"