https://zzz.buzz/zh/2015/12/26/configure-port-of-sshd-in-systemd-environment/
配置 sshd 大家都很熟悉,主要就是围绕 /etc/ssh/sshd_config 进行配置。而配置 sshd 的端口则是配置 sshd_config 中的 Port。不过在 systemd 环境下,根据服务是由 .socket 文件配置启动还是 .service 文件配置启动的不同,配置端口分别需要配置 sshd.socket 文件或依然是 sshd_config。
确认所用 sshd 服务
首先,我们需要确认系统所用的 sshd 服务,是由 sshd.socket 提供的,还是由 sshd.service 提供的。
如果服务由 sshd.socket 提供,配置端口需要配置 sshd.socket 文件;
如果服务由 sshd.service 提供,配置端口则需要配置传统的 sshd_config 文件。
一般系统中所安装的ssh服务都是由 openssh 包提供的,首先我们通过命令
dpkg -L openssh-server
rpm -ql openssh-server
pacman -Ql openssh
可以看到 openssh 包提供了如下 systemd 服务文件:
CentOS 7 下的输出:
/usr/lib/systemd/system/sshd-keygen.service
/usr/lib/systemd/system/sshd.service
/usr/lib/systemd/system/sshd.socket
/usr/lib/systemd/system/sshd@.service
Arch Linux 下的输出:
openssh /usr/lib/systemd/system/sshd.service
openssh /usr/lib/systemd/system/sshd.socket
openssh /usr/lib/systemd/system/sshd@.service
openssh /usr/lib/systemd/system/sshdgenkeys.service
其他系统下的输出也是类似的。
而其中,在 systemd 环境下,
CentOS 7 的 sshd 服务默认是由 sshd.service 文件启动的;
Arch Linux 的 sshd 服务默认是由 sshd.socket 文件启动的;
其他系统也可以按照下面介绍的方法来确认服务是如何启动的。
通过 systemctl 确认服务类型
我们可以通过以下命令来分别确认 sshd 服务是由 .service 文件启动,还是由 .socket 文件启动:
systemctl status sshd.service
另外,上述命令中的 sshd.service 也可直接替换为 sshd,因为 systemctl 命令默认就假设所输入的参数是一个 .service 文件。
systemctl status sshd.socket
根据实际系统及配置的不同可以分别看到类似如下输出:
sshd.service - OpenSSH Daemon
Loaded: loaded (/usr/lib/systemd/system/sshd.service; disabled; vendor preset: disabled)
Active: inactive (dead)
sshd.socket
Loaded: loaded (/usr/lib/systemd/system/sshd.socket; enabled; vendor preset: disabled)
Active: active (listening) since Sat 2015-12-26 15:23:31 CST; 1h 37min ago
Listen: [::]:22 (Stream)
Accepted: 3; Connected: 1
Active: 行中的 active 和 inactive 分别表示当前服务是否正在运行,也即 sshd 服务是否是由该配置文件启动。此外,如服务是由 .socket 文件配置启动的,还可以在 Listen: 行中看到具体的监听端口;如服务是由 .service 文件配置启动,则具体的监听端口需要在配置文件 sshd_config 中查看。
Loaded: 行中括号内的第一个 enabled 或者 disabled 分别表明了服务是否被默认启用,也就是重新启动系统后,服务是否会自动启动。该状态与服务当前是否正在运行无关。
通过 ss 或 netstat 确认服务类型
此外,我们还可以通过 ss 命令或 netstat 命令还查看当前 sshd 服务是由 .service 文件还是由 .socket 文件启动。
sudo ss -tlp
sudo netstat -tlp
得到如下输出:
LISTEN 0 128 *:ssh *:* users:(("sshd",pid=3824,fd=3))
或:
tcp 0 0 0.0.0.0:ssh 0.0.0.0:* LISTEN 3824/sshd
如在 ss 或 netstat 的结果中看到开启 ssh 端口的进程是 sshd 的话,则说明服务由 .service 文件启动;
如在 ss 的结果中看到开启 ssh 端口的进程是 systemd ,或在 netstat 的结果中看到开启 ssh 端口的进程是 init 的话,则说明服务由 .socket 文件启动。
如果已经启用 sshd.socket 服务,那么我们会发现 /etc/systemd/system/sockets.target.wants/sshd.socket 文件就会指向 /usr/lib/systemd/system/sshd.socket,而该文件会在更新 openssh 包时被更新,因此如果要修改 sshd.socket 所用的端口,我们不应直接修改该文件,而应先拷贝该文件:
cp /etc/systemd/system/sockets.target.wants/sshd.socket /etc/systemd/system/sshd.socket
再对 /etc/systemd/system/sshd.socket 进行修改,这样即使 openssh 包更新时,配置也能得到保留。
反之,如果直接修改 /etc/systemd/system/sockets.target.wants/sshd.socket,不仅改动会在 openssh 包升级时丢失,还会导致升级时 sshd.socket 由于在运行中被变更而不再工作,无法接受新连接,以至于有在重启系统前被锁在 SSH 外的风险:
sshd.socket: Socket unit configuration has changed while unit has been running, no open socket file descriptor left. The socket unit is not functional until restarted.
当修改配置文件时,需要修改的行如下:
ListenStream=22
将其中的 22 端口改成自己需要的端口,随后用以下命令加载新配置并重启服务:
systemctl daemon-reload
systemctl restart sshd.socket
重启完服务后,建议先在配置的新端口上验证可用后,再断开原先的ssh连接。
切换 sshd 的 socket 服务与 service 服务
如果目前使用的是 sshd.socket 服务,而想切换至 sshd.service 服务,可以执行如下命令:
systemctl disable sshd.socket
systemctl enable sshd.service
systemctl stop sshd.socket; systemctl start sshd.service
如果目前使用的是 sshd.service 服务,而想切换至 sshd.socket 服务,可以执行如下命令:
systemctl disable sshd.service
systemctl enable sshd.socket
systemctl stop sshd.service; systemctl start sshd.socket
socket 服务与 service 服务的异同
说了这么多,那两种启动 sshd 服务的方式到底有什么不同的,为什么需要有新的 socket 服务呢?
首先旧有的方式 sshd.service 模式会在后台保持一个 sshd 的守护进程,每当有 ssh 连接要建立时,就创建一个新进程,比较适合 SSH 下有大量流量的系统;
新的 sshd.socket 方式也是在每次要建立新的ssh连接时生成一个守护进程的实例,不过监听端口则是交给了 systemd 来完成,意味着没有 ssh 连接的时候,也不会有 sshd 守护进程运行,大部分情况下,使用 sshd.socket 服务更为合适。这也与 MacOS 下的行为相一致,默认只监听端口,有连接时才创建进程。
另外,通过使用 .socket 文件来管理需要监听端口的服务,可以直接通过 systemctl 来查看一些网络相关的信息,如监听的端口、目前已经接受的连接数、目前正连接的连接数等。
secure shell