How to Use Rsync Over SFTP (Without SSH Shell Access): A Technical Workaround


10 views

When dealing with servers that restrict access to SFTP-only (without full SSH shell access), traditional rsync-over-SSH methods fail with protocol errors. The fundamental issue stems from rsync's requirement for a clean bidirectional communication channel that pure SFTP doesn't provide.

Attempting rsync -av /source ssh user@remotehost:/target/ on SFTP-only hosts typically yields:

protocol version mismatch -- is your shell clean?
rsync error: protocol incompatibility (code 2)
ssh-dummy-shell: Command not allowed

1. Using rclone as SFTP Wrapper

The most robust solution is using rclone which natively supports SFTP:

# First configure rclone
rclone config
# Create new SFTP remote
n) New remote
name: sftpbackup
type: sftp
host: your.sftp.server
user: yourusername
# Then sync:
rclone sync /local/path sftpbackup:remote/path

2. FUSE-based Approach (for Advanced Users)

While slower, this method provides rsync compatibility:

# Mount remote SFTP as local filesystem
sshfs -o sftp_server=/usr/lib/openssh/sftp-server user@host:/remote/path /local/mount
# Now use regular rsync
rsync -av /source /local/mount/target
# Remember to unmount after
fusermount -u /local/mount

For large file transfers:

  • rclone supports multi-threaded transfers with --transfers=N
  • Compression can be enabled with --compress
  • Consider --checksum for better sync accuracy
Tool SFTP Support Delta Transfer Speed
rclone Excellent Partial Fast
lftp Yes No Medium
csync2 With plugin Yes Slow

For mission-critical deployments, consider setting up a minimal SSH access with:

Match User backupuser
    ForceCommand internal-sftp
    ChrootDirectory /backups
    PermitTunnel no
    X11Forwarding no
    AllowTcpForwarding no

This allows rsync-over-SSH while maintaining security constraints.


When attempting to use rsync with servers that only allow SFTP access (no full SSH shell), you'll encounter the frustrating "protocol version mismatch" error. This occurs because rsync fundamentally relies on SSH shell access for its transport layer protocol handshake.

rsync -av /source sshuser@remotehost:/target/
# Output:
# protocol version mismatch -- is your shell clean?
# rsync error: protocol incompatibility (code 2)

The diagnostic test confirms the server's limitation:

ssh remotehost /bin/true > out.dat
# Contents of out.dat:
# ssh-dummy-shell: Command not allowed

Traditional rsync solutions like SSHFS mounting are impractical due to performance issues:

  • High latency on file operations
  • Unreliable for large transfers
  • No native delta-transfer benefits

Option 1: lftp Mirroring

A robust alternative that supports SFTP's delta-transfer capabilities:

lftp -u user,password sftp://remotehost -e "
mirror --reverse --delete --only-newer /local/path /remote/path;
quit"

Option 2: rclone with SFTP Backend

Configuration example for ~/.config/rclone/rclone.conf:

[sftp-remote]
type = sftp
host = remotehost
user = username
pass = password
key_pem = ~/.ssh/id_rsa

Sync command with checksum verification:

rclone sync -P --checksum /local/path sftp-remote:/remote/path

Option 3: Paramiko-based Python Script

For custom delta-transfer implementation:

import paramiko
from stat import S_ISDIR

def sftp_sync(local_path, remote_path):
    transport = paramiko.Transport(('host', 22))
    transport.connect(username='user', password='pass')
    sftp = paramiko.SFTPClient.from_transport(transport)
    
    for root, dirs, files in os.walk(local_path):
        remote_root = os.path.join(remote_path, os.path.relpath(root, local_path))
        try:
            sftp.stat(remote_root)
        except IOError:
            sftp.mkdir(remote_root)
            
        for file in files:
            local_file = os.path.join(root, file)
            remote_file = os.path.join(remote_root, file)
            local_mtime = os.path.getmtime(local_file)
            
            try:
                remote_attr = sftp.stat(remote_file)
                if local_mtime <= remote_attr.st_mtime:
                    continue
            except IOError:
                pass
                
            sftp.put(local_file, remote_file)

When forced to use SFTP instead of native rsync:

  • Expect 30-50% slower transfer speeds
  • Memory usage increases for large directory trees
  • No hard link preservation capability

For critical production systems, consider requesting temporary SSH access from administrators specifically for rsync operations.