When executing rsync
commands over SSH in a cronjob, you'll often encounter authentication failures even when the same command works fine interactively. This happens because cron jobs run in a minimal environment that doesn't have access to your SSH agent by default.
Your interactive shell loads your SSH agent through your .bashrc
or similar startup files, but cron jobs:
- Don't load your shell configuration files
- Run with a minimal environment (no
SSH_AUTH_SOCK
variable) - Have no terminal or display associated
Method 1: Load SSH Agent in Crontab
The most reliable approach is to explicitly load the SSH agent in your crontab entry:
0 9 * * * source ~/.bashrc && rsync -a mydir remote_machine:
Or more precisely target the agent socket:
0 9 * * * eval $(ssh-agent) && ssh-add ~/.ssh/id_rsa && rsync -a mydir remote_machine:
Method 2: Use Keychain
Keychain manages ssh-agent for you across sessions. First install it:
sudo apt-get install keychain # Debian/Ubuntu
brew install keychain # macOS
Then modify your crontab:
0 9 * * * source $HOME/.keychain/$HOSTNAME-sh && rsync -a mydir remote_machine:
Method 3: SSH Config with Persistent Connection
Add this to your ~/.ssh/config
:
Host remote_machine
HostName actual.hostname.com
User yourusername
ControlMaster auto
ControlPath ~/.ssh/control:%h:%p:%r
ControlPersist 10m
Then establish the connection before cron runs:
ssh -f -N remote_machine
For debugging, add this to your cronjob temporarily:
* * * * * env > /tmp/cronenv.log
Then check if SSH_AUTH_SOCK
is present in the environment.
When automating SSH connections:
- Use dedicated SSH keys with limited permissions
- Consider adding
command=
restrictions inauthorized_keys
- Regularly rotate automated keys
- Never store passphrases in cronjobs
When executing rsync over SSH via cron while using ssh-agent, the authentication fails despite working perfectly in interactive shell sessions. This occurs because cron jobs don't inherit the SSH_AUTH_SOCK environment variable that ssh-agent sets.
The key difference lies in environment variables:
- Interactive shells automatically inherit SSH_AUTH_SOCK from your login session
- Cron runs in a minimal environment without these variables
Method 1: Forward SSH Agent in Cron
Explicitly set the environment in your cron job:
0 9 * * * SSH_AUTH_SOCK=$(ls -t /tmp/ssh-*/agent.* | head -1) rsync -a mydir remote_machine:
Method 2: Use Keychain
Keychain manages ssh-agent and provides a reliable way to access it from cron:
0 9 * * * source $HOME/.keychain/$HOSTNAME-sh && rsync -a mydir remote_machine:
Method 3: SSH Config Alternative
Configure passwordless SSH access permanently in ~/.ssh/config:
Host remote_machine
HostName actual.hostname.com
User yourusername
IdentityFile ~/.ssh/id_rsa
IdentitiesOnly yes
ForwardAgent no
Add these debugging lines to your cron job to verify the environment:
0 9 * * * echo "SSH_AUTH_SOCK: $SSH_AUTH_SOCK"; env > /tmp/cronenv; rsync -avvv mydir remote_machine: > /tmp/rsync.log 2>&1
For enterprise environments, consider this robust approach:
0 9 * * * eval $(ssh-agent) && ssh-add ~/.ssh/id_rsa && rsync -a -e "ssh -o BatchMode=yes" mydir remote_machine: