SSH 连接打开时防止机器休眠

Bha*_*shi 20 ssh suspend power-management

我试图通过在桌面处于非活动状态时将桌面切换到挂起模式来节省电量。但是许多桌面也可以由它们的所有者通过 SSH 访问。部署了一个wakeonlan 解决方案,使所有者能够打开机器,但问题是机器将在 10 分钟后再次自动挂起,即使 SSH 连接已打开。

我想要做的是在“活动”定义中包含活动的 SSH 会话。

问题是可以通过设置 polkit 规则来完成吗?是否可以通过放置一个在实际挂起之前运行的脚本来完成,并在找到 SSH 会话时中止它?我需要一种干净合法的方式来做到这一点。如果不是这样,那么也欢迎使用 hacky 方法。

当前天真的hacky解决方案:编辑/usr/sbin/pm-suspend

#check for SSH sessions, and prevent suspending:
if [ "$(who | grep -cv "(:")" -gt 0 ]; then
    echo "SSH session(s) are on. Not suspending."
    exit 1
fi
Run Code Online (Sandbox Code Playgroud)

这达到了目的。但我不知道更新何时会覆盖文件/usr/sbin/pm-suspend。我也不知道这将如何与 tuxonice 等其他挂起实现一起使用。

Dav*_*ter 22

直到 Ubuntu 14.10(基于新贵)

查看pm-action(8)并搜索/etc/pm/sleep.d“文件”部分。如果这些脚本之一以非零退出状态返回,则会阻止挂起。

为清楚起见,更新了说明:

  1. 所以创建一个文件/etc/pm/sleep.d/05_ssh_keepawake

  2. shebang ( #!/bin/sh) 和问题中提到的代码放入此文件中。

  3. 对其设置执行权限:

    chmod +x /etc/pm/sleep.d/05_ssh_keepawake
    
    Run Code Online (Sandbox Code Playgroud)

自 Ubuntu 15.04(基于 systemd)

systemd不使用pm-utils来管理它的电源状态钩子,但有自己的基础设施来达到同样的目的。睡眠抑制检查器不再在睡眠时执行,而必须由抑制睡眠的操作设置(参见1)。

因此,您必须向 SSH 会话登录和注销添加命令,以向 systemd 注册睡眠抑制器(例如 via systemd-inhibit(1)),然后释放抑制器。如果有人知道如何挂钩 SSH 登录和注销,我欢迎评论或编辑,以便我们制定相关步骤和命令。

以下部分正在进行中 - 只有在您知道自己在做什么时才使用它!

您也许可以编写一个 systemd 单元/etc/systemd/system/ssh-inhibt-sleep.service,使其成为sleep.target使用该RequiredBy选项的依赖项。如果您的新单元失败(从其调用的进程中退出非零状态),它将执行sleep.target并因此执行后续的睡眠操作。

[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
Run Code Online (Sandbox Code Playgroud)

与往常一样,您需要激活 systemd 单元才能使它们生效:

sudo systemctl enable ssh-inhibt-sleep.service
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请参阅systemd.unit(5)systemd.service(5)


cla*_*ion 9

结合两个相关的答案(此处此处),这是一个/etc/pam_session.sh在 Ubuntu 19.10 上实现的技巧(至少):

#!/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
Run Code Online (Sandbox Code Playgroud)

确保添加以下行:

session     optional    pam_exec.so quiet /etc/pam_session.sh
Run Code Online (Sandbox Code Playgroud)

/etc/pam.d/sshdsession部分,并使/etc/pam_session.sh脚本可执行:

chmod +x /etc/pam_session.sh
Run Code Online (Sandbox Code Playgroud)

请注意,该/etc/pam_session.sh脚本似乎在用户登录或注销时运行,因此用户需要sudo访问 mask/unmask systemd 目标。

  • 似乎是最优雅的解决方案。尽管已经很老了,但已确认在 20.10 开始工作。答案中缺少一个步骤:确保将“session option pam_exec.so Quiet /etc/pam_session.sh”行添加到会话部分中的“/etc/pam.d/sshd”,并创建“/etc/pam_session” .sh` 可执行文件。 (2认同)

Jud*_*ude 5

在现代systemd系统中,您还可以将ssh.socket服务与systemd-inhibit一起使用。您可以让systemd管理传入连接,而不是独立运行通常的ssh.service 。现在每个打开的会话都由ssh.socket处理,它创建基于ssh@.service 的实例单元,因此只需创建一个直接绑定到它的服务即可。这具有跟踪和记录与systemd 的每个 ssh 连接的额外好处。然后我们可以使用这个标识符在阻止睡眠时提供更多有用的信息。此方法还可以防止像其他一些示例一样因故障单元而导致systemd降级。

首先,如果您尚未使用ssh.socket,则需要检查以确保启用它。

systemctl is-active ssh.socket
Run Code Online (Sandbox Code Playgroud)

应该说活跃,否则你将需要启用它:

sudo systemctl disable ssh
sudo systemctl stop ssh
sudo systemctl enable ssh.socket
sudo systemctl start ssh.socket
Run Code Online (Sandbox Code Playgroud)

然后你只需要创建/etc/systemd/system/ssh-no-sleep@.service

systemctl is-active ssh.socket
Run Code Online (Sandbox Code Playgroud)

并启用它:

sudo systemctl enable ssh-no-sleep@
Run Code Online (Sandbox Code Playgroud)

为了触发 ssh@.service 别名(用 @ 表示),您必须确保 ssh.socket 服务具有[Socket]设置Accept=yes,否则 no sleep 服务将永远不会为每个新连接触发。您可以通过运行以下命令来测试您的 systemd 默认设置:

sudo systemctl show --no-pager --property Accept ssh.socket
Run Code Online (Sandbox Code Playgroud)

如果返回no,您需要通过创建一个conf文件/etc/systemd/system/ssh.socket.d/accept.conf将其覆盖为yes

sudo systemctl disable ssh
sudo systemctl stop ssh
sudo systemctl enable ssh.socket
sudo systemctl start ssh.socket
Run Code Online (Sandbox Code Playgroud)

如果您的系统缺少ssh@.servicessh.socket,以下是 Debian Bullseye 中的一个示例,您可以使用:

/etc/systemd/system/ssh@.service

[Unit]
Description=ssh no sleep
BindsTo=ssh@%i.service

[Service]
ExecStart=/usr/bin/systemd-inhibit --mode block --what sleep --who "ssh session "%I --why "session still active" /usr/bin/sleep infinity

[Install]
WantedBy=ssh@.service
Run Code Online (Sandbox Code Playgroud)

/etc/systemd/system/ssh.socket

sudo systemctl enable ssh-no-sleep@
Run Code Online (Sandbox Code Playgroud)

保存后,运行systemctl daemon-reloadsystemctl restart ssh.socket,您可以重新运行之前的 show 命令来确认Accept=yes

现在,当有人尝试暂停时,他们将收到所有阻塞 ssh 会话的有用消息

sudo systemctl suspend
Run Code Online (Sandbox Code Playgroud)

然后将返回类似以下内容:

sudo systemctl show --no-pager --property Accept ssh.socket
Run Code Online (Sandbox Code Playgroud)

ssh.socket的另一个好处是您还可以使用:

systemctl status ssh.socket
Run Code Online (Sandbox Code Playgroud)

返回活跃用户和系统统计信息:

[Socket]
Accept=yes
Run Code Online (Sandbox Code Playgroud)