Updated: 8 October 2026 · Applies to: OpenSSH 10.2p1 (Ubuntu 26.04) and 9.9p1 (AlmaLinux 10), rsync 3.4.1 and 3.5.0
To copy a folder recursively, use scp -r. scp has no option to exclude files and no option to skip files that already exist: it always sends everything and overwrites what is on the other side. For either job, use rsync over SSH with --exclude or --ignore-existing.
Copy a folder recursively with scp
scp -r /home/me/site user@server:/var/www/
Where the folder ends up depends on whether the target already exists. We ran each case and listed the result on the receiving side:
- Target folder exists:
scp -r site user@server:/backup/wwwcreates/backup/www/site/index.phpand so on. - Target does not exist:
scp -r site user@server:/backup/new-sitecreates/backup/new-site/index.php, so the folder is copied under the new name. - Trailing slash:
scp -r site/behaves exactly likescp -r site. Unlike rsync, the slash does not mean "contents only". - Contents only:
scp -r site/* user@server:/backup/www/copies what is insidesite, but the shell's*skips hidden files such as.htaccess.
Useful extras: -p keeps modification times and file modes, -P 2222 (capital P) sets the SSH port and -C turns on compression. According to the OpenSSH manual, scp -r follows symbolic links it finds in the tree, and since OpenSSH 9.0 scp uses the SFTP protocol by default (-O switches back to the legacy protocol for old servers). There is more on recursive copies in How to Copy Folders with scp -r.
Skip files that already exist
scp cannot do this. In our test we changed index.php on the server, ran scp -r again, and the server copy was overwritten. Use rsync instead:
- Install rsync on both machines if it is missing:
sudo apt install rsync(Ubuntu, Debian) orsudo dnf install rsync(AlmaLinux, Rocky Linux, Fedora). - Preview with a dry run (
-n) to see what would be sent. - Run the real copy:
rsync -av --ignore-existing /home/me/site/ user@server:/backup/www/
Real output from our test, where index.php already existed on the server:
sending incremental file list ./ error.log cache/ cache/c.tmp img/ img/logo.png sent 362 bytes received 92 bytes 908.00 bytes/sec total size is 12 speedup is 0.03
index.php is not in the list, and the edited copy on the server was kept. Three related choices:
--ignore-existing: never touch a file that exists on the receiver, even if yours is newer.--update(-u): skip files that are newer on the receiver, but update older ones.- Plain
rsync -av: skips files that are already identical (same size and modification time). Our second run of the same command sent no files at all, which makes rsync the better tool for resuming a large copy.
For more on this, see how to sync only new or changed files with rsync.
Exclude files and folders
rsync -av --exclude='*.log' --exclude='cache/' /home/me/site/ user@server:/backup/www/
sending incremental file list created directory /backup/www ./ index.php new.txt img/ img/logo.png
- Patterns are matched relative to the source folder. A trailing
/(cache/) matches folders only. - For many patterns, put one per line in a file and use
--exclude-from=exclude.txt. - A trailing
/on the rsync source (site/) copies the folder's contents; without it, rsync createssiteinside the target. - If SSH listens on another port, add
-e 'ssh -p 2222'. See rsync with a non-standard SSH port.
If you can only use scp
When rsync is not available on the server, you have two options that both worked in our tests.
Let Bash pick the files with an extended glob. This sends everything in site except the cache folder and .log files:
shopt -s extglob scp -r site/!(cache|*.log) user@server:/backup/www/
Or pack the folder with tar, which has its own --exclude, and unpack it on the server in one stream:
tar czf - --exclude='*.log' --exclude='site/cache' site | ssh user@server 'tar xzf - -C /backup'
Both send everything again each time, so for regular copies rsync is still the better choice. For more rsync options, see 13 rsync command examples.
Ucartz services for this topic
- KVM VPS hosting: NVMe SSD and full root access, with Free Basic Managed Support.
- Unmanaged dedicated servers: full root access and free IPMI KVM, with Free Basic Managed Support.
- Linux server management: hardening, patching, monitoring and automation for Ubuntu, Debian, RHEL and AlmaLinux.
