| 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_2rsync 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:
mkdir -p /tmp/demo/subdirAdd one file at the top level and one inside the subdirectory:
echo "test" > /tmp/demo/file.txt && echo "nested" > /tmp/demo/subdir/nested.txtPush the folder to /tmp/ on the remote host:
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:
ssh root@192.168.56.220 'ls -R /tmp/demo'Sample output:
/tmp/demo:
file.txt
subdir
/tmp/demo/subdir:
nested.txtThe 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:
mkdir -p /tmp/demo-pullPull the remote folder into the staging directory:
scp -r root@192.168.56.220:/tmp/demo /tmp/demo-pull/List what arrived:
ls /tmp/demo-pull/demoSample output:
file.txt
subdirThe 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:
rsync -av /tmp/demo root@192.168.56.220:/tmp/Sample 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.04Pull from the remote host into a local staging directory — rsync follows the same subdirectory rule as scp when the destination already exists:
mkdir -p /tmp/demo-rsync-pullRun rsync with the remote path as the source:
rsync -av root@192.168.56.220:/tmp/demo /tmp/demo-rsync-pull/Sample 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.04Confirm the pull layout:
ls /tmp/demo-rsync-pull/demoSample output:
file.txt
subdirRemote 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:
mkdir -p /tmp/trailing-src/innerAdd a top-level file and one nested file:
echo top > /tmp/trailing-src/top.txt && echo inner > /tmp/trailing-src/inner/data.txtSync contents only — note the slash after trailing-src:
rsync -av /tmp/trailing-src/ root@192.168.56.220:/tmp/trailing-with/Sample 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.03Files land directly under the destination:
ssh root@192.168.56.220 'find /tmp/trailing-with -type f | sort'Sample output:
/tmp/trailing-with/inner/data.txt
/tmp/trailing-with/top.txtSync without the trailing slash on the source:
rsync -av /tmp/trailing-src root@192.168.56.220:/tmp/trailing-without/Sample 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.03Check the paths on the remote host:
ssh root@192.168.56.220 'find /tmp/trailing-without -type f | sort'Sample output:
/tmp/trailing-without/trailing-src/inner/data.txt
/tmp/trailing-without/trailing-src/top.txtWithout 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.

