How to Fix “sudo: no tty present” Error in Rsync Over SSH Cron Jobs


6 views

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.