How to Copy a Directory Over SSH on Linux

Deepak Prasad
Tested on RHEL 10.2 (Coughlan) — vm1.lab.example (192.168.56.116) pushing and pulling to vm2.lab.example (192.168.56.220)
Package openssh-clients 9.9p1-25.el10_2
rsync 3.4.4-1.el10_2
Applies to RHEL, Rocky Linux, AlmaLinux, Fedora, Ubuntu, Debian, and other Linux hosts with OpenSSH and rsync installed
Privilege SSH login to the remote host (same user or root as needed)
Scope Recursive scp and rsync directory copy in both directions, path layout with trailing slashes, and verification. Does not cover rsync daemon mode, parallel copy tools, or SSH key setup.
Related guides scp command
rsync command
SCP vs rsync
ssh command
Copy files between servers

You copy a single file with scp or rsync the same way you copy a file locally — add -r to scp or use rsync archive mode when the source is a directory. The examples below use vm1.lab.example as the local host and vm2.lab.example (192.168.56.220) as the remote host.


Quick answer

Task Command pattern
Push a folder to a remote host scp -r /local/dir user@remote:/remote/parent/
Pull a folder from a remote host scp -r user@remote:/remote/dir /local/parent/
Push with rsync rsync -av /local/dir user@remote:/remote/parent/
Pull with rsync rsync -av user@remote:/remote/dir /local/parent/
Copy only directory contents (rsync) Trailing / on the source: rsync -av /local/dir/ user@remote:/remote/target/
Verify the result ls, find, or another listing on the destination host

Both tools use SSH for authentication and encryption. Replace user@remote with your account and hostname or IP.


Copy a folder to a remote server with scp

Use -r whenever the source is a directory. Create a small test tree on the machine you copy from:

bash
mkdir -p /tmp/demo/subdir

Add one file at the top level and one inside the subdirectory:

bash
echo "test" > /tmp/demo/file.txt && echo "nested" > /tmp/demo/subdir/nested.txt

Push the folder to /tmp/ on the remote host:

bash
scp -r /tmp/demo root@192.168.56.220:/tmp/

In an interactive terminal, scp normally prints a progress meter for each file. Use -q when you want to disable that meter. Either way, confirm the remote layout afterward:

bash
ssh root@192.168.56.220 'ls -R /tmp/demo'

Sample output:

output
/tmp/demo:
file.txt
subdir

/tmp/demo/subdir:
nested.txt

The remote path is /tmp/demo/ — the directory name matches the source.


Copy a folder from a remote server with scp

Pull the folder back onto the local host. When the destination is an existing directory, scp places the remote folder inside it:

bash
mkdir -p /tmp/demo-pull

Pull the remote folder into the staging directory:

bash
scp -r root@192.168.56.220:/tmp/demo /tmp/demo-pull/

List what arrived:

bash
ls /tmp/demo-pull/demo

Sample output:

output
file.txt
subdir

The copy lives at /tmp/demo-pull/demo/, not directly under /tmp/demo-pull/. To recreate /tmp/demo at the top level of /tmp/ on the local host, use /tmp/ as the destination instead of a staging directory that already exists.


Copy folders with rsync over SSH

rsync uses the same user@host:path syntax as scp. The -a flag enables archive mode: recursive copy plus preservation of common metadata such as permissions, ownership, timestamps, groups, and symbolic links. It does not automatically include ACLs, extended attributes, or hard links. -v lists each path as rsync runs.

Push the demo folder to the remote host:

bash
rsync -av /tmp/demo root@192.168.56.220:/tmp/

Sample output:

output
sending incremental file list
demo/
demo/file.txt
demo/subdir/
demo/subdir/nested.txt

sent 252 bytes  received 66 bytes  636.00 bytes/sec
total size is 12  speedup is 0.04

Pull from the remote host into a local staging directory — rsync follows the same subdirectory rule as scp when the destination already exists:

bash
mkdir -p /tmp/demo-rsync-pull

Run rsync with the remote path as the source:

bash
rsync -av root@192.168.56.220:/tmp/demo /tmp/demo-rsync-pull/

Sample output:

output
receiving incremental file list
demo/
demo/file.txt
demo/subdir/
demo/subdir/nested.txt

sent 78 bytes  received 256 bytes  222.67 bytes/sec
total size is 12  speedup is 0.04

Confirm the pull layout:

bash
ls /tmp/demo-rsync-pull/demo

Sample output:

output
file.txt
subdir

Remote rsync needs the rsync binary on both hosts. For a one-off copy, scp is enough; for jobs you run again, see SCP vs rsync.


rsync trailing slash: folder vs contents

rsync treats a trailing / on the source differently from scp. Build a small tree for the comparison:

bash
mkdir -p /tmp/trailing-src/inner

Add a top-level file and one nested file:

bash
echo top > /tmp/trailing-src/top.txt && echo inner > /tmp/trailing-src/inner/data.txt

Sync contents only — note the slash after trailing-src:

bash
rsync -av /tmp/trailing-src/ root@192.168.56.220:/tmp/trailing-with/

Sample output:

output
sending incremental file list
created directory /tmp/trailing-with
./
top.txt
inner/
inner/data.txt

sent 229 bytes  received 106 bytes  223.33 bytes/sec
total size is 10  speedup is 0.03

Files land directly under the destination:

bash
ssh root@192.168.56.220 'find /tmp/trailing-with -type f | sort'

Sample output:

output
/tmp/trailing-with/inner/data.txt
/tmp/trailing-with/top.txt

Sync without the trailing slash on the source:

bash
rsync -av /tmp/trailing-src root@192.168.56.220:/tmp/trailing-without/

Sample output:

output
sending incremental file list
created directory /tmp/trailing-without
trailing-src/
trailing-src/top.txt
trailing-src/inner/
trailing-src/inner/data.txt

sent 249 bytes  received 110 bytes  239.33 bytes/sec
total size is 10  speedup is 0.03

Check the paths on the remote host:

bash
ssh root@192.168.56.220 'find /tmp/trailing-without -type f | sort'

Sample output:

output
/tmp/trailing-without/trailing-src/inner/data.txt
/tmp/trailing-without/trailing-src/top.txt

Without the trailing slash, rsync copies the directory node and creates trailing-src/ on the destination. With the slash, it copies only what is inside the source directory into the target path.


Troubleshooting

Symptom Likely cause Fix
scp: ... No such file or directory Remote parent path missing Create the parent directory on the remote host or choose an existing path
Extra subdirectory on destination Destination was an existing directory Expected for scp -r remote:/dir /local/staging/ — adjust the local path or use rsync with a trailing / on the source when you want contents only
bash: rsync: command not found on remote rsync not installed on far host Install rsync on both hosts or use scp -r for a one-off copy
Wrong files on destination Source or destination path typo List both sides with ls or find and compare paths
Permission denied Wrong SSH user or key Confirm login with ssh user@host; use a user that can write the destination path
Host key or hostname mismatch Connecting by IP but keys expect a name Use the hostname from known_hosts or add the host key with ssh once before scp

References


Summary

Copying a directory over SSH means adding -r to scp or using rsync -av from the machine where you run the command. Push with scp -r /local/dir user@host:/remote/parent/; pull with the remote path first. scp normally shows transfer progress in an interactive terminal; verify the destination afterward with ls, find, or another listing when you need to confirm the layout.

rsync uses the same user@host:path syntax and lists each file as it runs. Archive mode preserves common metadata but not ACLs, xattrs, or hard links unless you add extra flags. When the destination is an existing directory, both tools create a subdirectory named after the source folder. rsync adds one more rule: a trailing / on the source copies contents only into the destination.

For repeated sync jobs, delta transfers, and exclude rules, prefer rsync and read SCP vs rsync before you pick a default tool for backups or deploy scripts.


Frequently Asked Questions

1. How do I copy a folder from local to remote Linux over SSH?

Use scp -r /path/to/local/dir user@remote:/path/on/remote/ or rsync -av /path/to/local/dir user@remote:/path/on/remote/. Both need SSH access to the remote host; scp requires -r for directories.

2. How do I copy a folder from remote to local with scp?

Run scp -r user@remote:/path/to/remote/dir /path/on/local/ from the machine where you want the copy to land. If the local destination is an existing directory, scp creates a subdirectory with the remote folder name inside it.

3. What is the difference between scp and rsync for directories?

scp copies the tree you name each time. rsync compares source and destination, lists each path as it syncs, and is better for repeated jobs. For a deeper comparison, see the scp vs rsync guide linked in Related guides.

4. Why did rsync create an extra directory on the destination?

When the source path has no trailing slash, rsync copies the directory node itself, so the destination gets a subdirectory named after the source. Add a trailing slash on the source when you want only the contents merged into the destination directory.
Omer Cakmak

Linux Administrator

Highly skilled at managing Debian, Ubuntu, CentOS, Oracle Linux, and Red Hat servers. Proficient in bash scripting, Ansible, and AWX central server management, he handles server operations on OpenStack, KVM, Proxmox, and VMware.

  • Debian
  • Ubuntu
  • Linux
  • Red Hat Enterprise Linux
  • Shell Script
  • System Administration