When attempting to run rsync over SSH in a cron job as root on Debian, you encounter the following error:
sudo: no tty present and no askpass program specified
This occurs despite having proper sudoers configuration and SSH key authentication working.
Several important observations were made during troubleshooting:
- The command works fine when run manually but fails in cron
- SSH key authentication is properly set up (
/home/backups/.ssh/id_rsa
) - The sudoers file contains:
backups ALL= NOPASSWD:/usr/bin/rsync
Defaults requiretty
is not present in /etc/sudoers- Adding
-t
flags to SSH causes different errors
The fundamental issue stems from how sudo and SSH interact in non-interactive environments (like cron). Even with NOPASSWD set, some sudo configurations still expect a terminal session.
Solution 1: Modify Sudoers More Explicitly
# In /etc/sudoers or /etc/sudoers.d/rsync_backups
Cmnd_Alias RSYNC = /usr/bin/rsync
backups ALL=(root) NOPASSWD: RSYNC
Defaults!RSYNC !requiretty
Solution 2: Alternative Rsync Command Structure
rsync -avz --rsync-path="sudo -n /usr/bin/rsync" \
-e "ssh -i /home/backups/.ssh/id_rsa -o LogLevel=ERROR" \
backups@remote:/source/ /destination/
Solution 3: Environment Variable Approach
#!/bin/bash
export RSYNC_RSH="ssh -i /home/backups/.ssh/id_rsa -q"
rsync -avz --rsync-path="sudo /usr/bin/rsync" \
backups@remote:/ /backup/dir/
To confirm your solution works:
sudo -u root crontab -e
# Add test job:
* * * * * /usr/bin/rsync --version >> /tmp/rsync_test.log 2>&1
- Check
/var/log/auth.log
for sudo/SSH errors - Test with
ssh -vvv
for detailed connection debugging - Consider using
strace
to trace system calls when the command fails
When running rsync over SSH in a cron job with sudo privileges, you might encounter the frustrating "no tty present" error. This typically occurs because:
- Cron jobs don't allocate a terminal (tty) by default
- Sudo expects a terminal for password input (even when NOPASSWD is set)
- The SSH connection isn't properly configured for non-interactive use
Here's the working command that solves all these issues:
rsync -vqrlHEAXogDtzhi \
--log-file=${LOG} \
--progress \
--rsync-path="sudo -n /usr/bin/rsync" \
--exclude-from=$CONFIG_DIR/excludes \
-e "ssh -i /home/backups/.ssh/id_rsa -o LogLevel=error" \
backups@${HOSTNAME}:/ ${BACKUP_DIR}
1. The -n flag for sudo:
This tells sudo to non-interactive mode, preventing it from asking for a password.
2. SSH LogLevel setting:
Setting LogLevel to error prevents SSH from outputting connection messages that might interfere with the protocol.
Ensure these settings are in place:
# In /etc/sudoers or /etc/sudoers.d/backups
backups ALL=(ALL) NOPASSWD: /usr/bin/rsync
Defaults:backups !requiretty
Before adding to cron, test interactively:
sudo -u backups bash -c 'rsync -vqrlHEAXogDtzhi --rsync-path="sudo -n /usr/bin/rsync" -e "ssh -i /home/backups/.ssh/id_rsa -o LogLevel=error" backups@remote:/ /tmp/testbackup'
Here's how your crontab entry should look:
0 2 * * * /usr/bin/flock -n /tmp/backup.lock -c 'rsync -vqrlHEAXogDtzhi --log-file=/var/log/backups/$(date +\%Y\%m\%d).log --progress --rsync-path="sudo -n /usr/bin/rsync" --exclude-from=/etc/backups/excludes -e "ssh -i /home/backups/.ssh/id_rsa -o LogLevel=error" backups@remote:/ /backup/destination'
The flock utility prevents multiple concurrent backups from running.