If you’re trying to copy files between servers with rsync over SSH and keep hitting permission errors, weird local directories, or cron jobs that just silently fail, you’re not alone.
Let’s walk through how to run rsync over SSH correctly, why /root is giving you a headache, and what usually breaks when you put rsync into crontab.
1. The basic idea: rsync over SSH
rsync is for copying/syncing files.
SSH is for connecting securely to another machine.
When you combine them, you get:
rsync [options] -e "ssh [ssh-options]" source destination
In the example from the question, the command looks like this:
rsync -avz \
-e "ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" \
--progress \
~/rocktree/dev/apps/countdown-timer/index.php \
192.81.208.45:/root/
Quick breakdown:
-a→ archive mode (permissions, timestamps, etc.)-v→ verbose output-z→ compress data during transfer-e "ssh ..."→ tell rsync to use SSH with specific options--progress→ show transfer progresssource→ local file pathdestination→ remote host and path
So far, so good. But then comes the error.
2. Fixing “Permission denied” when sending to /root/
The error you’re seeing is:
rsync: change_dir#1 "/root/" failed: Permission denied (13)
rsync error: errors selecting input/output files, dirs (code 3) at main.c(562) [Receiver=3.0.9]
rsync: connection unexpectedly closed (8 bytes received so far) [sender]
rsync error: error in rsync protocol data stream (code 12) at ...
Plain English: you don’t have permission to write to /root/ on the remote server.
/root is the home directory for the root user. Normal users are not allowed to write there. So if you run:
rsync ... 192.81.208.45:/root/
you are connecting as your default SSH user (often something like user), and that user is not allowed to touch /root.
To upload into /root, you must actually connect as root:
rsync -avz \
-e "ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" \
--progress \
~/rocktree/dev/apps/countdown-timer/index.php \
[email protected]:/root/
Key difference: [email protected] instead of just 192.81.208.45.
If that still fails, likely causes:
- Root login over SSH is disabled.
- Root has no valid SSH key/password set.
In that case, safest next step is usually: copy to a non-root user’s home directory instead, and then move it with sudo once you’re logged in.
Example flow:
- rsync to a normal user:
bash
rsync -avz -e "ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" \
--progress \
~/rocktree/dev/apps/countdown-timer/index.php \
[email protected]:/home/user/ - SSH into the server as that user.
- Use
sudo mvorsudo cpto move it into/rootif you truly need it there.
That way you respect permissions, and you’re not fighting with locked-down SSH settings.
3. Why rsync thinks you’re copying locally
Another problem mentioned: when using user@IP without a colon in the right place, rsync “thinks I’m sending it locally and creates a directory on my machine.”
This usually comes down to how rsync parses the destination.
Remote syntax needs to look like one of these:
user@host:/path/on/remote[email protected]:/root/
The colon : is important.
If rsync doesn’t see a proper HOST:PATH pattern, it may think you meant a local path and happily create a local directory instead.
So:
- ✅ Remote:
[email protected]:/var/www/ - ❌ Local (wrong for remote):
[email protected]/var/www/
If you see rsync creating user@IP as a directory locally, check the colon.
4. About using ssh://user@IP (and why it hangs)
Trying:
ssh://user@IPssh://IP:/root/
and seeing it “get stuck” with no errors is another clue.
rsync does not need the ssh:// URL-style prefix when you’re already telling it to use SSH with -e "ssh ...".
Typical remote form is just:
rsync ... user@IP:/path/on/remote
No ssh://.
If you add that ssh:// prefix, rsync may not understand what you mean and can appear to hang or just not behave as you expect.
So if things feel stuck and weird:
- Drop the
ssh://prefix. - Make sure there’s exactly one colon after the host.
Example of a clean command:
rsync -avz \
-e "ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" \
--progress \
~/rocktree/dev/apps/countdown-timer/index.php \
[email protected]:/home/user/
5. Running rsync over SSH in crontab
Last piece of the puzzle: “how to run rsync over ssh in a crontab… script works fine when executed but when placed in crontab it doesn’t work at all.”
This is super common with cron.
The main reasons are:
- Different environment (PATH, HOME, etc.).
- SSH keys or host checking acting differently in non-interactive mode.
- Not using full paths to executables.
You already tried “full path to rsync, ssh etc.” which is good, but let’s go over the general checklist.
5.1 Use full paths for everything
Cron doesn’t know your regular shell PATH.
Instead of:
rsync -avz -e "ssh ..." ...
use something like (paths are just examples):
/usr/bin/rsync -avz \
-e "/usr/bin/ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" \
--progress \
/full/path/to/local/file \
[email protected]:/full/path/on/remote/
Same rule for any script you call from cron: bash /full/path/to/script.sh, not ./script.sh.
5.2 Use full paths for files and dirs
In cron, relative paths (~/something or ./something) can point somewhere else than you expect.
Change things like:
~/rocktree/dev/apps/countdown-timer/index.php
into:
/home/youruser/rocktree/dev/apps/countdown-timer/index.php
Cron doesn’t expand ~ the way your interactive shell does, and it may run from / as the working directory.
5.3 Check SSH access from non-interactive context
If your rsync command depends on SSH keys, make sure SSH works without asking for passwords or prompts.
From the same user that owns the crontab, run:
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null [email protected]
If it prompts for a password or passphrase, cron will just hang or fail.
You’d need either:
- A key without a passphrase, or
- An SSH agent that’s properly initialized before cron (trickier), or
- Use some other auth method that doesn’t require interaction.
5.4 Log cron output to see errors
Cron failures are annoying because they’re silent.
Add logging to your cron line so you can see what’s going on.
Example crontab line:
0 * * * * /usr/bin/rsync -avz -e "/usr/bin/ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" \
/full/path/to/local/file \
[email protected]:/full/path/on/remote/ \
>> /var/log/rsync-cron.log 2>&1
Then you can open /var/log/rsync-cron.log and see exactly what rsync or ssh complained about.
6. Safety tips: permissions, root, and testing
A few quick safety notes so you don’t accidentally break things while experimenting with rsync and SSH.
-
Be careful with
/root
If you don’t specifically need files in/root, consider using a normal user’s home dir. It simple avoids permission problems and keeps root access tighter. -
Test with a small file first
Before syncing a big directory, just send one small file and confirm it lands where you expect. Saves a lot of time and surprises. -
Use
--progresswhile debugging
You already used--progress— keep that during testing so you can see whether rsync is actually moving data or hanging. -
Double-check your destination path
One typo and rsync may create weird directories. Make sureuser@host:/path/is really what you want, especially when running under cron.
7. Quick summary and next steps
- “Permission denied (13)” for
/root/→ you must connect asroot, or copy to a normal user and move withsudolater. - rsync creating local directories named like
user@IP→ you’re missing the colon:in the destination, or the format is off. ssh://user@IP→ not needed here; stick withuser@IP:/pathwhen using-e ssh.- Cron job works manually but not in crontab → use full paths for
rsync,ssh, and all files; make sure SSH auth doesn’t require interaction; log output to a file.
Once you get the pattern right, rsync over SSH becomes one of those boring tools that “just works” in the background.
If this saved you time, bookmark CrushEdge for more fixes.
No Comments