OS + Rocky 10 / sshd_config / ssh_config / sshd / sshd.service / ssh / 22222
s
- 问题2 防火墙和SELinux的作用
防火墙决定“能否进入端口”,而 SELinux 决定“能做什么应用”
- 问题1 rocky10开启ssh端口22222问题
root@rocky10:~# systemctl status sshd.service
● sshd.service - OpenSSH server daemon
Loaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; preset: enabled)
Active: active (running) since Mon 2025-09-08 22:21:54 CST; 17s ago
Invocation: e1cf69a9aaf345199111dfe2ddcdeae6
Docs: man:sshd(8)
man:sshd_config(5)
Main PID: 8937 (sshd)
Tasks: 1 (limit: 48756)
Memory: 1M (peak: 1.5M)
CPU: 9ms
CGroup: /system.slice/sshd.service
└─8937 "sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups"
Sep 08 22:21:54 rocky10.xianhemen.cn systemd[1]: Starting sshd.service - OpenSSH server daemon...
Sep 08 22:21:54 rocky10.xianhemen.cn (sshd)[8937]: sshd.service: Referenced but unset environment variable evaluates to an empty string: OPTIONS
Sep 08 22:21:54 rocky10.xianhemen.cn sshd[8937]: error: Bind to port 22222 on 0.0.0.0 failed: Permission denied.
Sep 08 22:21:54 rocky10.xianhemen.cn sshd[8937]: error: Bind to port 22222 on :: failed: Permission denied.
Sep 08 22:21:54 rocky10.xianhemen.cn sshd[8937]: Server listening on 0.0.0.0 port 22.
Sep 08 22:21:54 rocky10.xianhemen.cn sshd[8937]: Server listening on :: port 22.
Sep 08 22:21:54 rocky10.xianhemen.cn systemd[1]: Started sshd.service - OpenSSH server daemon.
解决1
可能原因:
SELinux 限制
RHEL / Rocky Linux 默认启用 SELinux,非标准端口(≠22)的 sshd 会被 SELinux 拒绝。
端口权限问题
Linux 普通进程绑定 1024 以下的端口需要 root 权限,但 22222 > 1024,按理不会有问题,所以大概率是 SELinux。
配置文件里多端口冲突
你可能在 /etc/ssh/sshd_config 里写了:
1、检查 SELinux 是否拦截
getenforce
2、允许 sshd 使用 22222 端口
sudo semanage port -a -t ssh_port_t -p tcp 22222
# 如果端口已存在则用 -m 修改
sudo semanage port -m -t ssh_port_t -p tcp 22222
3、添加防火墙放行端口
sudo firewall-cmd --permanent --add-port=22222/tcp
sudo firewall-cmd --reload
4、查看防火墙放行端口
sudo firewall-cmd --list-ports
5、重启 sshd
sudo systemctl restart sshd
一:只修改/etc/ssh/sshd_config配置
/opt/modify_sshd_config.sh
#!/bin/bash
# ==========================================
# 脚本名称: test.sh
# 功能描述: 一键修改 SSH 端口、配置 SELinux 及防火墙
# 适用系统: Rocky Linux / AlmaLinux / CentOS / RHEL
# ==========================================
# 定义变量
NEW_PORT=22222
SSH_CONFIG="/etc/ssh/sshd_config"
BACKUP_FILE="${SSH_CONFIG}.bak.$(date +%Y%m%d)"
echo "🚀 开始执行系统安全配置..."
# --- 第一步:环境检查与依赖安装 ---
echo "📦 [1/5] 正在检查并安装 SELinux 管理工具..."
if ! command -v semanage &> /dev/null; then
sudo dnf install -y policycoreutils-python-utils
else
echo " -> semanage 已安装,跳过。"
fi
# --- 第二步:备份配置文件 ---
echo "📝 [2/5] 正在备份 SSH 配置文件..."
sudo cp $SSH_CONFIG $BACKUP_FILE
echo " -> 备份完成: $BACKUP_FILE"
# --- 第三步:修改 SSH 配置 ---
echo "⚙️ [3/5] 正在修改 SSH 端口配置..."
# 检查是否已经存在该端口配置,避免重复添加
if grep -q "^Port $NEW_PORT" $SSH_CONFIG; then
echo " -> 端口 $NEW_PORT 已存在于配置文件中,跳过修改。"
else
# 在 #Port 22 下面追加新端口
sudo sed -i "/^#Port 22/a Port $NEW_PORT" $SSH_CONFIG
echo " -> 配置已追加。"
fi
# --- 第四步:配置 SELinux ---
echo "🔒 [4/5] 正在配置 SELinux 放行新端口..."
# 检查 SELinux 状态
if [ "$(getenforce)" != "Disabled" ]; then
# 检查端口是否已存在,防止报错
if sudo semanage port -l | grep -q "$NEW_PORT"; then
echo " -> SELinux 中已存在端口 $NEW_PORT 规则,跳过。"
else
sudo semanage port -a -t ssh_port_t -p tcp $NEW_PORT
echo " -> SELinux 规则添加成功。"
fi
else
echo " -> SELinux 处于禁用状态,跳过配置。"
fi
# --- 第五步:配置防火墙 ---
echo "🔥 [5/5] 正在配置防火墙 (Firewalld)..."
if systemctl is-active --quiet firewalld; then
# 检查端口是否已开放
if sudo firewall-cmd --zone=public --list-ports | grep -q "$NEW_PORT/tcp"; then
echo " -> 防火墙已开放端口 $NEW_PORT,跳过。"
else
sudo firewall-cmd --permanent --zone=public --add-port=$NEW_PORT/tcp
sudo firewall-cmd --reload
echo " -> 防火墙端口 $NEW_PORT 开放成功。"
fi
else
echo " -> 防火墙未运行,跳过配置。"
fi
# --- 第六步:重启服务与验证 ---
echo "🔄 正在重启 SSH 服务..."
# 检查配置语法
if sudo sshd -t; then
sudo systemctl restart sshd.service
echo "✅ SSH 服务重启成功!"
else
echo "❌ SSH 配置语法错误!正在回滚备份..."
sudo cp $BACKUP_FILE $SSH_CONFIG
sudo systemctl restart sshd.service
exit 1
fi
# --- 最终状态展示 ---
echo ""
echo "🎉 配置完成!当前系统状态如下:"
echo "------------------------------------------------"
echo "1. 配置文件中的端口设置:"
grep "Port" $SSH_CONFIG
echo ""
echo "2. SELinux 中的 SSH 端口:"
semanage port -l | grep ssh
echo ""
echo "3. 防火墙开放的端口:"
firewall-cmd --zone=public --list-ports
echo ""
echo "4. 当前监听的网络端口:"
ss -ntlp | grep sshd
echo "------------------------------------------------"
echo ""
echo "⚠️ 警告:请勿关闭当前窗口!"
echo "请新开一个终端窗口测试连接:ssh -p $NEW_PORT user@host"
echo "确认连接成功后,再关闭旧的 SSH 会话。"
二:防火墙配置
root@rocky1:~# sudo firewall-cmd --permanent --add-port=22222/tcp
root@rocky1:~# sudo firewall-cmd --reload
root@rocky1:~# sudo firewall-cmd --permanent --zone=public --list-all # 查看开放了哪些端口+协议
public (default)
target: default
ingress-priority: 0
egress-priority: 0
icmp-block-inversion: no
interfaces:
sources:
services: cockpit dhcpv6-client ssh
ports: 22222/tcp 33333/tcp
protocols:
forward: yes
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
root@rocky1:~# 查询永久配置中public区域的端口,仅重启后生效。
root@rocky1:~# firewall-cmd --permanent --zone=public --list-ports
22222/tcp 33333/tcp
root@rocky1:~# 查询运行时配置中public区域的端口,包括临时添加。
root@rocky1:~# firewall-cmd --zone=public --list-ports # 查看开放了哪些端口
22222/tcp 33333/tcp
root@rocky1:~# 查询永久配置中默认区域的端口。
root@rocky1:~# firewall-cmd --permanent --list-ports # 查看开放了哪些端口
22222/tcp 33333/tcp
root@rocky1:~# 关闭多余端口命令参考
root@rocky1:~# firewall-cmd --zone=public --remove-port=44444/tcp --remove-port=55555/tcp --permanent
root@rocky1:~# firewall-cmd --reload # 必须执行后生效
三:向SELinux中添加修改的SSH端口
RHEL / Rocky Linux 默认启用 SELinux,非标准端口(≠22)的 sshd 会被 SELinux 拒绝。
root@rocky2:~# dnf install -y policycoreutils-python-utils # 安装依赖
root@rocky2:~# yum provides semanage # 查看semanage
Extra Packages for Enterprise Linux 10 - x86_64 2.0 MB/s | 13 MB 00:06
Rocky Linux 10 - BaseOS 11 MB/s | 17 MB 00:01
Rocky Linux 10 - AppStream 13 MB/s | 11 MB 00:00
Rocky Linux 10 - Extras 8.4 kB/s | 8.0 kB 00:00
policycoreutils-python-utils-3.8-1.el10.noarch : SELinux policy core python utilities
Repo : @System
Matched from:
Filename : /usr/sbin/semanage
policycoreutils-python-utils-3.8-1.el10.noarch : SELinux policy core python utilities
Repo : appstream
Matched from:
Filename : /usr/sbin/semanage
root@rocky2:~# semanage port -l |grep ssh # ssh端口配置前,环境查看
ssh_port_t tcp 22
root@rocky2:~# semanage port -a -t ssh_port_t -p tcp 22222 # 向 SELinux 中添加指定放行端口
root@rocky2:~# systemctl restart sshd.service # 重启服务
root@rocky2:~# semanage port -l | grep ssh # 查看指定应用端口是否放行
ssh_port_t tcp 22222, 22
四:安全设置 Fail2ban
说明:Fail2ban 默认配置在 /etc/fail2ban/jail.conf,但官方推荐不要直接改它,而是写在 /etc/fail2ban/jail.local。
1、安装 fail2ban 应用
root@rocky2:~# sudo dnf install -y epel-release
root@rocky2:~# sudo dnf install -y fail2ban fail2ban-firewalld
root@rocky2:~# sudo systemctl enable --now fail2ban
root@rocky2:~# sudo systemctl status fail2ban
2、定义脚本
root@rocky2:~# sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
3、新增内容 /etc/fail2ban/jail.local。ini文件不能在-有效配置行后面加注释,容易启动不了
#===========================================================
# Fail2ban 本地配置文件 (jail.local)
# 作用:防护 SSH 爆破攻击
# 注意:
# 1. 注释必须单独占一行
# 2. filter 文件使用 sshd.local,覆盖默认规则
#===========================================================
[sshd]
# 是否启用此 jail
enabled = true
# 监听端口,可以写多个
port = 22,33333
# 使用自定义 filter 文件
filter = sshd
# 日志路径
logpath = /var/log/secure
# 最大尝试次数 (maxretry 次失败封禁 IP)
maxretry = 5
# 封禁时间 (秒),-1为永久
bantime = 3600
# 查找失败次数的时间窗口 (秒)
findtime = 600
# 后端类型,auto 即自动选择 systemd/journald 等
backend = auto
# 可选:如果使用 firewalld 封禁
# action = firewallcmd-ipset
# 默认 action 是 iptables-multiport,可自行修改
3.2 新增文件 /etc/fail2ban/filter.d/sshd.local ,添加如下内容:
- 写法1,简易规则
[INCLUDES]
before = common.conf
[Definition]
failregex = ^%(__prefix_line)sFailed password for .* from <HOST> port \d+ ssh2$
^%(__prefix_line)sConnection closed by authenticating user .* <HOST> port \d+ \[preauth\]$
ignoreregex =
- 写法2,多种规则,如加注释异常,可以去掉
[INCLUDES]
# 继承 common.conf 中的通用前缀(如 %(__prefix_line)s)和日期模式,确保兼容系统日志格式
before = common.conf
[Definition]
# SSH 登录失败常见日志匹配 - 这些规则用于检测各种 SSH 认证失败事件
# 每个规则用 | 分隔,Fail2Ban 会逐一尝试匹配日志行(OR 逻辑)
failregex = ^%(__prefix_line)sFailed password for .* from <HOST> port \d+ ssh2$
# 匹配普通密码认证失败日志,例如:Failed password for invalid from 192.168.1.1 port 22 ssh2
| ^%(__prefix_line)sInvalid user .* from <HOST>( port \d+)?$
# 匹配无效用户名登录尝试,例如:Invalid user fakeuser from 192.168.1.1
| ^%(__prefix_line)s pam_unix\(sshd:auth\): authentication failure; .* rhost=<HOST> .*$
# 匹配 PAM 认证失败(修正:添加 sshd[pam] 前缀以匹配标准格式),例如:pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty= ruser= rhost=192.168.1.1
| ^%(__prefix_line)sFailed publickey for .* from <HOST> port \d+ ssh2$
# 匹配 SSH 密钥认证失败,例如:Failed publickey for user from 192.168.1.1 port 22 ssh2
| ^%(__prefix_line)sConnection closed by authenticating user .* <HOST> port \d+ \[preauth\]$
# 匹配预认证阶段连接关闭(可疑行为),例如:Connection closed by authenticating user root 192.168.1.1 port 22 [preauth]
| ^%(__prefix_line)sDisconnected from <HOST> port \d+.*
# 匹配远程断开连接(可选:如果匹配正常用户,可能移到 ignoreregex 避免误判),例如:Disconnected from invalid user 192.168.1.1 port 22
| ^%(__prefix_line)serror: maximum authentication attempts exceeded for .* from <HOST> port \d+ ssh2$
# 匹配最大认证尝试超限,例如:error: maximum authentication attempts exceeded for invalid from 192.168.1.1 port 22 ssh2
# 忽略的日志匹配 - 可以为空,或添加正常行为模式(如本地 IP 断开)以避免误禁
ignoreregex =
4. 检查 fail2ban配置
sudo fail2ban-regex /var/log/secure /etc/fail2ban/filter.d/sshd.local
sudo systemctl restart fail2ban
sudo systemctl status fail2ban
sudo fail2ban-client reload # 测试加载
sudo fail2ban-client -d
5 启用 fail2ban
sudo systemctl restart fail2ban
sudo systemctl enable fail2ban
6 查看 sshd jail 状态
root@rocky2:~# sudo fail2ban-client status
root@rocky2:~# sudo fail2ban-client status sshd # 监测到并禁止IP
Status for the jail: sshd
|- Filter
| |- Currently failed: 1
| |- Total failed: 9
| `- File list: /var/log/secure
`- Actions
|- Currently banned: 1
|- Total banned: 1
`- Banned IP list: 122.192.15.8
7. 手动解封 IP(如果需要)/ 取消
sudo fail2ban-client unban <IP_ADDRESS>
8. 观察日志
tail -f /var/log/secure /var/log/fail2ban.log
- 9. 一键化脚本
#!/usr/bin/env python3
import os
import subprocess
from textwrap import dedent
def run(cmd):
print(f"\n[执行] {cmd}")
subprocess.run(cmd, shell=True, check=True, executable="/bin/bash")
def main():
# 1. 修改 SSH 配置文件端口
sshd_config = "/etc/ssh/sshd_config"
run(f"sudo sed -i 's/^#Port 22/Port 22\\nPort 22222/' {sshd_config}")
# 2. SELinux 添加端口规则 (只针对 SSH 新端口 22222)
run("sudo dnf install -y policycoreutils-python-utils")
run("sudo semanage port -a -t ssh_port_t -p tcp 22222 || sudo semanage port -m -t ssh_port_t -p tcp 22222")
# 3. 防火墙放行 SSH 新端口
run("sudo firewall-cmd --permanent --add-port=22222/tcp")
# 3.1 防火墙放行其他应用端口 (33333, 44444, 55555)
for port in [33333, 44444, 55555]:
run(f"sudo firewall-cmd --permanent --add-port={port}/tcp")
# 4. 重载防火墙规则
run("sudo firewall-cmd --reload")
# 5. 重启 sshd 并设置开机自启
run("sudo systemctl restart sshd")
run("sudo systemctl enable sshd")
# 6. 安装 Fail2ban
run("sudo dnf install -y epel-release")
run("sudo dnf install -y fail2ban fail2ban-firewalld")
run("sudo systemctl enable --now fail2ban")
# 7. 配置 Fail2ban jail.local
jail_local = dedent("""
[sshd]
enabled = true
port = 22,22222
filter = sshd
logpath = /var/log/secure
maxretry = 5
bantime = 3600
findtime = 600
backend = auto
action = firewallcmd-ipset
""").strip()
with open("/tmp/jail.local", "w") as f:
f.write(jail_local)
run("sudo cp /tmp/jail.local /etc/fail2ban/jail.local")
# 8. 配置 Fail2ban 自定义过滤规则
sshd_local = dedent("""
[INCLUDES]
before = common.conf
[Definition]
failregex = ^%(__prefix_line)sFailed password for .* from <HOST> port \\d+ ssh2$
^%(__prefix_line)sInvalid user .* from <HOST>( port \\d+)?$
^%(__prefix_line)s pam_unix\\(sshd:auth\\): authentication failure; .* rhost=<HOST>.*$
^%(__prefix_line)sFailed publickey for .* from <HOST> port \\d+ ssh2$
^%(__prefix_line)sConnection closed by authenticating user .* <HOST> port \\d+ \\[preauth\\]$
^%(__prefix_line)sDisconnected from <HOST> port \\d+.*
^%(__prefix_line)serror: maximum authentication attempts exceeded for .* from <HOST> port \\d+ ssh2$
ignoreregex =
""").strip()
with open("/tmp/sshd.local", "w") as f:
f.write(sshd_local)
run("sudo cp /tmp/sshd.local /etc/fail2ban/filter.d/sshd.local")
# 9. 重启 Fail2ban
run("sudo systemctl restart fail2ban")
# 10. 添加 alias 和 history 设置
lindows_sh = dedent("""
alias tt='ps -ef | grep http'
alias jj='ps -ef | grep java'
alias nn='netstat -atpln | grep : | sort'
alias ss='ss -ntpln | grep : |sort '
alias pp='netstat -aptln | grep php'
alias mm='netstat -atpln | grep mysql'
HISTTIMEFORMAT="%F %T "
HISTFILESIZE=10000
HISTSIZE=10000
""").strip()
with open("/tmp/lindows.sh", "w") as f:
f.write(lindows_sh)
run("sudo cp /tmp/lindows.sh /etc/profile.d/lindows.sh")
# 11. 立刻生效 alias / history 配置
run("source /etc/profile.d/lindows.sh")
print("\n✅ 全部操作完成!")
print("➡️ 使用 `ssh -p 22222 user@IP` 测试新端口连接")
print("➡️ Fail2ban 已启用,可用 `sudo fail2ban-client status sshd` 查看")
print("➡️ alias 已写入 /etc/profile.d/lindows.sh 并已生效")
print("➡️ 额外端口 33333, 44444, 55555 已对外开放(非 SSH)")
if __name__ == "__main__":
main()
- rocky10 fail2ban 配置
/etc/fail2ban/filter.d/sshd-custom.conf
# /etc/fail2ban/filter.d/sshd-custom.conf
[Definition]
# 匹配 SSH 登录失败的有效用户和无效用户
failregex = ^Failed password for .* from <HOST> port \d+ ssh2$
^Failed password for invalid user .* from <HOST> port \d+ ssh2$
^Connection closed by authenticating user .* <HOST> port \d+ \[preauth\]$
ignoreregex =
/etc/fail2ban/filter.d/sshd-invaliduser.conf
/etc/fail2ban/filter.d/sshd-invaliduser.conf
# Fail2Ban filter for invalid SSH username attempts
[Definition]
failregex = ^Invalid user .* from <HOST> port \d+$
ignoreregex =
/etc/fail2ban/jail.d/lindows.local
# 如果注释异常,最好另起行写注释
# ==============================
# Fail2Ban 自定义安全策略
# 文件:/etc/fail2ban/jail.d/lindows.local
# ==============================
[DEFAULT]
# ------------------------------
# 全局默认配置
# ------------------------------
# 放行 IP(本机 + 信任公网 IP)
ignoreip = 127.0.0.1/8 ::1 119.136.146.103
# 封禁时间(单位:秒),默认 1 小时
bantime = 3600
# 统计尝试的时间窗口(单位:秒),默认 5 分钟
findtime = 300
# 最大失败尝试次数,超出则封禁
maxretry = 1
# 日志后端,auto 自动选择 systemd 或轮询
backend = auto
# ------------------------------
# SSH 主服务安全检测
# /etc/fail2ban/filter.d/sshd.conf
# /etc/fail2ban/filter.d/sshd-custom.conf
# ------------------------------
[sshd]
enabled = true
port = 22222
filter = sshd
logpath = /var/log/secure
[sshd-custom]
enabled = true
port = 22222
filter = sshd-custom
logpath = /var/log/secure
maxretry = 3
bantime = 3600
# ------------------------------
# 随机用户名探测封禁24小时
# /etc/fail2ban/filter.d/sshd-invaliduser.conf
# ------------------------------
[sshd-invaliduser]
enabled = true
port = 22222
filter = sshd-invaliduser
logpath = /var/log/secure
bantime = 86400
-
# 常用命令
dnf install fail2ban
systemctl restart fail2ban
systemctl status fail2ban
fail2ban-server -t
fail2ban-client status
fail2ban-client status sshd
fail2ban-client status sshd-custom
fail2ban-client status sshd-invaliduser
fail2ban-client get sshd-invaliduser banned
fail2ban-client get sshd-invaliduser bantime
firewall-cmd --list-all
firewall-cmd --list-rich-rules
# 总结:
# Jail 不存在 = 配置没生效
# 必须 filter 文件存在,且 jail 名称一致
# 不要用 %(__prefix_line)s 变量
- rocky10 firewall的权限顺序
内核 > nftables > firewalld > Fail2Ban , 如果 nftables 已经禁止所有流量,firewalld 放行是“没用的”。
# Rocky/RHEL 8+ 以上
Linux Kernel (Netfilter)
↑
nftables ← 实际执行规则
↑
firewalld ← 管理 nftables
↑
Fail2Ban ← 动态封 IP
# Centos 7 老系统
Linux Kernel
↑
iptables
↑
firewalld
↑
Fail2Ban
end

浙公网安备 33010602011771号