Recently while automating server synchronization between ServerA and ServerB using rsync in root's crontab, I encountered this frustrating error:
rsync error: unexplained error (code 255) at io.c(600) [sender=3.0.6]
rsync: connection unexpectedly closed (0 bytes received so far) [receiver]
What makes this particularly puzzling is that the identical rsync command works perfectly when executed manually in the terminal, but fails when run through cron.
After extensive testing, I found these critical points:
- The error only occurs when running through cron (both system crontab and user crontab)
- SSH connectivity between servers is properly configured (works interactively)
- Both servers are running rsync 3.0.6
- Rebooting both servers didn't resolve the issue
The primary issue stems from environment differences between interactive shells and cron jobs. Specifically:
- Cron provides a minimal environment - many environment variables (like PATH) are missing
- SSH agent forwarding isn't available in cron by default
- Terminal vs non-terminal SSH sessions behave differently
Here's the fixed version that worked in my crontab after debugging:
#!/bin/bash
# Set full path to rsync
RSYNC="/usr/bin/rsync"
# Specify full path to SSH key
SSH_KEY="/root/.ssh/id_rsa"
# Source and destination with full paths
SRC="user@serverA:/path/to/source/"
DEST="user@serverB:/path/to/dest/"
# The working rsync command
$RSYNC -azP --delete -e "ssh -i $SSH_KEY -o StrictHostKeyChecking=no" $SRC $DEST
If the above doesn't work, try these steps:
# 1. Test SSH connection in cron context
* * * * * /usr/bin/ssh -v user@serverB echo "test" >> /tmp/ssh_test.log
# 2. Capture full environment in cron
* * * * * /usr/bin/env > /tmp/cron_env.log
# 3. Compare with your interactive shell environment
env > /tmp/shell_env.log
To avoid similar issues in the future:
- Always use full paths to binaries in cron scripts
- Explicitly set environment variables needed by your script
- Consider using a wrapper script that sources your profile
- Log all cron job output for debugging
Example wrapper script approach:
#!/bin/bash
source /root/.bash_profile
# Rest of your rsync commands here
I recently encountered an infuriating scenario where my bidirectional rsync script worked perfectly when executed manually, but failed consistently when run through sudo crontab
with error 255. Here's what I discovered and how I fixed it.
rsync error: unexplained error (code 255) at io.c(600) [sender=3.0.6]
rsync: connection unexpectedly closed (0 bytes received so far) [receiver]
Error 255 in rsync typically indicates an SSH connection problem. The key insight here is that cron jobs run with a minimal environment, often missing critical SSH configuration that works in interactive shells.
When debugging, I discovered several environmental differences:
- Cron doesn't load your
.bashrc
or.bash_profile
- SSH agent forwarding isn't available
- Environment variables like PATH may be different
- Home directory (
~
) resolution might not work as expected
The most reliable fix was to make the SSH connection explicit in the rsync command. Here's the working version of my script:
#!/bin/bash
# Absolute path to SSH key
SSH_KEY="/home/user/.ssh/id_rsa"
# Server details
SERVER_A="user@serverA"
SERVER_B="user@serverB"
# Sync from A to B
rsync -avz -e "ssh -i $SSH_KEY -o StrictHostKeyChecking=no" \
$SERVER_A:/path/to/source/ $SERVER_B:/path/to/destination/
# Sync from B to A
rsync -avz -e "ssh -i $SSH_KEY -o StrictHostKeyChecking=no" \
$SERVER_B:/path/to/source/ $SERVER_A:/path/to/destination/
For more complex setups, creating a system-wide SSH config can help:
sudo tee /etc/ssh/ssh_config.d/cron_rsync.conf << 'EOF'
Host serverA
HostName serverA.example.com
User user
IdentityFile /home/user/.ssh/id_rsa
StrictHostKeyChecking no
Host serverB
HostName serverB.example.com
User user
IdentityFile /home/user/.ssh/id_rsa
StrictHostKeyChecking no
EOF
To verify your cron environment, create a test script:
#!/bin/bash
env > /tmp/cron_env.txt
whoami >> /tmp/cron_env.txt
echo $PATH >> /tmp/cron_env.txt
Schedule it in cron and examine /tmp/cron_env.txt
to see exactly what environment your cron jobs run with.
Remember that running rsync via sudo cron means:
- The SSH key must be readable by root
- Consider using
sudo -u specificuser
to run as a particular user - Check
/var/log/cron
orjournalctl -u cron
for additional errors
Here's the cron entry that ultimately worked for me:
# m h dom mon dow user command
0 * * * * root /usr/bin/bash /path/to/rsync_script.sh >> /var/log/rsync.log 2>&1
The key was ensuring absolute paths for everything and explicit SSH configuration.