Prevent machine from sleeping when SSH connections are on

Until Ubuntu 14.10 (Upstart-based)

Have a look at pm-action(8) and search for /etc/pm/sleep.d in section “FILES”. If one of these scripts returns with a non-zero exit status, suspension is prevented.

Updated instructions for clarity:

  1. So create a file /etc/pm/sleep.d/05_ssh_keepawake.

  2. Put a shebang (#!/bin/sh) and the code mentioned in the question in this file.

  3. Set execute permissions on it:

    chmod +x /etc/pm/sleep.d/05_ssh_keepawake
    

Since Ubuntu 15.04 (systemd-based)

systemd doesn’t use pm-utils to manage its power state hooks but has its own infrastructure to the same end. Sleep inhibitor checkers are no longer executed on sleep but must be set by the action that inhibits sleep (see 1).

As such you’d have to add commands to the SSH session log-in and log-out that registers a sleep inhibitor with systemd (e. g. via systemd-inhibit(1)) and later releases the inhibitor. If somebody knows how to hook into SSH log-in and log-out, I’d welcome a comment or edit so that we could work out the relevant steps and commands.

The following section is work in progress – Only use it when you know what you’re doing!

You might be able to write a systemd unit /etc/systemd/system/ssh-inhibt-sleep.service that makes itself a dependency of sleep.target using the RequiredBy option. If your new unit fails (with a non-zero exit status from its invoked process), it will make sleep.target and thus the subsequent sleep action.

[Unit]
Description=Check for running SSH sessions and, if any, inhibit sleep
Before=sleep.target

[Service]
Type=oneshot
ExecStart=/bin/sh -c '! who | grep -qv "\(:0\)"'

[Install]
RequiredBy=sleep.target

As always you need to activate systemd units for them to take effect:

sudo systemctl enable ssh-inhibt-sleep.service

For more info see systemd.unit(5) and systemd.service(5).


Combining two related answers (here and here), here's an /etc/pam_session.sh that does the trick on Ubuntu 19.10 (at least):

#!/bin/sh
#
# This script runs when an ssh session opens/closes, and masks/unmasks
# systemd sleep and hibernate targets, respectively.
#
# Inspired by: https://unix.stackexchange.com/a/136552/84197 and
#              https://askubuntu.com/a/954943/388360

num_ssh=$(netstat -nt | awk '$4 ~ /:22$/ && $6 == "ESTABLISHED"' | wc -l)

case "$PAM_TYPE" in
    open_session)
        if [ "${num_ssh}" -gt 1 ]; then
            exit
        fi
        command=mask
        ;;

    close_session)
        if [ "${num_ssh}" -ne 0 ]; then
            exit
        fi
        command=unmask
        ;;

    *)
        exit
esac

logger "${command}ing sleep and suspend targets (num_ssh=${num_ssh})"
sudo systemctl ${command} sleep.target suspend.target

Make sure to add the line:

session     optional    pam_exec.so quiet /etc/pam_session.sh

to /etc/pam.d/sshd in the session section, and make the /etc/pam_session.sh script executable:

chmod +x /etc/pam_session.sh

Note that the /etc/pam_session.sh script appears to run as the the user logging in or out, so that user requires sudo access to mask/unmask systemd targets.