SCP vs SFTP vs rsync
All three tools transfer files over SSH. The difference is in what they are optimised for: SCP is a quick non-interactive copy, SFTP is an interactive session for browsing and managing files, and rsync is a synchronisation tool that only sends changes. Knowing which to reach for makes transfers faster and more reliable.
SCP: simple one-shot copy
SCP works like cp but across a network. It opens an SSH connection, copies the files, and exits. No interaction required.
# Copy a local file to a remote server
scp file.txt user@hostname:/remote/path/
# Copy a file from remote to local
scp user@hostname:/remote/path/file.txt ./
# Copy to the remote home directory
scp file.txt user@hostname:
# Copy to a specific directory name
scp file.txt user@hostname:~/uploads/
# Copy a directory recursively
scp -r ./mydir user@hostname:/remote/path/
# Specify a port (note: capital P, not lowercase)
scp -P 2222 file.txt user@hostname:/path/
# Specify a key
scp -i ~/.ssh/mykey file.txt user@hostname:/path/
# Copy between two remote servers (via your local machine)
scp user1@host1:/path/file.txt user2@host2:/path/
# Show progress
scp -v file.txt user@hostname:/path/
# Preserve timestamps and permissions
scp -p file.txt user@hostname:/path/
# Compress during transfer
scp -C largefile.tar user@hostname:/path/
# Limit bandwidth (in Kbps)
scp -l 1000 bigfile.tar user@hostname:/path/
SCP limitations
SCP does not resume interrupted transfers. If a large file transfer fails halfway, you start over. For large files, use rsync instead.
SCP also does not handle symbolic links consistently when copying directories. Use rsync -a if you need to preserve symlinks.
SFTP: interactive file management
SFTP opens an interactive session where you can browse directories, transfer files, rename, delete, and manage permissions. Think of it as an SSH-powered FTP client.
# Open an interactive SFTP session
sftp user@hostname
# Specify a port
sftp -P 2222 user@hostname
# Specify a key
sftp -i ~/.ssh/mykey user@hostname
SFTP interactive commands
Once connected, you get an sftp> prompt:
sftp> ls # list remote directory
sftp> ls -la # detailed listing
sftp> pwd # show remote working directory
sftp> cd /var/log # change remote directory
sftp> lcd ~/Downloads # change LOCAL directory
sftp> lpwd # show local working directory
sftp> get remote-file.txt # download a file
sftp> get remote-file.txt local-copy.txt # download with rename
sftp> get -r remotedir # download a directory recursively
sftp> put local-file.txt # upload a file
sftp> put local-file.txt /remote/path/renamed.txt
sftp> put -r localdir # upload a directory
sftp> mkdir newdir # create remote directory
sftp> rmdir emptydir # remove remote directory
sftp> rm file.txt # delete remote file
sftp> rename old.txt new.txt
sftp> chmod 644 file.txt # change remote permissions
sftp> chown 1000 file.txt # change remote owner (by UID)
sftp> df -h # remote disk usage (if supported)
sftp> help # list all commands
sftp> exit # close session
sftp> quit # same as exit
Non-interactive SFTP via batch file
# Create a batch file
cat << 'EOF' > sftp-commands.txt
cd /var/backups
put database.sql.gz
ls -la
EOF
# Run the batch
sftp -b sftp-commands.txt user@hostname
SFTP clients
For a graphical experience, many tools speak SFTP:
- FileZilla: free, cross-platform, mature
- Cyberduck: macOS and Windows
- WinSCP: Windows-focused, has a scripting mode
- Thunar / Nautilus / Dolphin: Linux desktop file managers support
sftp://URIs
# Open in Nautilus (GNOME file manager)
# Type this in the address bar: sftp://user@hostname/path
# or from terminal:
nautilus sftp://user@hostname
rsync: synchronisation and efficient transfer
rsync is the right tool when you want to keep two directories in sync, resume interrupted transfers, or avoid re-sending unchanged files.
# Basic syntax
rsync [options] source destination
# Sync a local directory to a remote server
rsync -avz ./mydir/ user@hostname:/remote/path/
# Sync remote to local
rsync -avz user@hostname:/remote/path/ ./localdir/
# The trailing slash on source matters:
# ./mydir/ -- copy the CONTENTS of mydir into /remote/path/
# ./mydir -- copy mydir ITSELF into /remote/path/ (creates /remote/path/mydir/)
Common rsync flags
# -a archive mode (preserves permissions, times, symlinks, owner, group)
# -v verbose output
# -z compress during transfer
# -P show progress + support resume (equivalent to --partial --progress)
# -n dry run (show what would happen without doing it)
# --delete delete files at destination that no longer exist at source
# The most common transfer command
rsync -avzP ./source/ user@hostname:/destination/
# Dry run first to preview
rsync -avzn --delete ./source/ user@hostname:/destination/
# Run the real transfer
rsync -avz --delete ./source/ user@hostname:/destination/
Resume an interrupted transfer
# --partial keeps partially transferred files, allowing resume
rsync -avz --partial user@hostname:/path/largefile.tar ./
# -P combines --partial and --progress
rsync -avzP user@hostname:/path/largefile.tar ./
Excluding files
# Exclude a pattern
rsync -avz --exclude='*.log' ./source/ user@hostname:/destination/
rsync -avz --exclude='node_modules' --exclude='.git' ./project/ user@hostname:/app/
# Exclude from a file
rsync -avz --exclude-from='.rsyncignore' ./source/ user@hostname:/dest/
# Include some excluded files (evaluated in order)
rsync -avz --include='important.log' --exclude='*.log' ./source/ user@hostname:/dest/
Non-standard SSH port
# Use -e to specify the SSH command
rsync -avz -e "ssh -p 2222" ./source/ user@hostname:/destination/
# With a key
rsync -avz -e "ssh -p 2222 -i ~/.ssh/mykey" ./source/ user@hostname:/dest/
rsync for local backups
rsync is equally useful for local copies (no SSH required):
# Local backup of a directory
rsync -avz --delete /home/colton/ /media/backup/colton/
# Mirror with --link-dest for incremental hardlink backups
# (each snapshot only stores changed files; unchanged files are hardlinks)
rsync -a --link-dest=/backup/latest/ /home/ /backup/$(date +%Y-%m-%d)/
ln -nsf /backup/$(date +%Y-%m-%d) /backup/latest
Choosing the right tool
| Scenario | Best tool |
|---|---|
| Copy a single file quickly | scp |
| Copy a few files, no frills | scp |
| Browse remote directories interactively | sftp |
| Upload/download from a GUI | SFTP client (FileZilla, etc.) |
| Sync a large directory, only changed files | rsync |
| Resume an interrupted large transfer | rsync -P |
| Backup with delete (mirror) | rsync --delete |
| Keep a remote server directory in sync | rsync (cron or systemd timer) |
| Transfer and preserve all metadata | rsync -a |
Frequently Asked Questions
What is the difference between SCP, SFTP, and rsync?
SCP (Secure Copy Protocol) is a simple non-interactive file copy tool over SSH. You specify source and destination on the command line and it copies. SFTP (SSH File Transfer Protocol) is an interactive file manager over SSH — you connect to a session and can browse directories, upload, download, rename, and delete files. rsync is a synchronisation tool that only transfers the differences between source and destination, making it much faster for large files or directories that change incrementally. SCP is the easiest to learn; rsync is the right choice for backups and large transfers; SFTP is best for interactive browsing and management.
When should I use rsync instead of SCP?
Use rsync when: you are transferring large files or directories and the transfer might fail partway (rsync can resume); you are keeping two directories in sync and only want to transfer changed files; you want to delete files at the destination that were deleted at the source (—delete flag); or you want to preserve all file metadata including permissions, timestamps, and symlinks (-a archive mode). Use SCP for simple one-off copies where the overhead of rsync’s delta comparison is not needed.
How does rsync delta transfer work?
rsync uses a rolling checksum algorithm to identify which parts of a file have changed since the last transfer. It divides the file into blocks, computes a fast checksum for each block on the receiver side, sends these to the sender, and the sender then only transmits the blocks that differ. For files with small changes (like log files or databases), this means transferring a fraction of the total file size. The first transfer of a file always sends the full content; subsequent transfers only send the changed portions.
What does the rsync -avz flag combination mean?
The -a flag (archive mode) is shorthand for -rlptgoD: recursive (-r), preserve symlinks (-l), preserve permissions (-p), preserve timestamps (-t), preserve group (-g), preserve owner (-o), and preserve device files (-D). The -v flag (verbose) prints each file being transferred. The -z flag enables compression during transfer, which reduces bandwidth at the cost of CPU. So rsync -avz is: recursive archive with verbose output and compression. A useful addition is —progress to show per-file transfer progress, or -P which combines —progress and —partial (resume support).
Is SFTP the same as FTP?
SFTP and FTP share a similar user experience (both are interactive file transfer clients) but they are completely different protocols. FTP is an older protocol that sends credentials and data in plaintext, is insecure, and requires firewall exceptions for passive mode. SFTP is a subsystem of SSH — it runs inside an SSH connection and inherits all of SSH’s security properties including encryption and key-based authentication. SFTP is far preferable to FTP for any serious use. The older FTPS (FTP over TLS) is a third option that adds encryption to FTP, but SFTP is simpler to configure and is already available on any server running SSH.
How do I transfer files to a server with a non-standard SSH port?
For SCP, use the -P flag (capital P, unlike SSH which uses lowercase -p): scp -P 2222 file.txt user@host:/path/. For rsync, specify the SSH command with —rsh or -e: rsync -av -e “ssh -p 2222” ./dir user@host:/path/. For SFTP, use the -P flag: sftp -P 2222 user@host. If you have the host configured in ~/.ssh/config with the correct port, all three tools will use the config file and you do not need to specify the port on the command line.