Transfer Files Between Machines with rsync over SSH
Copy or move folders between two Linux machines on the same local network. SSH provides the connection and rsync does the transfer, resuming and skipping unchanged files on a re-run. The direction does not matter: the machine receiving the files runs the SSH server, and the machine sending the files runs rsync. Replace SOURCE_PATH, DEST_PATH, and the user and IP placeholders as needed.
Quick reference
Section titled “Quick reference”# on the receiving machine: enable SSH and find its IPsudo systemctl enable --now sshdip -4 addr show | grep inet
# on the sending machine: dry-run, then the real transfercd SOURCE_PATHrsync -avh --dry-run ./ "$USER"@192.168.1.17:DEST_PATH/rsync -avh --progress ./ "$USER"@192.168.1.17:DEST_PATH/
# verify on the receiving machine, then remove the source if this was a movedu -sh DEST_PATHrm -rf SOURCE_PATHEnable SSH on the receiving machine
Section titled “Enable SSH on the receiving machine”The machine that receives the files needs an SSH server running. Enable and start it in one step, then confirm it is active.
sudo systemctl enable --now sshdsystemctl status sshdActive: active (running) confirms it is up. On Debian or Ubuntu the unit and
package are named ssh / openssh-server instead of sshd.
Find the receiving machine IP
Section titled “Find the receiving machine IP”Read the local network address of the receiving machine. Use ip directly, since
a minimal install may not ship hostname -I.
ip -4 addr show | grep inetinet 127.0.0.1/8 scope host loinet 192.168.1.17/24 brd 192.168.1.255 scope global dynamic wlo1Use the LAN address, usually 192.168.1.x on the active interface. Do not use
127.0.0.1 (loopback) or a 172.x Docker bridge address. For more on reading
this output, see Find local network IP.
Test the SSH connection
Section titled “Test the SSH connection”From the sending machine, confirm SSH works before transferring anything.
ssh "$USER"@192.168.1.17On the first connection SSH asks whether to trust the host fingerprint; type
yes, then enter the receiving user’s password if prompted. Run exit once the
login succeeds. To connect with a short alias instead of the full user and IP,
add a host block to ~/.ssh/config (see
SSH into a local network device).
Understand the rsync trailing slash
Section titled “Understand the rsync trailing slash”A trailing slash on the source changes what gets copied. This is the most common source of mistakes.
| Source form | Result |
|---|---|
rsync SOURCE_DIR/ DEST_DIR/ |
Copies the contents of SOURCE_DIR into DEST_DIR |
rsync SOURCE_DIR DEST_PARENT/ |
Copies SOURCE_DIR itself into DEST_PARENT |
The reliable pattern is to cd into the source folder and copy ./, which avoids
mistyping a long source path.
Dry-run first
Section titled “Dry-run first”Always preview with --dry-run. rsync lists what it would copy without moving any
file content. The flags are -a (archive: recurse and preserve permissions and
timestamps), -v (verbose), and -h (human-readable sizes).
cd SOURCE_PATHrsync -avh --dry-run ./ "$USER"@192.168.1.17:DEST_PATH/If you see change_dir "...source..." failed: No such file or directory, the
source path is wrong. Confirm where you are with pwd before retrying.
Run the transfer
Section titled “Run the transfer”Once the dry-run output looks correct, drop --dry-run and add --progress to
watch larger files transfer.
rsync -avh --progress ./ "$USER"@192.168.1.17:DEST_PATH/rsync prints an incremental file list and finishes without an error code. Re-run the same command anytime to copy only what changed.
Mirror with –delete
Section titled “Mirror with –delete”By default rsync only ever adds and updates: it never removes anything on the destination. So if you delete a file on the source (or a tool renames or moves an attachment), the old copy still sits on the destination forever, and over repeated runs the destination accumulates orphans that are no longer in the real source.
--delete removes files on the destination that no longer exist on the source,
making the destination an exact mirror instead of an ever-growing pile.
# preview exactly what would be deleted before committingrsync -avh --progress --delete --dry-run ./ "$USER"@192.168.1.17:DEST_PATH/
# then run it for realrsync -avh --progress --delete ./ "$USER"@192.168.1.17:DEST_PATH/The key thing to understand: --delete deletes on the destination side. It is
safe only when the sync is strictly one-way and the source is the single source of
truth, so “make the destination match the source” is exactly what you want. It is
dangerous the moment that assumption breaks: if you point the direction the other
way, or keep unique files that live only on the destination, --delete wipes them.
Always run it with --dry-run the first time to see what it would remove.
Verify on the receiving machine
Section titled “Verify on the receiving machine”SSH into the receiving machine and confirm the destination size and a sample of the files before trusting the transfer.
ssh "$USER"@192.168.1.17
du -sh DEST_PATHfind DEST_PATH -maxdepth 2 -type f | head -50exitRemove the source after verifying
Section titled “Remove the source after verifying”Only after the destination checks out, delete the original on the sending machine. This step applies to a move, not a copy.
cd ~rm -rf SOURCE_PATHrm -rf is irreversible. Verify the destination first, and prefer an absolute
SOURCE_PATH (or cd ~ first) so a typo cannot delete the wrong folder.
Safety notes
Section titled “Safety notes”- Always dry-run before the real transfer.
- Prefer
cd SOURCE_PATHthenrsync ... ./ ...over typing a long source path. - Verify the destination before deleting the source.
- Do not add
--deleteunless you explicitly want the destination mirrored. - Be careful transferring secrets:
.envfiles, SSH keys, cloud credentials, age identities, browser profiles, and app state folders. - For project code, prefer Git. Use rsync over SSH for notes, archives, scans, and one-time folder moves.