Long-running backups, reports, and maintenance tasks often need to keep running on the remote host after you reclaim the local terminal. Launching those jobs correctly over SSH avoids babysitting an open session and prevents a local shell from staying attached to work that should continue on its own.
The ssh client normally keeps the session open until the remote command exits and closes its standard streams. Current OpenSSH still uses -f only to fork the client after authentication, and -f already implies -n, so stdin is disconnected but stdout or stderr from the remote command can still keep a backgrounded local ssh process alive until the remote side finishes.
Reliable detached launches therefore need non-interactive authentication, a trusted host key, and explicit remote redirection of stdin, stdout, and stderr before the command is backgrounded. Add nohup when the remote program should ignore a hangup from the remote shell as it exits, but still write output to a chosen log file instead of relying on nohup.out.
Steps to execute remote SSH commands in the background:
- Open a terminal on the local machine and confirm that the target host accepts a non-interactive SSH login.
$ ssh -o BatchMode=yes user@host.example.net 'printf "ssh-login-ok\n"' ssh-login-ok
BatchMode=yes makes ssh fail instead of waiting for a password, passphrase, or host-key confirmation prompt, which is the behavior needed for unattended background launches.
- Run a simple remote command normally to observe the default blocking behavior.
$ ssh user@host.example.net 'sleep 30'
The local prompt returns only after the remote sleep command exits.
- Start the same kind of command with -f to send the SSH client into the local background after authentication.
$ ssh -f user@host.example.net 'sleep 120'
Current ssh(1) still documents -f as backgrounding the client just before command execution, and it already implies -n so stdin is redirected from /dev/null.
-f alone does not fully detach the remote job. The local ssh client stays alive in the background until the remote command exits because that command is still attached to the original SSH session.
- Check the local process list to confirm that ssh -f alone left a background client process behind.
$ pgrep -af "ssh .*sleep 120" 14862 ssh -f user@host.example.net sleep 120
A matching local ssh process here is expected because the remote sleep command is still using the same session.
- Launch the remote job with explicit redirection and a remote background operator so the original SSH client can exit.
$ ssh -f user@host.example.net "sh -c '/usr/local/bin/backup-job.sh >/var/log/backup-job.log 2>&1 < /dev/null &'"
Running the redirection and trailing & inside sh -c keeps the remote shell logic together under a predictable POSIX shell.
If stdout or stderr stays attached to the SSH channel, the local ssh client can remain in the background until the remote process closes those streams.
- Verify from a separate SSH session that the detached process is still running after the launcher exits.
$ ssh user@host.example.net "pgrep -af 'backup-job.sh'" 14527 /bin/bash /usr/local/bin/backup-job.sh
Checking from a new session confirms that the process no longer depends on the original launcher connection.
- Confirm that the local ssh client from the detached launch has already exited.
$ pgrep -af "ssh .*backup-job.sh"
No output indicates that the remote job is running independently instead of holding a backgrounded local ssh process open.
- Add nohup when the remote program should ignore hangup signals after the remote shell exits.
$ ssh -f user@host.example.net "nohup /usr/local/bin/backup-job.sh >/var/log/backup-job.log 2>&1 < /dev/null &"
nohup ignores the hangup signal, but it does not put the command into the background by itself, so the trailing & and explicit log redirection still matter.
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.
