Troubleshooting Rsync Error 255 in Cron: Fix for “connection unexpectedly closed” When Running as Root


2 views

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:

  1. Cron provides a minimal environment - many environment variables (like PATH) are missing
  2. SSH agent forwarding isn't available in cron by default
  3. 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 or journalctl -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.