systemd 环境下配置 sshd 监听端口
配置 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
包提供的,首先我们通过命令
# Ubuntu / Debian 下使用以下命令
dpkg -L openssh-server
# Red Hat / CentOS 下使用以下命令
rpm -ql openssh-server
# Arch Linux 下使用以下命令
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/[email protected]
-
Arch Linux 下的输出:
openssh /usr/lib/systemd/system/sshd.service openssh /usr/lib/systemd/system/sshd.socket openssh /usr/lib/systemd/system/[email protected] openssh /usr/lib/systemd/system/sshdgenkeys.service
-
其他系统下的输出也是类似的。
而其中,在 systemd 环境下,
- CentOS 7 的 sshd 服务默认是由
sshd.service
文件启动的; - Arch Linux 的 sshd 服务默认是由
sshd.socket
文件启动的; - 其他系统也可以按照下面介绍的方法来确认服务是如何启动的。
通过 systemctl 确认服务类型
我们可以通过以下命令来分别确认 sshd 服务是由 .service
文件启动,还是由 .socket
文件启动:
# 确认 sshd 服务是否由 .service 文件启动
systemctl status sshd.service
另外,上述命令中的 sshd.service
也可直接替换为 sshd
,因为 systemctl
命令默认就假设所输入的参数是一个 .service
文件。
# 确认 sshd 服务是否由 .socket 文件启动
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
文件启动。
# 使用 ss 命令
sudo ss -tlp
# 或使用 netstat 命令
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
所用端口
修改 如果已经启用 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
来查看一些网络相关的信息,如监听的端口、目前已经接受的连接数、目前正连接的连接数等。
扩展阅读: