网络配置与远程管理
本文合并自:03-网络配置与远程管理.md、1-7-Linux网络配置与故障排查.md、03-AB压测与NetworkManager.md
适用环境:RHEL 5 / RHEL 6 / CentOS 6 与 RHEL 7 / CentOS 7 及同系发行版。文中凡 CentOS 6 与 CentOS 7 命令、配置、网卡命名不同之处,均并列给出并标注适用版本,旧写法一律保留(生产环境仍有大量 CentOS 6 存量机器)。
版本适用范围提示:CentOS 7 已于 2024-06-30 结束生命周期(EOL),不再获得官方更新。本文中的
systemctl restart network与/etc/sysconfig/network-scripts/配置方式在 RHEL 8+ / RHEL 9 中已被移除或弃用,新系统应改用 NetworkManager(nmcli/nmtui)管理网络,具体用法见「六、NetworkManager 与 nmcli」;mii-tool(net-tools 包)同样已弃用,建议改用ethtool <网卡>查看链路状态。内容覆盖:TCP/IP 基础回顾、一致性网络设备命名与传统 eth0 命名、
ip命令族与ifconfig/route传统写法、临时与永久 IP 配置、ifcfg-*全字段详解、NetworkManager 与nmcli/nmtui、主机名与名称解析、多 IP 别名/bonding/team/bridge/VLAN/静态路由/MTU 等进阶配置、SSH 远程管理与安全加固、密钥认证与端口转发、scp/sftp/rsync/nc文件传输、分层网络故障排查与抓包分析、ab压力测试、练习与速查表。
一、TCP/IP 基础与通信前提
本节为网络基础理论的必要回顾,属于旁支内容,原文保留。 详见 阶段07
07-01-网络基础与网络配置.md(IP 地址、子网划分、路由与网关的完整讲解)
1.1 IP 地址分类(IPv4)
IPv4 地址是一个 32 位的二进制数字,由 网络地址 和 主机地址 两部分组成。
| 类别 | 网络位 / 主机位 | 首字节范围 | 完整地址范围 | 默认子网掩码 | 用途 |
|---|---|---|---|---|---|
| A 类 | 前 8 位 / 后 24 位 | 1 - 126 | 1.0.0.0 ~ 126.255.255.255 | 255.0.0.0 | 大型网络 |
| B 类 | 前 16 位 / 后 16 位 | 128 - 191 | 128.0.0.0 ~ 191.255.255.255 | 255.255.0.0 | 中型网络 |
| C 类 | 前 24 位 / 后 8 位 | 192 - 223 | 192.0.0.0 ~ 223.255.255.255 | 255.255.255.0 | 小型网络 |
| D 类 | 无网络/主机之分 | 224 - 239 | 224.0.0.0 ~ 239.255.255.255 | - | 组播(Multicast) |
| E 类 | 无网络/主机之分 | 240 - 255 | 240.0.0.0 ~ 255.255.255.255 | - | 实验/军用预留 |
127.0.0.0/8虽处于 A 类地址空间内,但被保留为本地环回,不能作为主机地址分配,因此 A 类的可用首字节范围是1 - 126。
1.2 特殊 IP 地址
| 地址 | 含义 |
|---|---|
0.0.0.0 |
本机或所有地址(监听时表示所有接口) |
255.255.255.255 |
全网广播地址 |
127.0.0.0/8 |
本地环回地址,用于测试本机 TCP/IP 协议栈 |
10.0.0.0/8 |
A 类私网地址 |
172.16.0.0/12 |
B 类私网地址 |
192.168.0.0/16 |
C 类私网地址 |
注意:某些集群软件(如 LVS 的 DR 模式)也会使用环回地址。
1.3 网络通信类型
| 类型 | 说明 | 典型应用 |
|---|---|---|
| 单播(点对点) | 一对一通信 | HTTP、邮件、DNS 查询 |
| 组播(点对多点) | 向一组节点发送数据 | 视频会议、集群心跳 |
| 广播(点对多点) | 向同一广播域所有节点发送 | DHCP、ARP |
1.4 子网掩码与网络号
子网掩码用于将 IP 地址划分为 网络部分 和 主机部分。两者进行按位与运算,可得到网络号。
示例: 192.168.0.183/24
IP: 11000000.10101000.00000000.10110111 (192.168.0.183)
掩码: 11111111.11111111.11111111.00000000 (255.255.255.0)
与: 11000000.10101000.00000000.00000000 (192.168.0.0)
- 网络号:主机位全为
0,如10.1.1.0/24。 - 广播地址:主机位全为
1,如10.1.1.255/24。 - 可用 IP 数量:主机位中除网络号和广播地址外,其余均为可用地址。
网络号相同的节点在默认配置下可直接通信。
1.5 两个节点通信的必要条件
- 物理连通:线缆、交换机、网卡等硬件正常。
- 路由正确:本机知道到达目的地址的路径。
- 通信权限:防火墙、SELinux 等未阻止流量。
1.6 上互联网三要素
| 要素 | 配置文件 / 命令 |
|---|---|
| IP 地址 | /etc/sysconfig/network-scripts/ifcfg-<网卡> |
| 网关(Gateway) | 路由表 / ip r / route -n |
| DNS | /etc/resolv.conf(或 ifcfg 中的 DNS1/DNS2) |
二、网卡与接口命名
2.1 一致性网络设备命名(CentOS 7 / RHEL 7 及以上)
在 RedHat 7 之前,网络接口名称一般为 eth0、eth1 等。这种命名由内核探测顺序决定,随着设备增加和删除,名称可能发生漂移,导致不对称信息(本次开机的 eth0 下次可能变成 eth1)。RedHat 7 起启用 一致性网络设备命名(Consistent Network Device Naming),根据设备类型与固件/拓扑信息分配固定名称,例如 ens33:
en s 33
类型 适配器类型 接口编号
接口类型前缀:
| 前缀 | 类型 |
|---|---|
en |
以太网接口(Ethernet) |
wl |
WLAN 接口(无线局域网,原文写作 w1) |
ww |
WWAN 接口(无线广域网,如 4G 模块) |
适配器类型(第二个字母):
| 字符 | 类型 |
|---|---|
o |
板载设备(onboard),编号取自固件提供的索引 |
s |
可热拔插插槽设备(hotplug slot) |
p |
PCI 接口,按总线/插槽位置命名 |
常见命名实例对照:
| 名称 | 含义 |
|---|---|
eno1 |
板载第 1 块以太网卡(物理服务器最常见) |
ens33 |
位于热插拔插槽 33 的以太网卡(VMware 虚拟机最常见) |
enp0s3 |
PCI 总线 0、插槽 3 上的以太网卡(VirtualBox/KVM 常见) |
enp0s25 |
PCI 总线 0、插槽 25 上的以太网卡 |
ens192 / ens160 |
VMware 使用 VMXNET3 网卡时的常见名称 |
eth0 |
传统内核顺序命名(CentOS 6 默认,CentOS 7 关闭新命名规则后也会出现) |
lo |
本地环回接口 |
virbr0 |
libvirt 创建的虚拟桥接口 |
命名规则的优先级顺序(依次尝试,成功即采用):
- 固件/BIOS 提供的板载设备索引 →
eno1 - 固件/BIOS 提供的 PCI Express 热插拔槽索引 →
ens33 - 硬件接口的物理位置 →
enp0s3 - 接口的 MAC 地址 →
enx001c2900bcde(默认不启用) - 以上都不可用时回退传统内核命名 →
eth0
2.2 改回传统 eth0 命名(CentOS 7)
大量老脚本、监控模板、教学环境依赖 eth0,可通过内核参数关闭一致性命名。
方法一:修改 GRUB2 默认内核参数(推荐,永久生效)
sudo vim /etc/default/grub
在 GRUB_CMDLINE_LINUX 一行中追加两个参数:
GRUB_CMDLINE_LINUX="rd.lvm.lv=centos/root rd.lvm.lv=centos/swap rhgb quiet net.ifnames=0 biosdevname=0"
重新生成 GRUB 配置并重启:
# BIOS 引导(传统分区)
sudo grub2-mkconfig -o /boot/grub2/grub.cfg
# UEFI 引导
sudo grub2-mkconfig -o /boot/efi/EFI/centos/grub.cfg
sudo reboot
方法二:安装系统时在启动菜单按 Tab(或 e)临时追加 net.ifnames=0 biosdevname=0,装完即为 eth0。
方法三:通过 udev 规则手工固定名称(按 MAC 绑定,适合多网卡顺序混乱的场景)
sudo vim /etc/udev/rules.d/70-persistent-net.rules
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="00:0c:29:75:88:e4", NAME="eth0"
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="00:0c:29:75:88:ee", NAME="eth1"
- CentOS 6:
/etc/udev/rules.d/70-persistent-net.rules由系统自动生成。克隆虚拟机后该文件里保留着源机器的 MAC,会出现「网卡变成 eth1、eth0 找不到」的经典问题。处理方法是删除该文件(或删掉旧条目并把新条目的NAME改为eth0),同时同步ifcfg-eth0中的HWADDR,然后重启。- CentOS 7:该文件默认不存在,改名后必须同步修改
/etc/sysconfig/network-scripts/ifcfg-*中的DEVICE/NAME以及文件名本身,否则网卡起不来。- 参数
net.ifnames=0关闭 systemd/udev 的一致性命名,biosdevname=0关闭 Dell 的 biosdevname 命名(会产生em1、p1p1这类名字)。两者要一起写。
2.3 查看有哪些网卡(多种手段)
# 查看所有接口及 IP(CentOS 7 首选,CentOS 6 也可用)
ip addr
ip a
ip a s # show 的缩写
ip -br addr # 单行简表输出(CentOS 7.4+),一屏看完所有接口状态
ip link # 只看链路层信息(含 MAC、MTU、state)
ip -s link # 附带收发包统计
# 传统命令(CentOS 6 首选;CentOS 7 需 yum install net-tools)
ifconfig # 只显示已启用(UP)的网卡
ifconfig -a # 显示全部网卡,含 DOWN 状态的
ifconfig eth0 # 查看指定网卡
# NetworkManager 视角(CentOS 7)
nmcli device
nmcli device status
nmcli device show ens33 # 查看某设备的详细信息(速率、MAC、当前 IP、DNS)
nmcli -f DEVICE,TYPE,STATE device status
# 硬件层面确认网卡是否被识别、驱动是否加载
lspci | grep -i ethernet
lspci | grep -i net
lspci -nnk | grep -A 3 -i ethernet # 顺带看驱动(Kernel driver in use)
lshw -C network # 需安装 lshw,信息最全
ethtool -i eth0 # 查看某网卡使用的驱动与固件版本
dmesg | grep -i eth # 内核启动时的网卡识别日志
# 只列出接口名
ls /sys/class/net/
cat /proc/net/dev
排查思路:
lspci能看到网卡但ip a没有对应接口 → 驱动未加载(缺少内核模块);ip a有接口但没有 IP → 配置问题;两者都没有 → 硬件或虚拟机未添加网卡。
2.4 网卡的启用与停用(up / down)
# CentOS 7 推荐:ip 命令
sudo ip link set enp0s25 up
sudo ip link set enp0s25 down
sudo ip l set dev enp0s25 up # 等价写法
sudo ip l set dev enp0s25 down
# 传统写法(CentOS 6 / CentOS 7 装了 net-tools 均可)
ifconfig eth1 up # 启用网卡
ifconfig eth1 down # 禁用网卡
# 使用 initscripts 脚本(会读取 ifcfg 文件,连带套用 IP 配置)
ifup eth0
ifdown eth0
# NetworkManager 方式(CentOS 7)
nmcli device connect ens33
nmcli device disconnect ens33
nmcli connection up ens33
nmcli connection down ens33
三者的区别必须分清:
ip link set up只是把链路层拉起来,不会套用任何 IP 配置。ifup/ifdown会读取ifcfg-*文件,套用其中的 IP、网关、DNS。nmcli con up由 NetworkManager 激活某个「连接配置」,同样会套用完整配置。
2.5 链路状态检查:mii-tool
mii-tool eth0 # CentOS 6 写法
sudo mii-tool enp0s25 # CentOS 7 写法(需 net-tools)
常见输出:
| 输出 | 含义 |
|---|---|
link ok |
网卡已连接,链路正常 |
no link |
网卡已启用但网线未连接 |
Invalid argument |
物理连接存在但网卡未启用(down) |
| 其他报错 | 可能网卡未驱动或硬件问题 |
配合启用/禁用网卡验证:
ifconfig eth1 up # 启用网卡
ifconfig eth1 down # 禁用网卡
link ok表示网卡物理连接正常,但不代表可以正常访问外网。mii-tool属于已弃用的 net-tools 包,且对新型网卡(万兆、VMXNET3)常报SIOCGMIIPHY on 'ens33' failed: Operation not supported,此时改用ethtool。
2.6 速率与双工:ethtool
ethtool eth0 # 查看网卡工作模式
输出关键字段:
Speed: 100Mb/s:速率Duplex: Full:全双工Auto-negotiation: on:自动协商Link detected: yes:链路已连接(等价于mii-tool的link ok)
临时修改速率/双工:
# 改为 10M、半双工、关闭自动协商
ethtool -s eth0 speed 10 duplex half autoneg off
# 改回 100M、全双工、开启自动协商
ethtool -s eth0 speed 100 duplex full autoneg on
其他常用子命令:
ethtool -i eth0 # 驱动与固件版本
ethtool -S eth0 # 网卡级别的收发/错误统计(丢包排查关键)
ethtool -k eth0 # 查看网卡卸载特性(TSO/GSO/GRO/LRO)
ethtool -K eth0 tso off # 关闭 TCP 分片卸载(排查诡异丢包时用)
ethtool -g eth0 # 查看/设置环形缓冲区大小
ethtool -p eth0 10 # 让网口指示灯闪 10 秒,用于机房定位物理网口
- 可通过
scp传输大文件对比不同速率下的实际传输速度,效果明显。ethtool -s的修改重启后失效;需要永久生效可写入ifcfg-eth0的ETHTOOL_OPTS="speed 100 duplex full autoneg on"。
三、查看与临时配置网络
3.1 ip 命令族(CentOS 7 首选,CentOS 6 亦可用)
ip 命令来自 iproute2 包,是 ifconfig/route/arp/netstat 的统一替代者,语法为 ip [选项] 对象 命令 参数。
常用对象:
| 对象 | 缩写 | 作用 | 替代的旧命令 |
|---|---|---|---|
address |
a、addr |
管理接口地址 | ifconfig |
link |
l |
管理网络设备(链路层) | ifconfig、mii-tool |
route |
r |
管理路由表 | route |
neighbour |
n、neigh |
管理 ARP/邻居表 | arp |
maddress |
m |
组播地址 | ipmaddr |
rule |
— | 策略路由规则 | — |
netns |
— | 网络命名空间 | — |
tunnel |
— | 隧道 | iptunnel |
ip addr:地址管理
# 查看
ip addr # 全部接口
ip addr show ens33 # 指定接口
ip a s ens33
ip -4 addr # 只看 IPv4
ip -6 addr # 只看 IPv6
ip -br -c addr # 简表 + 彩色输出
# 添加临时 IP(立即生效,重启失效)
sudo ip addr add 192.168.0.100/24 dev enp0s25
sudo ip a add 192.168.0.100/24 dev enp0s25
# 添加时同时指定广播地址与标签(标签即传统的别名 eth0:0)
sudo ip addr add 192.168.0.101/24 broadcast 192.168.0.255 dev eth0 label eth0:0
# 删除 IP
sudo ip addr del 192.168.0.100/24 dev enp0s25
sudo ip a del 192.168.0.100/24 dev enp0s25
# 清空某接口上的所有地址
sudo ip addr flush dev enp0s25
# 动态获取 IP(DHCP 客户端,临时)
sudo dhclient enp0s25
sudo dhclient -r enp0s25 # 释放租约
sudo dhclient -v enp0s25 # 显示交互过程,排查 DHCP 问题
ip addr add是「增加」而非「替换」:一个接口可以同时拥有多个 IP,第二个地址会以secondary标记显示。若想替换,先del或flush旧地址。
ip link:链路层管理
ip link # 查看所有设备
ip link show ens33
ip -s link show ens33 # 附收发包与错误统计
sudo ip link set ens33 up # 启用
sudo ip link set ens33 down # 停用
sudo ip link set ens33 mtu 9000 # 修改 MTU(临时)
sudo ip link set ens33 address 00:0c:29:aa:bb:cc # 修改 MAC(需先 down)
sudo ip link set ens33 name eth0 # 重命名接口(需先 down)
sudo ip link set ens33 promisc on # 开启混杂模式(抓包用)
sudo ip link set ens33 multicast on
ip route:路由表管理
# 查看路由表
ip route
ip r
ip route show
ip route list
ip route get 8.8.8.8 # 查询到某目标实际会走哪条路由、源 IP 是什么(排障利器)
# 默认路由(网关)
sudo ip route add default via 192.168.0.1
sudo ip r add default via 192.168.0.1 dev eth0
sudo ip route del default
sudo ip route replace default via 192.168.0.254
# 主机路由与网络路由
sudo ip route add 10.1.1.0/24 via 192.168.0.254
sudo ip route add 10.1.1.5/32 via 192.168.0.254 dev eth0
sudo ip route del 10.1.1.0/24
# 指定 metric(多条同目标路由时数值小的优先)
sudo ip route add 10.2.0.0/16 via 192.168.0.254 metric 100
# 查看指定路由表(策略路由场景)
ip route show table main
ip route show table all
ip neigh:ARP / 邻居表
ip neighbour # 查看 ARP 表(联系过的 IP↔MAC 映射)
ip neigh
ip n
ip neigh show dev eth0
sudo ip neigh add 192.168.0.50 lladdr 00:0c:29:11:22:33 dev eth0 # 静态绑定
sudo ip neigh del 192.168.0.50 dev eth0
sudo ip neigh flush all # 清空 ARP 缓存(IP 冲突/换设备后必做)
sudo ip neigh flush dev eth0
# 传统写法
arp -n # 查看 ARP 表(数字形式)
arp -a
sudo arp -d 192.168.0.50 # 删除某条 ARP 记录
sudo arp -s 192.168.0.50 00:0c:29:11:22:33 # 静态绑定
ARP 表中的状态含义:
| 状态 | 含义 |
|---|---|
REACHABLE |
最近确认可达 |
STALE |
记录尚在但需重新验证 |
DELAY / PROBE |
正在探测 |
FAILED |
探测失败,对方不存在或不响应 |
INCOMPLETE |
请求已发出但未收到应答(常见于 IP 不存在) |
3.2 ifconfig 与 route 的传统写法(CentOS 6 首选)
ifconfig 查看
ifconfig # 查看所有启用网卡
ifconfig -a # 包含未启用的网卡
ifconfig eth0 # 查看指定网卡
CentOS 6 输出字段说明:
eth0 Link encap:Ethernet HWaddr 10:C3:7B:69:48:B1
inet addr:10.0.0.200 Bcast:10.0.0.255 Mask:255.255.255.0
inet6 addr: fe80::12c3:7bff:fe69:48b1/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:... errors:0 dropped:0 ...
TX packets:... errors:0 dropped:0 ...
| 字段 | 含义 |
|---|---|
HWaddr |
MAC 物理地址 |
inet addr |
IPv4 地址 |
Bcast |
广播地址 |
Mask |
子网掩码 |
UP |
网卡已启用 |
RUNNING |
网线已连接 |
MTU:1500 |
最大传输单元 |
RX/TX packets |
收/发数据包统计(含 errors、dropped) |
CentOS 7 的 ifconfig 输出格式有变化(字段名改为 inet/netmask/broadcast/ether):
ens37: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.2.73 netmask 255.255.255.0 broadcast 192.168.2.255
inet6 fe80::7ea2:3cc1:a899:773c prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:75:88:e4 txqueuelen 1000 (Ethernet)
RX packets 502 bytes 54467 (53.1 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 29 bytes 4664 (4.5 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
| 字段 | 含义 |
|---|---|
RUNNING |
接口状态,表示可用(网线已连接) |
ether 00:0c:29:75:88:e4 |
MAC 地址 |
inet 192.168.2.73 |
IPv4 地址 |
inet6 fe80::... |
IPv6 地址 |
broadcast 192.168.2.255 |
广播地址 |
mtu 1500 |
最大传输单元 |
txqueuelen 1000 |
发送队列长度 |
CentOS 7 最小化安装默认不带
ifconfig,需要yum -y install net-tools(同时提供netstat、route、arp、mii-tool)。
ifconfig 临时修改 IP
ifconfig eth0 10.0.0.200 netmask 255.255.255.0
# 等价的 CIDR 写法
ifconfig eth0 10.0.0.200/24
# 同时指定广播地址并启用
ifconfig eth0 10.0.0.200 netmask 255.255.255.0 broadcast 10.0.0.255 up
# 修改 MTU
ifconfig eth0 mtu 9000
使用 ifconfig 修改立即生效,但 重启网络或系统后失效。
临时修改 MAC 地址
ifconfig eth0 down
ifconfig eth0 hw ether 00:01:22:AB:EF:CD
ifconfig eth0 up
需先 down 网卡再修改,再 up。等价的 ip 写法:
sudo ip link set dev eth0 down
sudo ip link set dev eth0 address 00:01:22:AB:EF:CD
sudo ip link set dev eth0 up
route 命令管理路由
route # 查看路由表(会反查主机名,较慢)
route -n # 以数字形式显示,不反查 DNS(推荐)
netstat -rn # 等价查看方式
# 添加默认网关
route add default gw 192.168.0.1
route add default gw 192.168.0.1 dev eth0
# 删除默认网关
route del default gw 192.168.0.1
# 添加/删除网络路由
route add -net 10.1.1.0 netmask 255.255.255.0 gw 192.168.0.254
route add -net 10.1.1.0/24 gw 192.168.0.254
route del -net 10.1.1.0/24
# 添加主机路由
route add -host 10.1.1.5 gw 192.168.0.254
# 屏蔽某网段(走黑洞)
route add -net 10.9.9.0/24 reject
route -n 输出各列含义:
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 192.168.0.1 0.0.0.0 UG 0 0 0 eth0
192.168.0.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
| 列 | 含义 |
|---|---|
Destination |
目标网络,0.0.0.0 表示默认路由 |
Gateway |
下一跳网关,0.0.0.0 表示目标在本网段可直达 |
Genmask |
目标网络掩码,255.255.255.255 为主机路由 |
Flags |
U 路由可用、G 需经网关、H 目标为主机、! 拒绝 |
Metric |
路由开销,多条同目标路由时数值小的优先 |
Iface |
出接口 |
排障时重点关注带有
UG标识的默认路由行;缺少默认路由则只能访问本网段。
3.3 临时配置为何重启失效
ip/ifconfig/route/arp 这类命令都是 直接修改内核运行时状态:
- 修改立即生效,无需重启服务,适合应急抢修与临时测试。
- 内核状态不会写入任何磁盘文件,因此 重启网络服务或重启系统后全部丢失,恢复为配置文件中的内容。
- 反之,只修改配置文件而不重启网络服务/不重载连接,内核状态不变,配置也不会生效。
因此完整的配置流程是:改配置文件(持久化)→ 重启网络服务或 nmcli con reload && nmcli con up(让内核生效)。抢修时可以先用 ip 命令让业务恢复,再补上配置文件。
3.4 查看系统与内核信息
uname 常用选项:
| 选项 | 作用 |
|---|---|
-a |
显示全部信息 |
-r |
内核版本 |
-m |
硬件架构(如 x86_64) |
-n |
主机名 |
-s |
操作系统名称 |
-v |
内核编译版本 |
-p |
处理器类型 |
uname -a
# Linux qianyun.cluster.com 2.6.32-279.el6.x86_64 ... x86_64 GNU/Linux
发行版版本:
cat /etc/redhat-release
# CentOS release 6.5 (Final)
# CentOS Linux release 7.9.2009 (Core)
cat /etc/os-release # CentOS 7 起提供的标准化文件
四、永久配置:网卡配置文件
四之前的前置检查
修改前建议先关闭防火墙与 SELinux,避免配置生效后仍无法通信:
CentOS 7 默认防火墙为 firewalld:
iptables -F仅清空 iptables 规则,不会影响 firewalld 管理规则。正确做法是使用systemctl stop firewalld停止 firewalld 服务,或通过firewall-cmd放行所需端口(如firewall-cmd --add-port=2049/tcp --permanent && firewall-cmd --reload)。详见 阶段07 防火墙与 SELinux 相关文档(iptables / firewalld / SELinux 完整讲解)
# 临时停止 firewalld(CentOS 7 默认防火墙)
sudo systemctl stop firewalld
# CentOS 6 关闭 iptables 服务
service iptables stop
chkconfig iptables off
# 临时清空 iptables 规则(仅对原生 iptables 生效)
sudo iptables -F
# 临时关闭 SELinux
sudo setenforce 0
# 查看 SELinux 状态
getenforce
永久关闭 SELinux:
sudo vim /etc/selinux/config
修改配置项:
SELINUX=disabled
4.1 配置文件位置与命名
/etc/sysconfig/network-scripts/ifcfg-<设备名>
- CentOS 6:
/etc/sysconfig/network-scripts/ifcfg-eth0 - CentOS 7:
/etc/sysconfig/network-scripts/ifcfg-ens33(或ifcfg-enp0s25、ifcfg-eno1)
# CentOS 6
sudo vim /etc/sysconfig/network-scripts/ifcfg-eth0
# CentOS 7
sudo vim /etc/sysconfig/network-scripts/ifcfg-ens33
sudo vim /etc/sysconfig/network-scripts/ifcfg-enp0s25
文件名中的设备名必须与文件内
DEVICE=的值一致,否则网卡起不来。修改前先备份:cp ifcfg-eth0{,.bak}。
4.2 ifcfg-* 字段全解
| 参数 | 说明 | 适用版本 |
|---|---|---|
DEVICE |
设备名,必须与文件名 ifcfg-xxx 的后缀及真实网卡名一致 |
6 / 7 |
NAME |
连接名称(NetworkManager 中显示的 NAME 列),CentOS 7 常与 DEVICE 同名 |
7 |
TYPE |
接口类型:Ethernet、Bridge、Bond、Team、Vlan、Wireless |
6 / 7 |
BOOTPROTO |
地址获取方式:static(静态)、none(静态,CentOS 7 惯用)、dhcp(动态)、bootp |
6 / 7 |
ONBOOT |
开机(或重启网络时)是否启用该网卡,yes/no。新装系统最常见的坑就是默认 no 导致没网 |
6 / 7 |
IPADDR |
静态 IP 地址;多个地址写 IPADDR1、IPADDR2… |
6 / 7 |
NETMASK |
子网掩码,如 255.255.255.0 |
6 / 7 |
PREFIX |
掩码位数写法,如 24。与 NETMASK 二选一,同时写时 PREFIX 优先 |
6 / 7 |
GATEWAY |
默认网关;也可写在 /etc/sysconfig/network 中对所有网卡生效 |
6 / 7 |
DNS1 / DNS2 / DNS3 |
DNS 服务器,会被写入 /etc/resolv.conf |
6 / 7 |
DOMAIN |
搜索域,对应 resolv.conf 的 search |
6 / 7 |
DEFROUTE |
是否将此连接的网关作为系统默认路由(多网卡时只让一块为 yes) |
7 |
NM_CONTROLLED |
是否受 NetworkManager 控制。no 表示由 network.service 管理,服务器传统上建议 no |
6 / 7 |
UUID |
连接的唯一标识,由 NetworkManager 生成;克隆虚拟机时应删除或用 uuidgen 重新生成 |
7 |
HWADDR |
绑定的网卡 MAC 地址。与实际 MAC 不符时网卡无法启动(克隆虚拟机的典型故障),可直接删掉此行 | 6 / 7 |
MACADDR |
强制设置 MAC 地址(与 HWADDR 含义相反,不可同时使用) |
6 / 7 |
USERCTL |
是否允许普通用户启停该网卡,一般 no |
6 / 7 |
PEERDNS |
DHCP 时是否用服务器下发的 DNS 覆盖 /etc/resolv.conf,设 no 可保留手工 DNS |
6 / 7 |
PEERROUTES |
DHCP 时是否接受服务器下发的路由 | 7 |
IPV4_FAILURE_FATAL |
IPv4 配置失败时是否认为整个连接失败 | 7 |
IPV6INIT |
是否启用 IPv6,不需要时设 no |
6 / 7 |
IPV6_AUTOCONF |
IPv6 是否自动配置 | 7 |
BROADCAST |
广播地址,一般可省略由系统计算 | 6 |
NETWORK |
网络号,一般可省略 | 6 |
MTU |
最大传输单元,如 1500、9000(巨帧) |
6 / 7 |
ETHTOOL_OPTS |
启动网卡时传给 ethtool 的参数,如 "speed 1000 duplex full autoneg on" |
6 / 7 |
ZONE |
firewalld 区域,如 public、trusted |
7 |
PROXY_METHOD / BROWSER_ONLY |
代理相关,CentOS 7 默认生成,保持默认即可 | 7 |
SLAVE / MASTER |
bonding 从属关系(见进阶配置) | 6 / 7 |
TEAM_MASTER / TEAM_CONFIG |
team 组队相关 | 7 |
BRIDGE / STP / DELAY |
桥接相关 | 6 / 7 |
VLAN / PHYSDEV / VLAN_ID |
VLAN 子接口相关 | 6 / 7 |
4.3 静态 IP 完整配置实操
CentOS 6 写法(/etc/sysconfig/network-scripts/ifcfg-eth0):
DEVICE=eth0
TYPE=Ethernet
BOOTPROTO=static # 或 none
ONBOOT=yes
NM_CONTROLLED="no"
IPADDR=10.0.0.200
NETMASK=255.255.255.0 # 或写 PREFIX=24
GATEWAY=10.0.0.1
DNS1=10.0.0.1
DNS2=8.8.8.8
CentOS 7 写法(/etc/sysconfig/network-scripts/ifcfg-enp0s25):
DEVICE="enp0s25"
NAME="enp0s25"
TYPE=Ethernet
BOOTPROTO=static
NM_CONTROLLED=no
ONBOOT=yes
DEFROUTE=yes
IPADDR=192.168.0.200
NETMASK=255.255.255.0
GATEWAY=192.168.0.1
DNS1=223.5.5.5
DNS2=192.168.0.1
IPV6INIT=no
CentOS 7 使用 PREFIX 与 UUID 的完整示例:
TYPE=Ethernet
BOOTPROTO=none
NAME=ens33
DEVICE=ens33
UUID=17883cd1-86c8-4ec3-b254-5ce6d462e929
ONBOOT=yes
DEFROUTE=yes
IPADDR=192.168.224.101
PREFIX=24
GATEWAY=192.168.224.2
DNS1=223.5.5.5
DNS2=119.29.29.29
IPV4_FAILURE_FATAL=no
IPV6INIT=no
配置完成后重启网络服务(见 4.6),然后验证:
ip a s ens33 # 确认 IP 已生效
ip r # 确认默认路由存在
cat /etc/resolv.conf # 确认 DNS 已写入
ping -c 2 192.168.0.1 # 网关连通性
ping -c 2 223.5.5.5 # 外网连通性
ping -c 2 www.baidu.com # DNS 解析
4.4 DHCP 自动获取配置
CentOS 6:
DEVICE=eth0
BOOTPROTO=dhcp
ONBOOT=yes
NM_CONTROLLED="no"
CentOS 7:
TYPE=Ethernet
BOOTPROTO=dhcp
NAME=ens33
DEVICE=ens33
ONBOOT=yes
DEFROUTE=yes
PEERDNS=yes
PEERROUTES=yes
命令行临时获取:
sudo dhclient ens33 # 获取地址
sudo dhclient -r ens33 # 释放地址
sudo dhclient -v ens33 # 显示 DISCOVER/OFFER/REQUEST/ACK 交互,排查 DHCP 故障
# 查看获取到的租约信息
cat /var/lib/dhclient/dhclient-*.lease
cat /var/lib/dhclient/dhclient.leases
DHCP 方式下,若不希望服务器下发的 DNS 覆盖手工配置的
/etc/resolv.conf,设置PEERDNS=no。DHCP 服务端搭建详见 阶段09
09-01-DHCP服务.md
4.5 全局网络配置文件 /etc/sysconfig/network
sudo vim /etc/sysconfig/network
CentOS 6 内容示例:
NETWORKING=yes
HOSTNAME=qianyun.cluster.com
GATEWAY=10.0.0.1
NETWORKING_IPV6=no
CentOS 7 内容示例(主机名已迁移到 /etc/hostname):
NETWORKING=yes
GATEWAY=192.168.0.1
| 参数 | 说明 |
|---|---|
NETWORKING |
是否启用网络功能,必须为 yes |
HOSTNAME |
主机名(仅 CentOS 6;CentOS 7 用 /etc/hostname) |
GATEWAY |
全局默认网关,对所有网卡生效;ifcfg 文件中的 GATEWAY 优先级更高 |
NETWORKING_IPV6 |
是否启用 IPv6 |
NOZEROCONF |
设为 yes 可去掉 169.254.0.0/16 的自动路由 |
若
NETWORKING=no,网络服务可能不可用,且不能通过简单重启恢复。
4.6 重启网络服务(各版本命令并列)
# ---------- CentOS 6 / RHEL 6 ----------
service network restart
service network stop
service network start
service network status
/etc/init.d/network restart # 等价写法
chkconfig network on # 设置开机自启
# ---------- CentOS 7 / RHEL 7(两套并存,按管理方式选择)----------
# 传统 network.service(配合 NM_CONTROLLED=no 使用)
sudo systemctl restart network
sudo systemctl status network
sudo systemctl enable network
# NetworkManager 方式(配合 nmcli 使用)
sudo systemctl restart NetworkManager
sudo nmcli connection reload # 重新读取磁盘上的 ifcfg 文件
sudo nmcli connection up ens33 # 重新激活连接
# ---------- 只重启单块网卡(6 / 7 通用,影响面更小)----------
ifdown eth0 && ifup eth0
sudo ifdown ens33 && sudo ifup ens33
# ---------- RHEL 8+ / RHEL 9 ----------
# network.service 已被移除,只有 NetworkManager
sudo nmcli connection reload
sudo nmcli connection up ens33
sudo systemctl restart NetworkManager
远程操作警告:
ifdown eth0 && ifup eth0用&&连接是必须的写法,但通过 SSH 执行时ifdown一执行会话就断了,后半句不会被执行,导致机器彻底失联。远程改网络的安全做法:
- 使用
nmcli con up(原子切换,不先断后连);- 或
nohup bash -c 'sleep 2; systemctl restart network' &让命令在会话断开后继续;- 或事先确认有 VNC / IPMI / 云控制台等带外通道。
五、NetworkManager 与 nmcli(CentOS 7 及以上)
第四节使用的 /etc/sysconfig/network-scripts/ifcfg-* 加 systemctl restart network 是 CentOS 6/7 的传统做法,在 RHEL 8+ / RHEL 9 中 network.service(initscripts 包)已被移除,网络配置一律由 NetworkManager 负责。本节补齐这套替代方案,避免只知道旧命令、上了新系统无从下手。
NetworkManager 是监控和管理网络的服务。命令行工具(nmcli)和图形化工具(nmtui、nm-connection-editor)将网络配置信息保存在 /etc/sysconfig/network-scripts 目录中(RHEL 7/8)或 /etc/NetworkManager/system-connections/(RHEL 9 默认 keyfile 格式)。Linux 网络配置可使用命令行工具、图形化界面工具、配置文件三种方式,RHEL 7 起官方推荐使用命令行工具 nmcli 配置网络 IP 地址信息。
5.1 本节目标
- 使用 nmcli 和 NetworkManager 管理网络设备。
- 通过编辑配置文件修改网络设置。
- 配置和测试系统主机名和名称解析。
5.2 连接与设备:两个必须分清的概念
| 概念 | 英文 | 含义 | 查看命令 |
|---|---|---|---|
| 设备 | device | 真实存在的网卡(如 enp0s25、ens33),由内核识别 |
nmcli dev status |
| 连接 | connection | 一套配置方案(IP、网关、DNS、是否自启),可以有多个,绑定到某个设备 | nmcli con show |
RedHat 7 中有网卡设备和网卡连接两种东西。网卡设备是真实的网卡,网卡连接是网卡的一个配置文件,需要将网卡关联到网卡配置文件上才能正常使用。
理解要点:
- 一个设备上可以定义多个连接(如「公司静态 IP」和「家里 DHCP」),但同一时刻只有一个处于激活状态。
- 激活连接靠
nmcli con up <连接名>,不是靠ip link set up;只ip命令启用设备并不会套用任何 IP 配置。 - NetworkManager 把配置写在
/etc/NetworkManager/system-connections/(RHEL 9 默认 keyfile 格式)或仍兼容读写ifcfg-*文件(RHEL 7/8)。
手工改了 ifcfg 文件之后必须执行
nmcli con reload:NetworkManager 只在启动时和收到 reload 指令时读取磁盘上的配置文件,它内存中保存的是旧值。若跳过 reload 直接nmcli con up,激活的仍是旧配置,会出现「文件里明明写对了、生效的却是老 IP」这类费时的假故障。
# 手工编辑 ifcfg 后的正确顺序
sudo vim /etc/sysconfig/network-scripts/ifcfg-enp0s25
sudo nmcli con reload # 重新读取磁盘配置
sudo nmcli con up enp0s25 # 重新激活该连接
5.3 nmcli 命令摘要
nmcli 的对象(可缩写):general(g)、networking(n)、radio(r)、connection(c/con)、device(d/dev)、agent、monitor。
# ---------- general:NetworkManager 整体状态 ----------
nmcli general # 总体状态
nmcli general status
nmcli general hostname # 查看主机名
nmcli general hostname newname # 修改主机名(等价 hostnamectl set-hostname)
nmcli general permissions # 当前用户可执行的操作权限
nmcli general logging # 日志级别
# ---------- networking:网络总开关 ----------
nmcli networking on # 打开全部网络
nmcli networking off # 关闭全部网络(等价于飞行模式)
nmcli networking connectivity # 连通性状态:none/portal/limited/full
# ---------- device:物理设备 ----------
nmcli dev status # 列出物理设备的状态
nmcli dev show # 所有设备详细信息
nmcli dev show ens33 # 单个设备详细信息(速率、MAC、IP、DNS)
nmcli dev dis <dev> # 关闭物理连接(disconnect)
nmcli dev conn <dev> # 打开物理连接(connect)
nmcli dev wifi list # 扫描无线网络
# ---------- connection:连接配置 ----------
nmcli con show # 列出所有连接(含未激活的)
nmcli con show --active # 只列出已激活连接
nmcli con show "name" # 查看某连接的全部参数
nmcli con up "name" # 激活连接
nmcli con down "name" # 关闭连接
nmcli con add # 添加连接
nmcli con mod # 修改连接
nmcli con del # 删除连接
nmcli con reload # 重新读取磁盘配置文件
nmcli con edit "name" # 进入交互式编辑器
5.4 查看状态与网络信息
# 查看所有设备及其状态(connected / disconnected / unmanaged)
nmcli dev status
# 查看所有连接(含未激活的)
nmcli con show
# 查看某个连接的全部参数(属性非常多,可配合 grep)
nmcli con show static-eth0
nmcli con show static-eth0 | grep -E 'ipv4.(method|addresses|gateway|dns)'
# 查看设备的详细信息(速率、MAC、当前 IP)
nmcli dev show enp0s25
查看全部连接的实际输出:
[root@server ~]# nmcli conn show
NAME UUID TYPE DEVICE
Wired connection 1 4057b67c-031d-309c-ac43-5e0afaa3c1b8 802-3-ethernet ens37
ens33 17883cd1-86c8-4ec3-b254-5ce6d462e929 802-3-ethernet ens33
virbr0 083789d4-f752-4ba6-aa8a-5d156bef98e8 bridge virbr0
查看单个网卡(连接)信息:
[root@server ~]# nmcli conn show "ens33"
connection.id: ens33
connection.uuid: 17883cd1-86c8-4ec3-b254-5ce6d462e929
connection.stable-id: --
connection.interface-name: ens33
connection.type: 802-3-ethernet
connection.autoconnect: yes
connection.autoconnect-priority: 0
connection.timestamp: 1545900407
connection.read-only: no
connection.permissions:
connection.zone: --
connection.master: --
connection.slave-type: --
查看网卡物理设备信息:
[root@server ~]# nmcli device status
DEVICE TYPE STATE CONNECTION
virbr0 bridge connected virbr0
ens33 ethernet connected ens33
ens37 ethernet connected Wired connection 1
lo loopback unmanaged --
virbr0-nic tun unmanaged --
设备 STATE 常见取值:
| 状态 | 含义 |
|---|---|
connected |
已激活某个连接,配置已生效 |
disconnected |
设备存在但未激活任何连接 |
unmanaged |
不受 NetworkManager 管理(通常因 NM_CONTROLLED=no) |
unavailable |
设备不可用(如网线未插、未 up) |
connecting |
正在激活中 |
nmcli dev status中出现unmanaged表示该设备被排除在 NetworkManager 管理之外,通常就是 ifcfg 文件里写了NM_CONTROLLED=no(见 5.8)。
5.5 新建连接(con add)
新建静态 IP 连接:
sudo nmcli con add type ethernet con-name static-eth0 ifname enp0s25 \
ipv4.method manual \
ipv4.addresses 192.168.0.100/24 \
ipv4.gateway 192.168.0.1 \
ipv4.dns 223.5.5.5
参数含义:
| 参数 | 说明 |
|---|---|
type ethernet |
连接类型(还可为 bond、bridge、team、vlan、wifi 等) |
con-name |
连接名称,自定义,后续 up/mod 都用它 |
ifname |
绑定的物理设备名 |
ipv4.method manual |
静态配置;auto 相当于 DHCP |
ipv4.addresses |
地址加掩码位数,多个地址用逗号分隔 |
ipv4.gateway |
默认网关 |
ipv4.dns |
DNS 服务器,多个用逗号分隔,如 223.5.5.5,119.29.29.29 |
新建 DHCP 连接:
sudo nmcli con add type ethernet con-name dhcp-eth0 ifname enp0s25 ipv4.method auto
新建的连接默认 connection.autoconnect yes(等价于旧的 ONBOOT=yes),如需关闭:
sudo nmcli con mod static-eth0 connection.autoconnect no
nmcli con add执行后会立即在/etc/sysconfig/network-scripts/下生成对应的ifcfg-<con-name>文件,可以打开对照学习字段映射关系。
5.6 修改、激活与重载(con mod / up / down / reload / delete)
# 修改已有连接的属性(改完需要重新激活才生效)
sudo nmcli con mod static-eth0 ipv4.addresses 192.168.0.200/24
sudo nmcli con mod static-eth0 ipv4.dns "223.5.5.5 119.29.29.29"
sudo nmcli con mod static-eth0 ipv4.method auto # 改回 DHCP
# 追加/移除单个值(属性名前加 + 或 -)
sudo nmcli con mod static-eth0 +ipv4.addresses 192.168.0.201/24
sudo nmcli con mod static-eth0 -ipv4.dns 119.29.29.29
# 激活 / 停用连接
sudo nmcli con up static-eth0
sudo nmcli con down static-eth0
# 重新读取磁盘上的配置文件(手工编辑 ifcfg / keyfile 后必做)
sudo nmcli con reload
# 删除连接
sudo nmcli con delete static-eth0
更多实用修改示例:
# 修改连接名称:把 "Wired connection 1" 改为 abc
nmcli con modify "Wired connection 1" con-name abc
[root@server ~]# nmcli con show
NAME UUID TYPE DEVICE
abc 4057b67c-031d-309c-ac43-5e0afaa3c1b8 802-3-ethernet ens37
ens33 17883cd1-86c8-4ec3-b254-5ce6d462e929 802-3-ethernet ens33
virbr0 083789d4-f752-4ba6-aa8a-5d156bef98e8 bridge virbr0
# 关闭自动连接(等价 ONBOOT=no)
nmcli con modify "System eth0" connection.autoconnect no
# 修改 DNS(覆盖原值)
nmcli con modify "System eth0" ipv4.dns 172.25.254.254
# 追加 DNS(保留原值)
nmcli con modify "System eth0" +ipv4.dns 172.25.254.250
# 修改 IP 地址(第二个值为网关的旧式写法)
nmcli con modify "System eth0" ipv4.addresses "172.25.0.10/16 172.25.0.254"
# 同时修改 IP 地址和网关(推荐写法)
nmcli conn modify abc ipv4.addresses 192.168.224.101/24 ipv4.gateway 192.168.224.2
# 只修改网关
nmcli conn modify abc ipv4.gateway 192.168.224.2
# 静态配置时必须把方法改为 manual,否则仍会去 DHCP
nmcli conn modify abc ipv4.method manual
# 重新加载配置(激活连接使修改生效)
nmcli con up "System eth0"
如果 nmcli con up 无效,可以重启 network 服务(CentOS 7 两套机制并存时)或 systemctl restart NetworkManager。
常用属性名速查:
| 属性 | 对应 ifcfg 字段 | 说明 |
|---|---|---|
ipv4.method manual / auto |
BOOTPROTO=static / dhcp |
地址获取方式 |
ipv4.addresses |
IPADDR + PREFIX |
地址,可多个 |
ipv4.gateway |
GATEWAY |
默认网关 |
ipv4.dns |
DNS1/DNS2 |
DNS 服务器 |
ipv4.dns-search |
DOMAIN |
搜索域 |
ipv4.never-default |
DEFROUTE=no |
不作为默认路由 |
ipv4.routes |
route-<dev> 文件 |
静态路由 |
ipv4.ignore-auto-dns |
PEERDNS=no |
忽略 DHCP 下发的 DNS |
connection.autoconnect |
ONBOOT |
开机自动连接 |
connection.id |
NAME |
连接名 |
connection.interface-name |
DEVICE |
绑定设备 |
802-3-ethernet.mtu |
MTU |
最大传输单元 |
802-3-ethernet.cloned-mac-address |
MACADDR |
伪装 MAC |
远程操作警告:通过 SSH 修改正在使用的连接时,
nmcli con down会立即断开你自己的会话。安全做法是使用nmcli con up(它会原子地切换配置,而不是先断后连),或先在带外通道(VNC / 控制台 / IPMI)留一条退路。
5.7 nmtui:字符界面前端
不想背参数时可以用 nmtui,它是 NetworkManager 的 curses 图形前端,无需 X 环境:
sudo nmtui
三个菜单项:Edit a connection(增删改连接)、Activate a connection(激活/停用)、Set system hostname(改主机名,等价于 hostnamectl set-hostname)。
也可直接进入某个界面:
sudo nmtui-edit
sudo nmtui-connect
sudo nmtui-hostname
图形环境下还有 nm-connection-editor(GUI)与 nmcli con edit <名称>(交互式命令行编辑器,支持 print、set、save、quit 等指令)。
nmtui保存后同样需要在Activate a connection中重新激活连接才生效,不会自动应用。
5.8 NM_CONTROLLED=no 与两套机制的冲突
第 4.2 / 4.3 节的 ifcfg 示例中有一行 NM_CONTROLLED=no,含义是:让 NetworkManager 完全不要接管这块网卡,该设备在 nmcli dev status 中显示为 unmanaged,其 IP 由 network.service(initscripts 脚本)在开机时读取 ifcfg 文件配置。
CentOS 7 的现实是两套机制并存,容易互相打架:
| 场景 | 后果 |
|---|---|
NM_CONTROLLED=no 但只启用了 NetworkManager、禁用了 network.service |
开机后该网卡无人配置,永远没有 IP |
NM_CONTROLLED=yes(或未写)且两个服务同时启用 |
两者可能先后写入不同配置,出现 IP 反复变化、DNS 被覆盖 |
NetworkManager 托管的网卡,手工改 /etc/resolv.conf |
被 NetworkManager 重新生成覆盖 |
实践建议:
- CentOS 7 上二选一并保持一致:要么全交给 NetworkManager(不写
NM_CONTROLLED,用nmcli管理,可systemctl disable network),要么全部NM_CONTROLLED=no并systemctl disable NetworkManager。教学环境中为了配合systemctl restart network才使用后者。 - RHEL 8+ / RHEL 9 上没有选择:
network.service已不存在,NM_CONTROLLED=no会导致网卡彻底不通,必须使用nmcli/nmtui。 - 想让 NetworkManager 不要动 DNS,可在
/etc/NetworkManager/NetworkManager.conf的[main]段加dns=none,再自行维护/etc/resolv.conf。
彻底关闭 NetworkManager 的命令(按版本):
# ---------- CentOS 6 ----------
/etc/init.d/NetworkManager stop
chkconfig NetworkManager off
chkconfig network on
# ---------- CentOS 7 ----------
sudo systemctl stop NetworkManager
sudo systemctl disable NetworkManager
sudo systemctl enable network
sudo systemctl start network
是否禁用 NetworkManager 的取舍:
- 禁用的理由:服务器 IP 固定,不需要自动切换网络;避免两套机制冲突;老运维脚本依赖
service network restart。- 保留的理由:bonding/team/bridge/VLAN 的现代配置方式、
nmcli的原子切换、RHEL 8+ 的唯一选择、笔记本/无线场景必需。- 结论:CentOS 7 教学与遗留环境可禁用;新建系统与 RHEL 8+ 一律保留并使用
nmcli。
5.9 传统命令与 nmcli 对照表
| 传统做法 | nmcli 等价命令 |
|---|---|
ifup enp0s25 |
nmcli con up <连接名>(或 nmcli dev connect enp0s25) |
ifdown enp0s25 |
nmcli con down <连接名>(或 nmcli dev disconnect enp0s25) |
systemctl restart network |
nmcli con reload + nmcli con up <连接名>(或 systemctl restart NetworkManager) |
编辑 ifcfg-* 改 IP |
nmcli con mod <连接名> ipv4.addresses 192.168.0.100/24 |
编辑 ifcfg-* 改网关 |
nmcli con mod <连接名> ipv4.gateway 192.168.0.1 |
编辑 ifcfg-* 改 DNS / 改 /etc/resolv.conf |
nmcli con mod <连接名> ipv4.dns 223.5.5.5 |
BOOTPROTO=static |
ipv4.method manual |
BOOTPROTO=dhcp |
ipv4.method auto |
ONBOOT=yes |
connection.autoconnect yes |
dhclient enp0s25 |
nmcli con mod <连接名> ipv4.method auto; nmcli con up <连接名> |
ip a s 看 IP(仍可用) |
nmcli dev show enp0s25 |
hostname / 改 /etc/sysconfig/network |
nmcli general hostname <名> / hostnamectl set-hostname <名> |
| 手工编辑配置文件后重启服务 | 手工编辑后 nmcli con reload(必做) |
5.10 实战一:为虚拟机增加一块桥接网卡并配置 IP
目标:为 Client2 增加一块物理桥接类型的网卡,将 IP 设置为 192.168.198.131。
-
登录虚拟机。
-
运行
nmcli conn show,结果显示只有 ens33 一块网卡:
[jim@client1 ~]$ nmcli con show
NAME UUID TYPE DEVICE
ens33 17883cd1-86c8-4ec3-b254-5ce6d462e929 802-3-ethernet ens33
virbr0 ee3ee66a-b0a2-44e8-8fac-ffefe039a0b1 bridge virbr0
- 开机状态下为虚拟机 Client2 增加一块「仅主机」类型的网卡。Linux 自动识别到新网卡 ens37,连接名称为 "Wired connection 1":
[root@client4 ~]# nmcli con show
NAME UUID TYPE DEVICE
Wired connection 1 f7ef9df8-e21a-393c-8b9d-5ac5c300b54b 802-3-ethernet ens37
ens33 17883cd1-86c8-4ec3-b254-5ce6d462e929 802-3-ethernet ens33
virbr0 69cdf8dd-53a3-4db5-9685-6162a828f381 bridge virbr0
- 再次运行
nmcli conn show,系统自动识别到新网卡 ens37。因为网络默认是 DHCP 类型,机器已自动获得 IP,网段为192.168.198.X:
[jim@client1 ~]$ ifconfig
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.224.11 netmask 255.255.255.0 broadcast 192.168.224.255
inet6 fe80::aed7:e5a6:39f2:bc3c prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:4e:51:b0 txqueuelen 1000 (Ethernet)
RX packets 19387 bytes 28578038 (27.2 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 8951 bytes 545551 (532.7 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
ens37: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.198.128 netmask 255.255.255.0 broadcast 192.168.198.255
inet6 fe80::18a7:f3a8:5db7:9e2e prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:4e:51:ba txqueuelen 1000 (Ethernet)
RX packets 135 bytes 17298 (16.8 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 52 bytes 8999 (8.7 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
...
- 修改 IP 地址为
192.168.198.131:
nmcli con modify "Wired connection 1" ipv4.addresses "192.168.198.131/24"
- 激活配置:
nmcli conn up "Wired connection 1"
- 运行
ifconfig查询 IP,结果已生效:
ens37: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.198.131 netmask 255.255.255.0 broadcast 192.168.198.255
inet6 fe80::a660:7d23:dfee:475c prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:86:28:31 txqueuelen 1000 (Ethernet)
RX packets 5 bytes 1148 (1.1 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 89 bytes 14164 (13.8 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
- 删除连接配置,将静态 IP 改回自动获取:
nmcli conn delete "Wired connection 1"
5.11 实战二:为一块网卡配置多份连接配置
为网卡 ens37 配置多份连接配置,以便在不同环境下切换 IP。例如配置一 conn1 的 IP 为 192.168.198.120,配置二 conn2 的 IP 为 192.168.198.121。
创建 conn1,IP 为 120:
# nmcli con add con-name conn1 type ethernet ifname ens37 ipv4.addresses "192.168.198.120/24" ipv4.gateway 192.168.192.1
创建 conn2,IP 为 121:
# nmcli con add con-name conn2 type ethernet ifname ens37 ipv4.addresses "192.168.198.121/24" ipv4.gateway 192.168.192.1
激活 conn2:
# nmcli conn up conn2
激活 conn1:
# nmcli conn up conn1
同一设备上的多个连接同一时刻只有一个生效,
nmcli con up会自动把前一个顶下去,这就是「一台机器在办公室/机房两套 IP 之间秒切」的标准做法。
六、主机名与名称解析
6.1 查看与临时修改主机名
hostname # 查看当前主机名
hostname qianyun.com # 临时修改(重启失效)
echo "qianyun.com" > /proc/sys/kernel/hostname # 等价写法
sysctl kernel.hostname=qianyun.com # 另一种等价写法
hostname 命令实质上读取 /etc/hostname 文件(CentOS 7),但它修改的主机名不会保存到该文件,只是修改内核中的临时变量,重启后恢复。
[root@desktop0 ~]# hostname desktop0.example.com
[root@desktop0 ~]# hostname XXX.example.com
临时修改后当前 Shell 的提示符不会立刻变化,需要重新登录或执行
exec bash才能看到新主机名。
6.2 永久修改主机名
CentOS 6 / RHEL 6:编辑 /etc/sysconfig/network
HOSTNAME=qianyun.com
配合临时命令使其立即生效,无需重启:
hostname qianyun.com
CentOS 7 / RHEL 7 及以上:使用 hostnamectl(立即生效且永久保存)
hostnamectl # 查看主机名相关全部信息
hostnamectl status
hostnamectl set-hostname XXXXXX # 永久修改
hostnamectl set-hostname node1.example.com
# 分类型设置
hostnamectl set-hostname "Web Server 01" --pretty # 描述性名称
hostnamectl set-hostname web01 --static # 静态主机名(写入 /etc/hostname)
hostnamectl set-hostname web01 --transient # 瞬态主机名(内核中,DHCP/mDNS 可改)
# nmcli 等价写法
nmcli general hostname web01
CentOS 7 的主机名配置文件:
cat /etc/hostname
# node1.example.com
# 也可直接编辑(需重启或执行 hostname 命令使其生效)
sudo vim /etc/hostname
三类主机名的区别:
| 类型 | 存储位置 | 说明 |
|---|---|---|
| static | /etc/hostname |
传统主机名,开机读取,是「真正的」主机名 |
| transient | 内核 | 运行时主机名,可被 DHCP/mDNS 动态修改 |
| pretty | /etc/machine-info |
自由格式的描述,可含空格与大写 |
- 主机名建议写成 FQDN(Full Qualified Domain Name,全限定域名),即
主机名.域名格式,如qianyun.cluster.com。部分软件(如 Apache)要求 FQDN,否则启动时报Could not reliably determine the server's fully qualified domain name。- 如果系统中没有
/etc/hostname文件,系统会使用 IP 进行 DNS 反向解析,从而通过 DNS 获取主机名称。- 修改主机名后,务必同步更新
/etc/hosts,将回环地址与主机名对应起来,否则可能导致图形界面启动缓慢、sudo 报unable to resolve host、SSH 登录变慢。
相关概念:
server:主机名称 hostname。server.example.com:FQDN(Fully Qualified Domain Name,全限定域名)。
6.3 /etc/hosts 本地名称解析
/etc/hosts 是本地静态名称解析文件(本地静态 DNS 缓存),相当于手工 DNS。默认情况下访问主机名或域名需要通过 DNS 服务器将名称解析成 IP;某些情况下需要配置 DNS 服务器中不存在的名称,就可以在本地设置。
格式:
IP地址 主机名/域名 [别名1] [别名2] ...
配置文件路径:
/etc/hosts
示例内容:
127.0.0.1 localhost localhost.localdomain localhost4
::1 localhost localhost.localdomain localhost6
10.0.0.61 server61.com
10.0.0.2 qianyun.com
主机名改为 newname 后,环回地址与实际 IP 都建议对应上:
127.0.0.1 newname
192.168.0.200 newname
集群环境的典型 /etc/hosts(各节点内容保持完全一致):
192.168.0.11 node1 node1.example.com
192.168.0.12 node2 node2.example.com
192.168.0.13 node3 node3.example.com
实际验证:
[root@desktop0 ~]# cat /etc/hosts
…
172.25.254.254 classroom.example.com
172.25.254.254 content.example.com
172.25.0.10 desktop0.example.com
[root@desktop0 ~]# host classroom.example.com
classroom.example.com has address 172.25.254.254
如有定义
/etc/hosts,先按该文件解析;没有相应条目再使用 DNS 解析。
/etc/hosts的修改立即生效,无需重启任何服务;但只对本机有效,且不支持通配符与轮询。
6.4 名称解析顺序:/etc/nsswitch.conf
系统在解析主机名时,先查 /etc/hosts,再查 DNS,这一顺序由 /etc/nsswitch.conf 中的 hosts: 行控制:
grep '^hosts' /etc/nsswitch.conf
hosts: files dns myhostname
| 关键字 | 含义 |
|---|---|
files |
查询本地文件 /etc/hosts |
dns |
查询 /etc/resolv.conf 中配置的 DNS 服务器 |
myhostname |
systemd 提供的模块,解析本机主机名与 localhost |
nis / ldap |
查询 NIS / LDAP 目录服务 |
mdns4_minimal |
组播 DNS(.local 域,桌面环境常见) |
调换顺序即可改变优先级,例如写成 hosts: dns files 就会先查 DNS。生产环境一般保持 files dns(本地覆盖优先,便于临时改指向)。
6.5 DNS 客户端配置:/etc/resolv.conf
sudo vim /etc/resolv.conf
添加内容(顶行优先):
# 首选 DNS 与备用 DNS,最多前 3 个 nameserver 生效
nameserver 223.5.5.5
nameserver 8.8.8.8
nameserver 114.114.114.114
# 默认搜索域:输入 web01 时自动尝试 web01.example.com
search example.com cluster.com
# 本机所在域(与 search 只写一个即可,search 优先)
domain example.com
# 解析行为微调
options timeout:2 attempts:2 rotate single-request-reopen
| 指令 | 说明 |
|---|---|
nameserver |
DNS 服务器地址,按顺序尝试,通常只有前 3 个生效 |
search |
搜索域列表,短主机名会依次拼接这些域名再查询 |
domain |
本机域名,作用类似单个 search,与 search 互斥 |
sortlist |
对返回的多个地址按指定网段排序 |
options timeout:n |
单个 DNS 查询超时秒数(默认 5,建议 1~2) |
options attempts:n |
每个服务器重试次数(默认 2) |
options rotate |
轮询使用各 nameserver,实现简单负载均衡 |
options ndots:n |
域名中点数少于 n 时先拼 search 域再查(容器环境常调整) |
options single-request-reopen |
规避某些网关下 A/AAAA 并发查询丢包导致的解析慢 |
常用公共 DNS:
| 地址 | 提供方 |
|---|---|
223.5.5.5 / 223.6.6.6 |
阿里云 DNS(国内首选) |
114.114.114.114 / 114.114.115.115 |
114DNS |
180.76.76.76 |
百度 DNS |
119.29.29.29 |
腾讯 DNSPod |
8.8.8.8 / 8.8.4.4 |
Google DNS |
1.1.1.1 |
Cloudflare |
/etc/resolv.conf被覆盖的问题:DHCP 客户端与 NetworkManager 都会重写此文件。彻底解决办法有三:
- 在 ifcfg 中写
DNS1/DNS2(推荐,由系统统一生成);- ifcfg 中加
PEERDNS=no阻止 DHCP 覆盖;- 在
/etc/NetworkManager/NetworkManager.conf的[main]段加dns=none,再手工维护。DNS 服务端(BIND)搭建详见 阶段09
09-03-DNS域名解析服务.md
6.6 验证名称解析
# 按 nsswitch.conf 的完整顺序解析(会读取 /etc/hosts,最贴近应用程序的行为)
getent hosts www.baidu.com
getent hosts node1
getent ahosts node1
# 只查 DNS,不看 /etc/hosts —— 用于区分「是 hosts 生效还是 DNS 生效」
nslookup www.baidu.com
nslookup www.baidu.com 8.8.8.8 # 指定 DNS 服务器查询
host www.baidu.com # 简洁输出
host -t A www.baidu.com # 指定记录类型
host -t MX baidu.com
host 223.5.5.5 # 反向解析
dig www.baidu.com # 最详细,运维排障首选
dig +short www.baidu.com # 只输出结果
dig @8.8.8.8 www.baidu.com # 指定 DNS 服务器
dig +trace www.baidu.com # 从根域开始追踪整个解析链
dig -x 223.5.5.5 # 反向解析
关键区别:
ping/getent/应用程序都会读/etc/hosts,而nslookup/dig/host直接问 DNS 服务器,不读/etc/hosts。出现「ping 域名解析到旧 IP,但 dig 结果是新 IP」时,第一嫌疑就是/etc/hosts里有残留条目。
6.7 为什么要互相绑定主机名
使用 SSH 连接另一台机器时,如果没有主机名解析,可能会卡几秒才出现密码提示(服务端做反向 DNS 解析等待超时)。多台服务器互相在 /etc/hosts 中绑定,可显著加快连接。配合服务端的 UseDNS no 效果最佳。
集群软件(Hadoop、Kubernetes、MySQL 主从、Puppet/SaltStack)几乎都要求节点间能用主机名互相解析,且解析结果必须一致,否则会出现「注册上来的节点地址是 127.0.0.1」这类问题。
6.8 大规模服务器的主机名管理方案
当服务器数量很多时,逐台维护 /etc/hosts 不现实,可选方案:
- 脚本批量分发
/etc/hosts(for循环 +scp,见下例) - 自动化运维工具(如 Puppet、Ansible、SaltStack)统一管理
- 搭建内部 DNS 服务器(节点数超过几十台时的正解)
- 在批量装机(Kickstart/Cobbler)时自动写入
# 方案 1 的最简实现:把标准 hosts 分发到所有节点
for host in node1 node2 node3; do
scp /etc/hosts root@$host:/etc/hosts
done
七、进阶网络配置
7.1 多网卡与多 IP(IP 别名)
临时添加
在一块物理网卡上绑定多个 IP:
# 传统别名写法(CentOS 6)
ifconfig eth0:0 10.0.0.36 netmask 255.255.255.0
ifconfig eth0:1 10.0.0.37 netmask 255.255.255.0
ifconfig eth0:2 10.0.0.38 netmask 255.255.255.0
# ip 命令写法(CentOS 7 推荐,一个接口挂多个地址,不产生虚拟接口)
sudo ip addr add 10.0.0.36/24 dev eth0
sudo ip addr add 10.0.0.37/24 dev eth0 label eth0:1
临时配置在重启网络后消失。
ifconfig只能看到带label的别名地址,ip addr才能看到全部地址。CentOS 7 上用ip a检查。
永久生效:单个别名(CentOS 6 风格)
新建 /etc/sysconfig/network-scripts/ifcfg-eth0:0:
DEVICE=eth0:0
BOOTPROTO=static
IPADDR=10.0.0.36
NETMASK=255.255.255.0
ONBOOT=yes
NM_CONTROLLED="no"
批量添加:range 文件
新建 /etc/sysconfig/network-scripts/ifcfg-eth0-range0:
IPADDR_START=10.0.0.37 # 起始 IP
IPADDR_END=10.0.0.50 # 结束 IP
NETMASK=255.255.255.0
CLONENUM_START=10 # 别名编号从 eth0:10 开始
CentOS 7 的多 IP 写法
方式一:在同一个 ifcfg 文件中写多组编号
DEVICE=ens33
BOOTPROTO=none
ONBOOT=yes
IPADDR0=192.168.0.200
PREFIX0=24
IPADDR1=192.168.0.201
PREFIX1=24
IPADDR2=192.168.0.202
PREFIX2=24
GATEWAY=192.168.0.1
方式二:用 nmcli 一次配置多个地址
nmcli con mod ens33 ipv4.addresses "192.168.0.200/24,192.168.0.201/24,192.168.0.202/24"
nmcli con mod ens33 +ipv4.addresses 192.168.0.203/24 # 追加
nmcli con up ens33
多 IP 常见用途:一台机器承载多个 HTTPS 站点(SNI 之前的做法)、Keepalived 的 VIP、迁移期间新旧 IP 并存。
7.2 网卡绑定 bonding
bonding 把多块物理网卡聚合成一个逻辑网卡,实现链路冗余或带宽叠加。
常用模式:
| 模式 | 名称 | 说明 | 是否需要交换机配合 |
|---|---|---|---|
mode=0 |
balance-rr | 轮询发包,带宽可叠加,但可能乱序 | 需要(端口聚合) |
mode=1 |
active-backup | 主备,只有一块工作,故障自动切换(生产最常用) | 不需要 |
mode=2 |
balance-xor | 按源/目的 MAC 哈希分流 | 需要 |
mode=3 |
broadcast | 所有从网卡都发一份,容错极高、效率极低 | 不需要 |
mode=4 |
802.3ad (LACP) | 标准链路聚合,带宽叠加 + 冗余(机房推荐) | 需要(配置 LACP) |
mode=5 |
balance-tlb | 按负载分配发送流量,接收不分流 | 不需要 |
mode=6 |
balance-alb | 收发都做负载均衡(靠 ARP 协商) | 不需要 |
传统 ifcfg 配置方式(CentOS 6 / 7 通用)
主接口 /etc/sysconfig/network-scripts/ifcfg-bond0:
DEVICE=bond0
NAME=bond0
TYPE=Bond
BONDING_MASTER=yes
BOOTPROTO=none
ONBOOT=yes
IPADDR=192.168.0.200
PREFIX=24
GATEWAY=192.168.0.1
DNS1=223.5.5.5
NM_CONTROLLED=no
BONDING_OPTS="mode=1 miimon=100 primary=eth0 fail_over_mac=1"
从属接口 ifcfg-eth0:
DEVICE=eth0
TYPE=Ethernet
BOOTPROTO=none
ONBOOT=yes
MASTER=bond0
SLAVE=yes
NM_CONTROLLED=no
从属接口 ifcfg-eth1:
DEVICE=eth1
TYPE=Ethernet
BOOTPROTO=none
ONBOOT=yes
MASTER=bond0
SLAVE=yes
NM_CONTROLLED=no
CentOS 6 还需要加载模块(CentOS 7 自动加载):
sudo vim /etc/modprobe.d/bonding.conf
alias bond0 bonding
options bond0 miimon=100 mode=1
重启网络并验证:
# CentOS 6
service network restart
# CentOS 7
sudo systemctl restart network
# 查看绑定状态(当前活动网卡、各从属网卡链路状态)
cat /proc/net/bonding/bond0
ip a s bond0
# 拔掉主网卡网线(或 ip link set eth0 down)验证是否自动切换
sudo ip link set eth0 down
cat /proc/net/bonding/bond0 | grep -E 'Active Slave|MII Status'
BONDING_OPTS 常用参数:
| 参数 | 说明 |
|---|---|
mode |
绑定模式,见上表 |
miimon=100 |
每 100 毫秒检测一次链路状态(必配) |
updelay / downdelay |
链路恢复/断开后延迟多少毫秒才切换,防抖动 |
primary=eth0 |
指定主用网卡(仅 active-backup 有效) |
fail_over_mac |
切换时如何处理 MAC,虚拟机环境常设 1 |
lacp_rate=fast |
LACP 报文发送频率(mode=4) |
xmit_hash_policy=layer3+4 |
哈希策略(mode=2/4),按 IP+端口分流更均匀 |
nmcli 配置方式(CentOS 7 推荐)
# 创建 bond 主接口
sudo nmcli con add type bond con-name bond0 ifname bond0 mode active-backup \
ipv4.method manual ipv4.addresses 192.168.0.200/24 ipv4.gateway 192.168.0.1 ipv4.dns 223.5.5.5
# 加入从属网卡
sudo nmcli con add type bond-slave con-name bond0-p1 ifname ens33 master bond0
sudo nmcli con add type bond-slave con-name bond0-p2 ifname ens37 master bond0
# 激活
sudo nmcli con up bond0
sudo nmcli con up bond0-p1
sudo nmcli con up bond0-p2
# 查看
cat /proc/net/bonding/bond0
7.3 team 组队(CentOS 7 新增)
team 是 RHEL 7 引入的替代 bonding 的方案,由用户空间守护进程 teamd 实现,功能相近但更易扩展。
runner(相当于 bonding 的 mode):broadcast、roundrobin、activebackup、loadbalance、lacp。
# 创建 team 主接口(activebackup 模式)
sudo nmcli con add type team con-name team0 ifname team0 \
config '{"runner": {"name": "activebackup"}}' \
ipv4.method manual ipv4.addresses 192.168.0.200/24 ipv4.gateway 192.168.0.1
# 加入成员网卡
sudo nmcli con add type team-slave con-name team0-p1 ifname ens33 master team0
sudo nmcli con add type team-slave con-name team0-p2 ifname ens37 master team0
# 激活
sudo nmcli con up team0
# 查看状态
sudo teamdctl team0 state
sudo teamnl team0 ports
ip a s team0
ifcfg 写法 /etc/sysconfig/network-scripts/ifcfg-team0:
DEVICE=team0
DEVICETYPE=Team
NAME=team0
TEAM_CONFIG='{"runner": {"name": "activebackup"}}'
BOOTPROTO=none
ONBOOT=yes
IPADDR=192.168.0.200
PREFIX=24
GATEWAY=192.168.0.1
成员 ifcfg-ens33:
DEVICE=ens33
DEVICETYPE=TeamPort
TEAM_MASTER=team0
ONBOOT=yes
bonding 与 team 不能同时管理同一块网卡。新系统若无特殊要求,仍可继续使用 bonding(内核态、成熟、文档多);RHEL 9 起 team 已被标记弃用,官方重新推荐 bonding。
7.4 桥接 bridge
桥接把物理网卡变成虚拟交换机的一个端口,KVM 虚拟化和容器网络的基础。
nmcli 方式:
# 创建桥
sudo nmcli con add type bridge con-name br0 ifname br0 \
ipv4.method manual ipv4.addresses 192.168.0.200/24 ipv4.gateway 192.168.0.1 ipv4.dns 223.5.5.5
# 关闭 STP(单机环境可关,减少 up 后的等待时间)
sudo nmcli con mod br0 bridge.stp no
# 把物理网卡加入桥
sudo nmcli con add type bridge-slave con-name br0-port1 ifname ens33 master br0
sudo nmcli con up br0
ifcfg 方式,桥接口 ifcfg-br0:
DEVICE=br0
NAME=br0
TYPE=Bridge
BOOTPROTO=none
ONBOOT=yes
IPADDR=192.168.0.200
PREFIX=24
GATEWAY=192.168.0.1
DNS1=223.5.5.5
STP=no
DELAY=0
物理网卡 ifcfg-ens33(注意:物理网卡不再配 IP):
DEVICE=ens33
NAME=ens33
TYPE=Ethernet
BOOTPROTO=none
ONBOOT=yes
BRIDGE=br0
查看与管理:
brctl show # 需 bridge-utils 包
brctl showmacs br0
ip link show type bridge
bridge link show # iproute2 提供的新命令
nmcli con show br0 | grep bridge
配置桥接会导致物理网卡上的 IP 转移到 br0,操作过程中网络会短暂中断。远程操作必须使用
nmcli con up并准备带外通道。
7.5 VLAN 子接口
在一块物理网卡上承载多个 VLAN(需交换机端口配置为 trunk)。
nmcli 方式:
sudo nmcli con add type vlan con-name vlan10 ifname ens33.10 dev ens33 id 10 \
ipv4.method manual ipv4.addresses 192.168.10.200/24
sudo nmcli con up vlan10
ifcfg 方式 /etc/sysconfig/network-scripts/ifcfg-ens33.10:
DEVICE=ens33.10
BOOTPROTO=none
ONBOOT=yes
VLAN=yes
VLAN_ID=10
PHYSDEV=ens33
IPADDR=192.168.10.200
PREFIX=24
临时创建(ip 命令):
sudo modprobe 8021q # 加载 VLAN 模块
sudo ip link add link ens33 name ens33.10 type vlan id 10
sudo ip addr add 192.168.10.200/24 dev ens33.10
sudo ip link set ens33.10 up
# 查看
ip -d link show ens33.10
cat /proc/net/vlan/config
# 删除
sudo ip link del ens33.10
传统 vconfig 写法(CentOS 6):
vconfig add eth0 10
vconfig rem eth0.10
7.6 静态路由永久化
临时添加的路由(ip route add)重启即失效,需要写入配置文件。
方式一:route-<设备名> 文件(CentOS 6 / 7 通用)
sudo vim /etc/sysconfig/network-scripts/route-eth0
写法 A(ip 命令风格,推荐):
10.1.1.0/24 via 192.168.0.254 dev eth0
172.16.0.0/16 via 192.168.0.254
default via 192.168.0.1
写法 B(键值对风格,多条路由用编号区分):
ADDRESS0=10.1.1.0
NETMASK0=255.255.255.0
GATEWAY0=192.168.0.254
ADDRESS1=172.16.0.0
NETMASK1=255.255.0.0
GATEWAY1=192.168.0.254
生效:
# CentOS 6
service network restart
# CentOS 7
sudo systemctl restart network
# 或只重启该网卡
sudo ifdown eth0 && sudo ifup eth0
方式二:nmcli 写入连接属性(CentOS 7 推荐)
sudo nmcli con mod ens33 +ipv4.routes "10.1.1.0/24 192.168.0.254"
sudo nmcli con mod ens33 +ipv4.routes "172.16.0.0/16 192.168.0.254 100" # 末位为 metric
sudo nmcli con up ens33
nmcli con show ens33 | grep ipv4.routes
方式三:写进 rc.local(不推荐,但常见于老环境)
sudo vim /etc/rc.d/rc.local
/sbin/ip route add 10.1.1.0/24 via 192.168.0.254
sudo chmod +x /etc/rc.d/rc.local # CentOS 7 必须加执行权限才会被执行
开启路由转发(让 Linux 充当路由器/网关)
# 临时开启
sudo sysctl -w net.ipv4.ip_forward=1
echo 1 > /proc/sys/net/ipv4/ip_forward
# 永久开启
sudo vim /etc/sysctl.conf # CentOS 6
# 或 /etc/sysctl.d/99-forward.conf # CentOS 7 推荐
net.ipv4.ip_forward = 1
sudo sysctl -p
sysctl net.ipv4.ip_forward # 验证
7.7 MTU 调整
MTU(Maximum Transmission Unit)默认 1500 字节。存储网络、集群内网可调至 9000(巨帧)提升吞吐;PPPoE、VPN、隧道环境需调小以避免分片丢包。
# 临时修改
sudo ip link set dev ens33 mtu 9000
ifconfig eth0 mtu 9000 # 传统写法
# 查看当前 MTU
ip a s ens33 | grep mtu
cat /sys/class/net/ens33/mtu
# 永久修改:ifcfg 文件
# MTU=9000
# 永久修改:nmcli
sudo nmcli con mod ens33 802-3-ethernet.mtu 9000
sudo nmcli con up ens33
探测链路实际可用 MTU(发送不允许分片的大包,逐步降低直到成功):
# -M do 禁止分片,-s 指定数据部分大小(实际包大小 = -s 值 + 28 字节头)
ping -c 2 -M do -s 1472 192.168.0.1 # 成功说明 MTU >= 1500
ping -c 2 -M do -s 1473 192.168.0.1 # 失败提示 Frag needed and DF set (mtu = 1500)
ping -c 2 -M do -s 8972 192.168.0.1 # 测试巨帧 9000
# tracepath 自动探测路径 MTU
tracepath 8.8.8.8
MTU 不一致的典型症状:
ping通、SSH 能登录、但scp大文件卡死、网页打开一半、数据库大结果集查询超时——即「小包通、大包丢」。全链路(包括交换机端口、对端服务器)必须统一 MTU,只改一端会更糟。
八、SSH 远程登录
8.1 为什么用 SSH 而不是 telnet
远程管理 Linux 的协议有两代:早期的 telnet(23/tcp)与现在通用的 SSH(Secure Shell,22/tcp)。
| 对比项 | telnet | SSH |
|---|---|---|
| 默认端口 | 23/tcp | 22/tcp |
| 传输方式 | 全程明文 | 全程加密 |
| 用户名/密码 | 明文出现在网络包中 | 加密协商,抓包不可读 |
| 身份认证 | 仅口令 | 口令 + 公钥 + 主机密钥双向校验 |
| 文件传输 | 无 | 自带 scp / sftp |
| 端口转发 / X11 转发 | 无 | 支持 |
| 现状 | 已淘汰,仅用于调试端口连通性 | 事实标准 |
telnet 被淘汰的核心原因就一条:它把用户名和密码以明文形式发送。只要在链路上任意一点抓包(交换机镜像口、同网段 ARP 欺骗、公网中间设备),就能直接读出登录凭据。
# telnet 现在的正确用法:只当「TCP 端口探测工具」,不用来登录
telnet 192.168.0.183 22 # 能看到 SSH-2.0-OpenSSH_7.4 说明 22 端口通且 sshd 在
SSH 协议本身有两个版本:
| 版本 | 说明 |
|---|---|
| SSH v1 | 使用 CRC-32 做完整性校验,存在可插入攻击、密钥可被破解等设计缺陷,已废弃,OpenSSH 7.4 起默认不再编译支持 |
| SSH v2 | 重新设计了密钥交换与完整性校验(HMAC),支持 DH 密钥交换,当前唯一应使用的版本 |
老配置文件里可能残留 Protocol 2,1,应改为只允许 v2:
# /etc/ssh/sshd_config
Protocol 2
新版 OpenSSH 已移除
Protocol指令,写了反而会导致 sshd 启动失败,仅在 CentOS 6 这类老系统上需要显式声明。
8.2 基本登录
两种等价写法:
ssh 10.0.0.2 # 以「当前本地用户名」登录远程主机
ssh user1@10.0.0.2 # 以指定用户登录(最常用)
ssh -l user1 10.0.0.2 # -l 指定登录用户,与上一行完全等价
指定端口(服务端改过端口时必须加):
ssh -p 2222 user1@10.0.0.2 # 注意 ssh 是小写 -p,scp/sftp 是大写 -P
其他常用形式:
ssh user1@server1.com # 用主机名登录(依赖 /etc/hosts 或 DNS)
ssh -i ~/.ssh/id_rsa_prod deploy@10.0.0.2 # 指定私钥文件
ssh -o ConnectTimeout=5 user1@10.0.0.2 # 限制连接超时,批量脚本必备
首次登录的指纹确认
第一次连接某台主机时,会出现主机密钥(host key)确认提示:
The authenticity of host '10.0.0.2 (10.0.0.2)' can't be established.
RSA key fingerprint is b1:70:27:1f:8c:2a:...:9e.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '10.0.0.2' (RSA) to the list of known hosts.
这里的含义需要讲清楚:
- 每台安装了 sshd 的主机都会在
/etc/ssh/下生成一对主机密钥(如ssh_host_rsa_key/ssh_host_rsa_key.pub)。 - 客户端连接时,服务端出示自己的公钥;客户端本地没有记录,无法判断「这台机器是不是我要连的那台」,于是把指纹(公钥的哈希摘要)显示给人工确认。
- 输入
yes的真实含义是:我确认这个指纹属于我要连的主机,请把它记下来。此后该公钥被追加进~/.ssh/known_hosts,再次连接时客户端自动比对,一致则不再提示。 - 严格来说,首次连接应通过带外渠道(控制台、装机记录)核对指纹;实际运维中内网环境多数直接
yes。
查看服务端自己的指纹用于核对:
ssh-keygen -lf /etc/ssh/ssh_host_rsa_key.pub # 显示本机主机密钥指纹
ssh-keygen -lf /etc/ssh/ssh_host_ecdsa_key.pub
known_hosts 的作用:
cat ~/.ssh/known_hosts # 每行一条:主机名/IP + 密钥类型 + 公钥
ssh-keygen -F 10.0.0.2 # 查询某主机是否已有记录
它是防中间人攻击的关键。如果没有它,攻击者冒充服务端时客户端毫无察觉,密码会直接送到攻击者手里。
免密登录(
ssh-keygen生成密钥对、ssh-copy-id分发公钥、~/.ssh/authorized_keys)是 SSH 的另一大主题,本文只做要点提及:生成密钥 → 公钥追加到服务端authorized_keys→ 私钥 600、~/.ssh700。详见 04-02-计划任务与SSH等效性.md
8.3 报错:REMOTE HOST IDENTIFICATION HAS CHANGED
报错原文:
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the RSA key sent by the remote host is
b1:70:27:1f:8c:2a:...:9e.
Please contact your system administrator.
Add correct host key in /root/.ssh/known_hosts to get rid of this message.
Offending key in /root/.ssh/known_hosts:6
RSA host key for 10.0.0.2 has changed and you have requested strict checking.
Host key verification failed.
成因:本地 known_hosts 里记录的主机公钥,与服务端这次出示的公钥不一致。常见原因:
- 远程主机重装了系统(主机密钥重新生成)——最常见。
- 该 IP 被另一台机器复用(DHCP 重新分配、虚拟机重建、云主机释放后重新申请)。
- 服务端手工删除或重建了
/etc/ssh/ssh_host_*文件。 - 真的遭遇了中间人攻击(少见但不能排除)。
正确做法:只清理这一条记录
ssh-keygen -R 10.0.0.2 # 按 IP 删除
ssh-keygen -R server1.com # 按主机名删除(如果是用主机名连的,两条都要删)
ssh-keygen -R "[10.0.0.2]:2222" # 非默认端口的记录格式是 [主机]:端口
执行后会生成备份文件 known_hosts.old,然后重新连接,重新确认一次指纹即可。
粗暴做法及其代价
rm -f ~/.ssh/known_hosts # 不推荐
代价是:所有主机的信任记录一次性全部丢失。之后连接每一台机器都会重新提示确认指纹,而在「习惯性一路 yes」的状态下,真正的中间人攻击也会被一并放过——等于把整个 known_hosts 机制的保护作用清零。只删单行同样可行:
sed -i '6d' ~/.ssh/known_hosts # 删除报错提示的第 6 行
StrictHostKeyChecking 与批量运维的取舍
# 单次跳过检查(不写入 known_hosts)
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null user@10.0.0.2
# 批量脚本中常见写法
ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 user@$ip 'uptime'
取值含义:
| 取值 | 行为 |
|---|---|
yes |
主机密钥不在 known_hosts 中直接拒绝连接,最严格 |
ask(默认) |
未知主机弹出指纹确认;已知主机密钥变更则拒绝 |
no / accept-new |
no 自动接受任何密钥(含变更后的);accept-new 只自动接受新主机,密钥变更仍拒绝 |
安全含义必须点明:
StrictHostKeyChecking=no等于彻底放弃对服务端身份的校验,中间人可以无声无息地劫持会话并拿到你输入的密码或命令。它只适合「一次性初始化大批新装机器、且处于可信内网」的场景。若确实需要免交互,优先选accept-new(OpenSSH 7.6+),或提前用ssh-keyscan批量收集指纹写入 known_hosts:
ssh-keyscan -t rsa,ecdsa 10.0.0.2 >> ~/.ssh/known_hosts # 单台
ssh-keyscan -f iplist.txt >> ~/.ssh/known_hosts # 按 IP 列表批量
8.4 远程执行命令
不进入交互式 Shell,执行完命令直接返回结果:
ssh 10.0.0.2 date # 执行 date 并把输出打回本地
ssh user1@10.0.0.2 'df -h /'
ssh user1@10.0.0.2 uptime
引号与转义的注意点
命令会先经过本地 Shell 解析一次,再由远程 Shell 解析一次,因此变量、通配符、重定向的解析位置取决于引号:
ssh 10.0.0.2 echo $HOSTNAME # 错误:$HOSTNAME 被本地展开,打印的是本地主机名
ssh 10.0.0.2 'echo $HOSTNAME' # 正确:单引号阻止本地展开,在远程展开
ssh 10.0.0.2 "echo $HOSTNAME" # 双引号仍会被本地展开,注意区分
ssh 10.0.0.2 'ls /var/log/*.log' # 通配符在远程展开
ssh 10.0.0.2 'df -h > /tmp/df.txt' # 重定向发生在远程
ssh 10.0.0.2 'df -h' > /tmp/df.txt # 重定向发生在本地
多条命令的写法
ssh 10.0.0.2 'hostname; uptime; df -h /' # 分号:不管前一条成败都执行
ssh 10.0.0.2 'cd /tmp && tar zcf log.tar.gz *.log' # && :前一条成功才继续
ssh 10.0.0.2 'systemctl is-active nginx || systemctl start nginx'
# 多行写法,可读性更好
ssh 10.0.0.2 '
yum -y install httpd
systemctl enable --now httpd
systemctl is-active httpd
'
-t 强制分配伪终端
ssh 10.0.0.2 'sudo systemctl restart nginx' # 可能报 sudo: no tty present
ssh -t 10.0.0.2 'sudo systemctl restart nginx' # 加 -t,可以正常交互输入密码
ssh -t 10.0.0.2 'top' # 全屏交互程序必须有 tty
ssh -t 10.0.0.2 'vim /etc/hosts'
ssh -tt 10.0.0.2 'command' # 即使本地无 tty(脚本中)也强制分配
需要 -t 的典型场景:sudo 需要输入密码、top / vim / less 等全屏交互程序、需要看到进度条的程序。
-T 则是禁用伪终端分配:
ssh -T git@github.com # 测试 GitHub 密钥,不需要 tty
ssh -T 10.0.0.2 'cat >> /tmp/a' # 纯管道传输时禁用 tty,避免回显干扰数据
执行本地脚本(不需要先上传)
ssh 10.0.0.2 'bash -s' < /root/init.sh # 把本地脚本喂给远程 bash
ssh 10.0.0.2 'bash -s' -- --env=prod < deploy.sh # 还能传参数给脚本
cat init.sh | ssh 10.0.0.2 'bash -s' # 等价写法
ssh 10.0.0.2 'sudo bash -s' < patch.sh # 以 root 执行
这是批量初始化机器的常用技巧:脚本只维护一份在本地,无需 scp 到每台机器再删除。
配合远程写文件:
echo "hello" | ssh user@10.0.0.2 'cat > /tmp/file' # 覆盖写
ssh user@10.0.0.2 'cat >> /tmp/file' < local.txt # 追加写
tar zcf - /etc/nginx | ssh 10.0.0.2 'tar zxf - -C /' # 打包直传,不落地临时文件
8.5 远程调用图形程序(X11 转发)
在远程服务器上运行图形程序,把窗口显示到本地:
ssh -X user1@10.0.0.2 firefox # 单次转发:登录并直接启动远程 firefox
ssh -X user1@10.0.0.2 # 登录后再在提示符下运行图形程序
ssh -Y user1@10.0.0.2 # 信任模式转发
-X 与 -Y 的区别
| 选项 | 名称 | 行为 | 安全性 |
|---|---|---|---|
-X |
不信任转发 | 受 X11 SECURITY 扩展限制,远程程序不能截取本地其他窗口的键盘输入、不能抓屏 | 较安全,但部分程序会因限制而报错或异常退出 |
-Y |
信任转发 | 不加任何限制,远程程序与本地 X 客户端权限相同 | 不安全:远程主机上的恶意程序可以键盘记录、截屏你的本地桌面 |
原则:优先用 -X,只有程序确实跑不起来时才临时改用 -Y,且仅对完全可信的服务器使用。
对应的客户端配置项:
# ~/.ssh/config
ForwardX11 yes # 相当于 -X
ForwardX11Trusted yes # 相当于 -Y
服务端与依赖条件
# /etc/ssh/sshd_config
X11Forwarding yes # 必须开启,否则客户端 -X 无效
X11UseLocalhost yes # 默认 yes
systemctl restart sshd # CentOS 7+
service sshd restart # CentOS 6
# 服务端必须安装 xauth,否则 -X 静默失效
rpm -q xorg-x11-xauth || yum -y install xorg-x11-xauth
# 服务端还需要安装图形程序本身及其依赖库
yum -y install xorg-x11-apps # 提供 xclock / xeyes 等测试小程序
验证是否转发成功
# 登录远程主机后执行
echo $DISPLAY
# 有输出如 localhost:10.0 → 转发已生效
# 无任何输出 → 转发未生效(服务端未开 X11Forwarding、未装 xauth,或客户端没加 -X)
xclock # 弹出时钟窗口即完全正常
xeyes
常见失败原因排查顺序:客户端是否加了 -X/-Y → 服务端 X11Forwarding yes 是否生效(sshd -T | grep -i x11)→ 服务端是否装了 xauth → 本地是否有可用的 X Server(Windows 上需 Xming / VcXsrv / MobaXterm,macOS 需 XQuartz)。
8.6 故障排查:Connection refused
报错原文:
ssh 10.0.0.2
ssh: connect to host 10.0.0.2 port 22: Connection refused
Connection refused 的准确含义是:网络是通的,数据包到达了对端,但对端 22 端口没有任何程序在监听(内核直接回了 RST)。所以问题一定在服务端,而不在链路。按下面顺序排查。
第 1 步:远端 sshd 是否在运行
# CentOS 7 及以上
systemctl status sshd
systemctl is-active sshd
# CentOS 6
service sshd status
/etc/init.d/sshd status
第 2 步:是否监听 22 端口
ss -tnlp | grep 22 # CentOS 7+ 推荐
ss -tnlp | grep sshd
netstat -ntlup | grep sshd # CentOS 6 / 老系统
lsof -i :22
正常输出:
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 6840/sshd
tcp 0 0 :::22 :::* LISTEN 6840/sshd
0.0.0.0:22 表示监听所有网卡。若只看到 127.0.0.1:22,说明 sshd_config 里 ListenAddress 被限制成了回环地址,外部当然连不上。
第 3 步:启动服务并设置开机自启
# CentOS 7 及以上(systemd)
systemctl start sshd
systemctl enable sshd
systemctl enable --now sshd # 启动 + 开机自启,一条搞定
# CentOS 6(SysV init)
service sshd start
/etc/init.d/sshd start
chkconfig sshd on
chkconfig --list sshd # 确认 2、3、4、5 为 on
若启动失败,看日志定位原因:
journalctl -u sshd -n 50 --no-pager # CentOS 7+
tail -50 /var/log/secure # 通用
sshd -t # 先做配置语法检查
第 4 步:防火墙是否放行
# CentOS 7+ firewalld
firewall-cmd --list-all
firewall-cmd --permanent --add-service=ssh
firewall-cmd --reload
# CentOS 6 iptables
iptables -nL --line-numbers
/etc/init.d/iptables status
注意:防火墙 DROP 掉数据包时报错通常是 timeout(连接卡住直到超时),而 REJECT 才会立刻返回 refused。所以「立刻 refused」更多指向服务没起,「卡半天才失败」更多指向防火墙。
详见 07-03-防火墙与SELinux.md
第 5 步:端口是否被改过
grep -i '^Port' /etc/ssh/sshd_config # 服务端确认实际端口
sshd -T | grep -i '^port' # 看生效值(含默认值)
ssh -p 2222 user1@10.0.0.2 # 客户端按实际端口连接
nmap -p 1-65535 10.0.0.2 | grep ssh # 不知道端口时扫描(需授权)
telnet 10.0.0.2 2222 # 快速验证某端口是否开放
第 6 步:分级调试输出
ssh -v user1@10.0.0.2 # 一级:看握手阶段、认证方式协商
ssh -vv user1@10.0.0.2 # 二级:更多协议细节
ssh -vvv user1@10.0.0.2 # 三级:最详细,含密钥交换全过程
调试输出的读法(重点看这几行):
| 输出行 | 说明 |
|---|---|
Connecting to 10.0.0.2 [10.0.0.2] port 22. |
目标 IP 和端口是否符合预期 |
Connection established. |
TCP 已连通,说明网络和端口没问题,问题在认证阶段 |
Server host key: ssh-rsa SHA256:... |
服务端主机密钥指纹 |
Authentications that can continue: publickey,password |
服务端允许的认证方式(若没有 password,说明密码认证被关了) |
Offering public key: /root/.ssh/id_rsa |
客户端尝试的私钥 |
Authentications that can continue: password 反复出现 |
密钥被服务端拒绝,检查 authorized_keys 与权限 |
debug1: Next authentication method: password |
已回退到密码认证 |
卡在 Connecting to ... |
网络/防火墙问题 |
卡在 Connection established 之后很久 |
大概率是服务端 UseDNS / GSSAPIAuthentication 反查超时 |
服务端也可以开调试,在前台单独跑一个实例(不影响现有 sshd):
/usr/sbin/sshd -d -p 2222 # -d 前台调试模式,换个端口避免冲突
ssh -p 2222 user1@10.0.0.2 # 另开终端连接,服务端会打印完整过程
四种报错的区分
| 报错 | 含义 | 通常原因 | 排查方向 |
|---|---|---|---|
Connection refused |
包到了,端口无人监听 | sshd 没启动 / 端口改了 / 只监听了 127.0.0.1 / 防火墙 REJECT | 服务端 systemctl status sshd、ss -tnlp |
Connection timed out |
包发出去没有任何回应 | 防火墙 DROP / 安全组未放行 / 路由不通 / 主机关机 | ping、traceroute、防火墙与云安全组规则 |
No route to host |
本机路由表找不到去路,或对端 ARP 无响应 | 网关配置错误 / 目标 IP 不存在 / 不在同网段且无路由 / firewalld REJECT | ip route、ip neigh、网关连通性 |
Permission denied |
网络与服务都正常,认证失败 | 密码错误 / 用户不存在 / 密钥不对 / PermitRootLogin no / AllowUsers 限制 |
/var/log/secure、ssh -v 看认证方式 |
口诀:refused 找服务,timeout 找防火墙,no route 找路由,denied 找认证。
九、SSH 服务端配置与加固
9.1 两个配置文件不要搞混
| 文件 | 角色 | 作用 |
|---|---|---|
/etc/ssh/sshd_config |
服务端(sshd 守护进程) | 决定「别人怎么连进本机」,加固改的是它 |
/etc/ssh/ssh_config |
客户端全局 | 决定「本机怎么连出去」,对所有用户生效 |
~/.ssh/config |
客户端用户级 | 只对当前用户生效,优先级高于全局 |
多了一个 d 就从「连出去」变成「连进来」,这是初学者最容易改错的地方。
9.2 sshd_config 常用配置项详解
vim /etc/ssh/sshd_config
cp -a /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%F) # 改之前先备份
监听相关
Port 22 # 监听端口,可写多行同时监听多个端口
Port 2222
ListenAddress 0.0.0.0 # 监听的本机地址,默认所有 IPv4 地址
ListenAddress :: # 所有 IPv6 地址
ListenAddress 192.168.0.183 # 只监听指定网卡地址(多网卡机器常用,内网口开放、公网口不开)
AddressFamily inet # inet=仅 IPv4,inet6=仅 IPv6,any=两者(默认)
Protocol 2 # 仅 CentOS 6 需要,禁用不安全的 SSH v1
| 配置项 | 说明与建议 |
|---|---|
Port |
默认 22。改为高位端口可减少扫描噪音;改端口后 SELinux 需 semanage port -a -t ssh_port_t -p tcp 2222,防火墙也要放行 |
ListenAddress |
只写内网地址是很有效的加固手段——公网上根本扫不到这个端口 |
认证相关
PermitRootLogin no # 是否允许 root 直接登录
PasswordAuthentication yes # 是否允许密码认证
PubkeyAuthentication yes # 是否允许公钥认证
AuthorizedKeysFile .ssh/authorized_keys # 公钥存放位置(相对用户家目录)
PermitEmptyPasswords no # 是否允许空密码用户登录
MaxAuthTries 3 # 单次连接允许的认证失败次数
MaxSessions 10 # 单条连接允许的会话数
LoginGraceTime 60 # 登录宽限时间(秒),超时未完成认证即断开
PermitRootLogin 的取值(重点):
| 取值 | 含义 |
|---|---|
yes |
允许 root 用任何方式登录(含密码),默认值,不安全 |
no |
完全禁止 root 登录,推荐 |
prohibit-password |
允许 root 登录但禁止密码认证,只能用密钥(旧名 without-password),需要 root 密钥自动化时的折中方案 |
forced-commands-only |
仅允许 root 执行 authorized_keys 中用 command= 强制指定的命令,用于备份等受限自动化 |
LoginGraceTime 的作用:从 TCP 连上到认证完成的时间窗口。设小一点(30~60 秒)可以减少半开连接被用来做资源耗尽攻击的空间;设 0 表示不限制(不建议)。
保活相关(ClientAliveInterval 与 ClientAliveCountMax 的配合计算)
ClientAliveInterval 60 # 每 60 秒向客户端发一次探测包
ClientAliveCountMax 3 # 连续 3 次无响应则断开
超时时间 = ClientAliveInterval × ClientAliveCountMax = 60 × 3 = 180 秒。
两种相反的用途,取决于你的目标:
# 目标 A:安全策略要求空闲会话自动断开(如 10 分钟)
ClientAliveInterval 300
ClientAliveCountMax 2 # 300 × 2 = 600 秒 = 10 分钟
# 目标 B:防止 NAT/防火墙因空闲回收连接,让长连接一直活着
ClientAliveInterval 60
ClientAliveCountMax 30 # 60 × 30 = 1800 秒,配合客户端 ServerAliveInterval
ClientAliveCountMax 0 表示探测一次无响应就断开,容易在网络抖动时误杀会话。
性能相关(登录慢的两个元凶)
UseDNS no # 关闭对客户端 IP 的反向 DNS 解析
GSSAPIAuthentication no # 关闭 Kerberos/GSSAPI 认证协商
UseDNS yes时,sshd 收到连接后会对客户端 IP 做 PTR 反向解析,再用解析出的域名正向解析回来比对。如果 DNS 服务器不可达、或客户端 IP 没有 PTR 记录(内网 IP 基本都没有),sshd 会一直等到 DNS 超时(通常 5~30 秒)才继续认证流程。表现就是「密码提示都没出来就卡十几秒」。设为no可以立刻消除这个延迟。OpenSSH 7.x 起默认已是no,但大量老配置文件里仍写着yes。GSSAPIAuthentication yes同理:客户端会尝试 GSSAPI/Kerberos 认证,在没有 Kerberos 环境的机器上这一步注定失败,但仍要经过一轮协商与可能的 DNS 查询,白白增加延迟。绝大多数环境应设为no。
# 验证是不是这两项导致的慢
ssh -v user@10.0.0.2 # 观察在哪一步停顿最久
time ssh user@10.0.0.2 'exit' # 改配置前后对比耗时
访问控制(白名单 / 黑名单)
AllowUsers deploy ops zhangsan # 只允许这些用户登录,其他全部拒绝
AllowUsers deploy@192.168.0.* # 还能限制来源网段(用户@来源)
DenyUsers test guest ftpuser # 拒绝这些用户
AllowGroups sshusers wheel # 只允许这些组的成员登录
DenyGroups nologin_group
匹配优先级(从先到后,命中即决定):DenyUsers → AllowUsers → DenyGroups → AllowGroups。
# 配合用户组批量管理,比逐个写用户名好维护
groupadd sshusers
usermod -aG sshusers deploy
usermod -aG sshusers zhangsan
高危提醒:
AllowUsers写错(比如漏了自己当前使用的账号)会把自己直接锁在门外,而sshd -t不会报错——它只检查语法,不检查逻辑。
其他常用项
Banner /etc/ssh/banner.txt # 认证前显示的提示文件(法律警告语等)
PrintMotd yes # 登录后显示 /etc/motd
X11Forwarding yes # 是否允许 X11 图形转发,无图形需求时设 no
AllowTcpForwarding no # 禁止端口转发(防止被当跳板穿透内网)
PermitTunnel no
Subsystem sftp /usr/libexec/openssh/sftp-server # 启用 sftp 子系统,注释掉则 sftp 不可用
LogLevel INFO # 日志级别
StrictModes yes # 登录前检查家目录与 .ssh 权限,权限过松则拒绝
Compression delayed
LogLevel 取值:QUIET < FATAL < ERROR < INFO(默认)< VERBOSE < DEBUG1/2/3。
- 排查登录问题时设
VERBOSE,日志会记录登录所用密钥的指纹,便于审计「是谁的密钥登进来的」。 DEBUG级别会记录敏感信息且日志量巨大,仅临时排障使用,用完改回。
Subsystem sftp 还常用于配置「只能传文件、不能登录 Shell」的受限用户:
Subsystem sftp internal-sftp
Match Group sftponly
ChrootDirectory /data/sftp/%u
ForceCommand internal-sftp
AllowTcpForwarding no
X11Forwarding no
Match 块用于对特定用户/组/来源做差异化配置,必须写在文件末尾(Match 之后的所有配置都属于该块)。
9.3 客户端配置 ~/.ssh/config
日常运维效率提升最明显的一个文件。写好之后,ssh web1 就能带上端口、用户、密钥、跳板机全部参数。
mkdir -p ~/.ssh && chmod 700 ~/.ssh
vim ~/.ssh/config
chmod 600 ~/.ssh/config # 权限过松 ssh 会拒绝使用该文件
完整示例:
# ===== 全局默认(写在最前面的 Host * 也可放最后,先匹配先生效)=====
Host *
ServerAliveInterval 60 # 每 60 秒发一次保活包,防 NAT 超时断连
ServerAliveCountMax 3 # 3 次无响应则判定断开
TCPKeepAlive yes
ConnectTimeout 10
Compression yes
ControlMaster auto # 连接复用:同一目标第二次连接秒开
ControlPath ~/.ssh/cm-%r@%h:%p
ControlPersist 10m
AddKeysToAgent yes
# ===== 生产 Web 服务器 =====
Host web1
HostName 192.168.0.183 # 真实地址,Host 只是别名
User deploy
Port 2222
IdentityFile ~/.ssh/id_rsa_prod
IdentitiesOnly yes # 只用指定的这把私钥,避免把所有密钥都试一遍
# ===== 跳板机本身 =====
Host bastion
HostName 203.0.113.10
User ops
Port 22
IdentityFile ~/.ssh/id_rsa_bastion
# ===== 内网机器:经跳板机访问 =====
Host db1
HostName 10.0.0.51
User dbadmin
ProxyJump bastion # OpenSSH 7.3+ 的跳板写法,等价于 -J bastion
IdentityFile ~/.ssh/id_rsa_prod
# 老版本 OpenSSH 用 ProxyCommand 实现跳板
Host db2
HostName 10.0.0.52
User dbadmin
ProxyCommand ssh -q -W %h:%p bastion
# ===== 通配匹配一批机器 =====
Host 10.0.0.*
User root
StrictHostKeyChecking accept-new
Host github.com
User git
IdentityFile ~/.ssh/id_rsa_github
IdentitiesOnly yes
使用效果:
ssh web1 # 自动 = ssh -p 2222 -i ~/.ssh/id_rsa_prod deploy@192.168.0.183
ssh db1 # 自动经 bastion 跳板进内网
scp app.tar.gz web1:/tmp/ # scp / sftp / rsync 全部自动复用这些配置
rsync -av ./dist/ web1:/var/www/html/
ssh -J bastion dbadmin@10.0.0.51 # 命令行临时跳板,多级用逗号分隔:-J b1,b2
ssh -G web1 # 打印某别名最终生效的全部配置,排错用
9.4 加固清单
① 修改默认端口(作用有限,但能降噪)
sed -i 's/^#\?Port 22/Port 2222/' /etc/ssh/sshd_config
semanage port -a -t ssh_port_t -p tcp 2222 # SELinux 必须先放行,否则 sshd 起不来
firewall-cmd --permanent --add-port=2222/tcp
firewall-cmd --reload
sshd -t && systemctl restart sshd
诚实的评价:改端口不能防定向攻击(nmap 全端口扫描几十秒就找到了),但能挡掉绝大多数只扫 22 端口的自动化脚本,/var/log/secure 会清爽非常多,有助于让真实告警不被淹没。
② 禁用 root 直接登录,改用普通用户 + sudo
# 顺序很重要:先建好普通用户并验证能登录,再禁 root
useradd deploy
passwd deploy
usermod -aG wheel deploy # wheel 组默认可 sudo
ssh deploy@192.168.0.183 # 必须先验证通过!
sudo -l # 确认 sudo 权限可用
# 验证成功后再改
vim /etc/ssh/sshd_config # PermitRootLogin no
sshd -t && systemctl restart sshd
好处:攻击者不但要猜密码,还要先猜对用户名;同时所有提权操作都会留下 sudo 审计日志。
③ 优先密钥认证,关闭密码认证
PubkeyAuthentication yes
PasswordAuthentication no
PermitEmptyPasswords no
ChallengeResponseAuthentication no # 这一项也要关,否则可能仍能走键盘交互式密码
关闭前必须先确认密钥能登录,否则重启 sshd 后你就再也进不去了。验证命令:
ssh -o PreferredAuthentications=publickey -o PasswordAuthentication=no deploy@192.168.0.183另外注意:关掉密码认证后
ssh-copy-id也用不了(它依赖密码登录),新机器的公钥要通过装机镜像、cloud-init 或已有运维通道下发。密钥的生成与分发详见 04-02-计划任务与SSH等效性.md
④ 限制来源 IP 与用户白名单
AllowUsers deploy ops
AllowUsers deploy@192.168.0.*
# 更彻底的做法:在防火墙层面只放行运维网段
firewall-cmd --permanent --zone=public --remove-service=ssh
firewall-cmd --permanent --add-rich-rule='rule family=ipv4 source address=192.168.0.0/24 service name=ssh accept'
firewall-cmd --reload
⑤ 防暴力破解
MaxAuthTries 3 # 3 次失败即断开连接,抬高单连接的试错成本
LoginGraceTime 30
MaxAuthTries 只是限制单条连接内的尝试次数,攻击者反复重连仍可继续试。要真正封禁来源 IP,用 fail2ban:
yum -y install epel-release && yum -y install fail2ban
systemctl enable --now fail2ban
配置文件说明:/etc/fail2ban/jail.conf 会在软件升级时被覆盖,自定义配置一律写在 /etc/fail2ban/jail.local(同名项覆盖 jail.conf)。
# /etc/fail2ban/jail.local
[DEFAULT]
bantime = 3600 # 封禁 1 小时(-1 为永久)
findtime = 600 # 统计窗口 10 分钟
maxretry = 5 # 窗口内失败 5 次即封
ignoreip = 127.0.0.1/8 192.168.0.0/24 # 白名单,必须含自己的管理网段
banaction = firewallcmd-ipset # CentOS 7 firewalld 环境用这个后端
[sshd]
enabled = true
port = 2222
filter = sshd
logpath = /var/log/secure
backend = systemd
maxretry = 3
| 参数 | 说明 |
|---|---|
bantime |
封禁持续时间;对反复作恶的 IP 可配合 bantime.increment = true 递增 |
findtime |
在多长的时间窗口内统计失败次数 |
maxretry |
触发封禁的失败次数阈值 |
ignoreip |
白名单,必须写上自己的管理网段,否则极易把自己封掉 |
port |
与 sshd_config 中的 Port 保持一致,改过端口一定要同步 |
logpath |
CentOS/RHEL 认证日志为 /var/log/secure(Debian 系为 /var/log/auth.log) |
backend |
日志读取方式;CentOS 7 上 systemd 比轮询文件更可靠 |
banaction |
执行封禁的后端,firewalld 环境用 firewallcmd-ipset,纯 iptables 环境用默认的 iptables-multiport |
fail2ban-client status # 查看所有 jail 状态
fail2ban-client status sshd # 查看当前封禁列表与失败计数
fail2ban-client set sshd unbanip 1.2.3.4 # 手工解封(万一封了自己)
fail2ban-client set sshd banip 1.2.3.4 # 手工封禁
fail2ban-client reload # 重载配置
# 校验过滤规则能否匹配到日志中的失败记录(配好却不生效时先跑这个)
fail2ban-regex /var/log/secure /etc/fail2ban/filter.d/sshd.conf
⚠️ 把自己封了怎么办:先确认
ignoreip已包含管理网段;已被封时通过控制台 / VNC / IPMI 等带外通道执行上面的unbanip。启用密钥登录后基本不会触发失败计数,两项措施应配合使用。
⑥ 排查暴力破解的来源 IP
# 当前已建立的 SSH 连接
ss -tnp | grep :22
ss -tnp state established '( sport = :22 )'
who / w # 当前登录用户与来源
# 从日志统计失败来源(核心手段)
grep 'Failed password' /var/log/secure | awk '{print $11}' | sort | uniq -c | sort -rn | head -20
grep 'Invalid user' /var/log/secure | awk '{print $10,$12}' | sort | uniq -c | sort -rn | head
grep -c 'Failed password' /var/log/secure # 失败总次数,感受一下被扫的强度
# 成功登录记录(重点审计有没有可疑成功)
grep 'Accepted' /var/log/secure
last -20 # 登录历史(/var/log/wtmp)
lastb -20 # 失败登录历史(/var/log/btmp)
lastlog # 每个用户最后一次登录时间
CentOS/RHEL 的 SSH 日志在 /var/log/secure,Debian/Ubuntu 在 /var/log/auth.log。
⑦ 权限必须正确(高频坑)
密钥认证失败最常见的原因不是密钥不对,而是权限过松。sshd 的 StrictModes yes 会检查权限,一旦发现「组或其他用户可写」就直接拒绝认证,且客户端只看到一句 Permission denied (publickey),毫无提示。
| 对象 | 要求权限 | 命令 |
|---|---|---|
家目录 ~ |
不能被组/其他用户可写(755 / 700) |
chmod 755 ~ |
~/.ssh 目录 |
700 | chmod 700 ~/.ssh |
~/.ssh/authorized_keys |
600(644 也能工作,但推荐 600) | chmod 600 ~/.ssh/authorized_keys |
私钥 ~/.ssh/id_rsa |
600,否则 ssh 客户端直接报错拒绝使用 | chmod 600 ~/.ssh/id_rsa |
~/.ssh/config |
600 | chmod 600 ~/.ssh/config |
| 属主 | 必须是该用户本人 | chown -R user:user ~/.ssh |
# 一条命令修好
chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys ~/.ssh/id_rsa && chown -R $USER:$USER ~/.ssh
# 私钥权限过松时客户端的报错
# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# @ WARNING: UNPROTECTED PRIVATE KEY FILE! @
# Permissions 0644 for '/root/.ssh/id_rsa' are too open.
# This private key will be ignored.
# 启用了 SELinux 时还要修上下文
restorecon -Rv ~/.ssh
ls -Zd ~/.ssh # 正确应为 ssh_home_t
9.5 改配置的正确流程
# 0. 【最重要】保留当前这个已登录的 SSH 会话,另开一个新窗口做验证
# 1. 备份
cp -a /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%F-%H%M)
# 2. 修改
vim /etc/ssh/sshd_config
# 3. 语法检查(不通过绝对不要重启)
sshd -t
sshd -t -f /etc/ssh/sshd_config # 指定文件检查
# 4. 查看最终生效的值(含所有默认值,比 grep 配置文件可靠)
sshd -T | grep -E 'permitrootlogin|passwordauthentication|^port|maxauthtries|usedns|allowusers'
# 5. 生效
systemctl reload sshd # 优先 reload:不影响已有连接
systemctl restart sshd # CentOS 7+
service sshd restart # CentOS 6
/etc/init.d/sshd reload # CentOS 6
# 6. 【不可省略】在新窗口验证能登录
ssh -p 2222 deploy@192.168.0.183
为什么必须保留一个已登录会话?
sshd 重启只影响新建连接,已经建立的 SSH 会话不会被断开。所以只要你手上还留着一个活的会话,即使新配置有问题(端口错、
AllowUsers漏了自己、密码认证关了而密钥没配好),你依然可以在这个老会话里把配置改回去、把服务重新起来。反过来,如果你改完配置就
exit退出,而新配置恰好有问题,那么这台机器对你来说就彻底失联了——只能去机房接显示器,或者依赖云平台的 VNC / 串口控制台 / 救援模式。远程机房环境下这可能意味着几个小时的停机。补充两条保险措施:
sshd -t只检查语法,不检查逻辑。把自己排除在AllowUsers之外、端口和防火墙不匹配,它都不会报错,所以第 6 步的实际登录验证不可替代。- 临时开一个备用端口的 sshd 实例作为退路:
/usr/sbin/sshd -p 2200,验证新配置无误后再杀掉它。
十、文件传输:scp / sftp / rsync
三者都走 SSH 加密通道,不需要额外部署服务,只要 sshd 能连上就能用。
10.1 scp:远程拷贝
scp(secure copy)基于 SSH,传输全程加密,用法几乎与 cp 一致,只是路径可以带 用户@主机: 前缀。
通用语法:
scp [选项] 源路径 目标路径
scp [选项] [user@]host:/remote/path /local/path # 远程 → 本地
scp [选项] /local/path [user@]host:/remote/path # 本地 → 远程
① 本地 → 远程
# 拷贝单个文件到远程目录
scp /share/iso/rhel-5.4-server-i386-dvd.iso 10.0.0.2:/root/Desktop/
scp /bin/bash zhangsan@10.1.1.2:/tmp/newbash # 同时改名
# 拷贝目录必须加 -r
scp -r /share/iso/ 10.0.0.2:/root/Desktop/
scp -r /local/dir user@10.0.0.2:/remote/path
# 一次拷多个文件
scp /etc/hosts /etc/resolv.conf 10.0.0.2:/tmp/
② 远程 → 本地
# 拷贝单个文件
scp 10.0.0.2:/root/Desktop/sn.txt /root/Desktop/
scp zhangsan@192.168.0.182:/some/where/file /local/dir/file
# 拷贝目录加 -r
scp -r 10.0.0.2:/root/Desktop/ /root/Desktop/
scp -r zhangsan@192.168.0.182:/some/where/dirname /local/dir/
# 拷到当前目录
scp 10.0.0.2:/var/log/messages .
③ 指定用户
scp 文件 user1@10.0.0.2:/home/user1/
scp -r /data/backup deploy@10.0.0.2:/data/
不写 用户@ 时,scp 使用本地当前用户名去登录远程主机,用户不存在就会认证失败。
④ 远程 → 远程(本机作为中转控制)
scp user1@10.0.0.2:/tmp/a.txt user2@10.0.0.3:/tmp/
scp -3 user1@10.0.0.2:/tmp/a.txt user2@10.0.0.3:/tmp/ # -3 强制数据经本机转发
常用选项
| 选项 | 作用 |
|---|---|
-r |
递归拷贝目录(传目录必须加,否则报 not a regular file) |
-P 端口 |
指定 SSH 端口,大写 P |
-p |
保留源文件的修改时间、访问时间和权限模式 |
-C |
传输时压缩,跨广域网传文本/日志效果明显,传已压缩文件反而变慢 |
-l 速率 |
限速,单位 Kbit/s(注意是比特不是字节,-l 8000 ≈ 1 MB/s) |
-i 私钥 |
指定私钥文件 |
-q |
静默模式,不显示进度条(脚本中常用) |
-v |
调试输出 |
-o 选项 |
传递 ssh 选项,如 -o StrictHostKeyChecking=no |
-3 |
远程到远程时经本地中转 |
scp -P 2222 -r /data/www deploy@10.0.0.2:/var/www/ # 非默认端口传目录
scp -Cp -l 8000 bigfile.tar.gz 10.0.0.2:/data/ # 压缩 + 保留属性 + 限速约 1MB/s
scp -i ~/.ssh/id_rsa_prod app.jar deploy@10.0.0.2:/opt/
易错点:
-P与-p的大小写
命令 指定端口 保留属性 ssh-p 2222(小写)— scp-P 2222(大写)-p(小写)sftp-P 2222(大写)— rsync没有端口选项,用 -e 'ssh -p 2222'-p或-a用小写
-p指定端口的后果是:scp 以为你要保留文件属性,然后按默认 22 端口去连,报Connection refused,很容易误判成服务端问题。根治办法是在~/.ssh/config里为该主机写好Port,scp 会自动读取。
路径中含空格与特殊字符的引号处理
远程路径会被远程 Shell 再解析一次,因此需要双层转义:
scp "10.0.0.2:/tmp/my file.txt" ./ # 错误:远程 Shell 拆成两个参数
scp "10.0.0.2:'/tmp/my file.txt'" ./ # 正确:内层单引号供远程 Shell 使用
scp 10.0.0.2:/tmp/my\\\ file.txt ./ # 正确:三反斜杠转义
scp '10.0.0.2:/tmp/a\ b.txt' ./ # 正确
# 本地路径只需本地一层引号
scp "/local/my file.txt" 10.0.0.2:/tmp/
# 含 $ ( ) & 等字符同理,用单引号包住远程部分
scp "10.0.0.2:'/tmp/log\$(date).txt'" ./
含空格路径较多时,建议改用 rsync(它对引号的处理更直观)或 sftp。
目标路径为目录与为文件名时的行为差异
# 目标是已存在的目录 → 文件放进该目录,保持原名
scp a.txt 10.0.0.2:/tmp/ # 结果:/tmp/a.txt
scp a.txt 10.0.0.2:/tmp # 同上(/tmp 是已存在目录)
# 目标是不存在的路径 → 当作文件名,即「拷贝并改名」
scp a.txt 10.0.0.2:/tmp/b.txt # 结果:/tmp/b.txt(内容是 a.txt)
scp a.txt 10.0.0.2:/tmp/newdir/ # 报错:No such file or directory(不会自动建目录)
# 目标是已存在的文件 → 直接覆盖,无任何提示,且无法恢复
scp a.txt 10.0.0.2:/etc/hosts # 危险:/etc/hosts 被静默覆盖
# 目录的特殊情况
scp -r /data/www 10.0.0.2:/var/ # /var/www 不存在 → 建立 /var/www
scp -r /data/www 10.0.0.2:/var/ # /var/www 已存在 → 变成 /var/www/www(嵌套!)
最后一条是 scp 传目录最常见的意外,重复执行同一条命令会不断加深嵌套层级。规避方法:明确写出目标目录名 scp -r /data/www 10.0.0.2:/var/www,或改用 rsync。
scp 从 OpenSSH 8.8 起底层默认改用 SFTP 协议,并且官方已把 scp 标记为不推荐(协议设计陈旧,存在服务端可控制客户端写入路径的风险)。新环境建议优先用
sftp或rsync。
10.2 sftp:交互式安全传输
sftp 10.0.0.2 # 以当前用户登录
sftp user1@10.0.0.2 # 指定用户
sftp -P 2222 user1@10.0.0.2 # 指定端口(大写 P)
sftp -i ~/.ssh/id_rsa user@host
登录后进入 sftp> 提示符。常用子命令(记忆规律:带 l 前缀的操作本地,不带的操作远程):
| 子命令 | 作用 |
|---|---|
ls / ll |
列出远程当前目录 |
lls |
列出本地当前目录 |
pwd |
显示远程当前目录 |
lpwd |
显示本地当前目录 |
cd 目录 |
切换远程目录 |
lcd 目录 |
切换本地目录 |
get 远程文件 [本地名] |
下载文件 |
get -r 远程目录 |
下载目录(递归) |
put 本地文件 [远程名] |
上传文件 |
put -r 本地目录 |
上传目录 |
mget 文件模式 |
批量下载,支持通配符,如 mget *.log |
mput 文件模式 |
批量上传,如 mput *.conf |
rm 文件 |
删除远程文件 |
rmdir 目录 |
删除远程空目录 |
mkdir 目录 |
在远程创建目录 |
lmkdir 目录 |
在本地创建目录 |
rename 旧名 新名 |
重命名远程文件 |
chmod 权限 文件 |
修改远程文件权限 |
chown/chgrp |
修改远程属主/属组 |
df -h |
查看远程磁盘使用 |
!命令 |
执行本地 Shell 命令,如 !ls -l |
! |
临时切到本地 Shell,exit 返回 |
progress |
开关传输进度条 |
bye / quit / exit |
退出 |
help / ? |
查看全部子命令 |
典型会话:
sftp> lcd /root/download
sftp> cd /var/log
sftp> ls
sftp> get messages
sftp> mget *.log
sftp> lcd /etc
sftp> put nginx.conf /tmp/nginx.conf
sftp> put -r /data/www
sftp> rm /tmp/old.tar.gz
sftp> mkdir /tmp/backup
sftp> bye
批处理模式 -b(脚本中免交互使用)
# 把子命令写进文件
cat > /root/sftp.batch <<'EOF'
cd /data/upload
put /tmp/report.csv
get remote.log /tmp/
bye
EOF
sftp -b /root/sftp.batch user1@10.0.0.2
sftp -b - user1@10.0.0.2 <<'EOF' # -b - 表示从标准输入读
cd /tmp
put a.txt
bye
EOF
# 批处理默认遇错即退出;在子命令前加 - 可忽略该行错误
sftp -b batch.txt -oBatchMode=yes user@host # BatchMode=yes 禁止密码提示,必须已配密钥
sftp 与传统 ftp 的区别
| 对比项 | ftp | sftp |
|---|---|---|
| 底层协议 | FTP(21 控制端口 + 数据端口) | SSH 子系统,只用 22 一个端口 |
| 加密 | 明文(含用户名密码) | 全程加密 |
| 需要额外服务 | 需装并运行 vsftpd / proftpd | 不需要,sshd 自带(Subsystem sftp) |
| 防火墙 | 主动/被动模式,数据端口配置麻烦 | 只放行 22 即可 |
| 账号 | 可用虚拟账号 | 使用系统账号 |
| 匿名访问 | 支持 | 不支持 |
| 断点续传 | 支持 | 支持(reget / reput) |
结论:内部运维传文件优先 sftp;需要对外提供匿名下载、大量虚拟账号或严格的目录配额时才考虑 FTP 服务。
详见 09-03-FTP服务.md
10.3 rsync:增量同步
原理与优势
rsync 采用「快速检查 + 滚动校验(rolling checksum)」算法:
- 先按文件大小和修改时间筛选出可能有变化的文件(默认行为,很快)。
- 对需要传输的文件,把它切成固定大小的块,逐块计算弱校验(Adler-32)与强校验(MD5),只把目标端缺失或不同的块通过网络传过去。
相比 scp 的优势:
| 对比项 | scp | rsync |
|---|---|---|
| 传输方式 | 每次全量传输 | 增量,只传差异部分 |
| 重复执行 | 全部重传 | 未变化的文件直接跳过,秒级完成 |
| 中断续传 | 从头开始 | -P 支持断点续传 |
| 删除同步 | 不支持 | --delete 使目标与源完全一致 |
| 排除文件 | 不支持 | --exclude 灵活过滤 |
| 保留属性 | -p 部分 |
-a 完整保留权限/属主/时间/软链接 |
| 限速 | -l(Kbit/s) |
--bwlimit(KB/s) |
| 适用场景 | 一次性拷贝小文件 | 备份、代码发布、目录镜像、定期同步 |
对于「每天同步一个 10 GB 目录,其中只改了 20 MB」这种场景,scp 要传 10 GB,rsync 只传约 20 MB,差距是量级的。
常用选项
| 选项 | 作用 |
|---|---|
-a |
归档模式,等价于 -rlptgoD:递归 + 保留软链接、权限、时间、属组、属主、设备文件。最常用 |
-v |
显示传输过程(-vv、-vvv 更详细) |
-z |
传输时压缩,跨公网传文本效果好 |
-P |
等于 --partial --progress:显示进度条 + 保留未传完的部分文件以便续传 |
-r |
递归(-a 已包含) |
-l |
保留软链接本身;-L 则把软链接转成实际文件 |
-h |
输出使用人类可读的单位 |
-n / --dry-run |
只试运行不实际传输,配合 -v 预览将发生什么,用 --delete 前必做 |
--delete |
删除目标端存在但源端没有的文件,使两端完全一致 |
--exclude=模式 |
排除匹配的文件/目录,可多次使用 |
--exclude-from=文件 |
从文件读取排除列表 |
--include=模式 |
在排除规则中开例外(须写在对应 --exclude 之前) |
-e 'ssh -p 端口' |
指定远程 Shell 及其参数(改过 SSH 端口时必用) |
--bwlimit=KB/s |
限速,如 --bwlimit=5000 约 5 MB/s |
--backup --backup-dir=目录 |
覆盖前先把旧文件备份到指定目录 |
-u / --update |
跳过目标端比源端更新的文件 |
-c |
强制按内容校验和比较(忽略时间/大小快速判断),慢但最可靠 |
--stats |
传输结束后输出统计信息 |
结尾斜杠的关键差异(rsync 最重要的一个细节)
规则只有一句:源路径结尾有 / 表示「同步该目录里的内容」,没有 / 表示「同步该目录本身」。 目标路径的斜杠没有影响。
# 假设本地存在 /data/www/ 目录,里面有 index.html
情况 A:源路径带结尾斜杠
rsync -av /data/www/ 10.0.0.2:/var/dest/
# 结果:/var/dest/index.html
# 含义:把 www 目录「内部的内容」放到 dest 里
情况 B:源路径不带结尾斜杠
rsync -av /data/www 10.0.0.2:/var/dest/
# 结果:/var/dest/www/index.html
# 含义:把 www 这个「目录本身」放进 dest,多出一层 www
记忆方法:/data/www/ 读作「www 里的东西」,/data/www 读作「www 这个目录」。或者:带斜杠 = 内容,不带 = 目录。
这个差异配合 --delete 会造成严重后果:
# 意图:让远程 /var/www 与本地 /data/www 完全一致
rsync -av --delete /data/www 10.0.0.2:/var/www/ # 错!变成 /var/www/www/,
# 且 --delete 会删掉 /var/www 下原有全部内容
rsync -av --delete /data/www/ 10.0.0.2:/var/www/ # 对
所以任何带 --delete 的命令,第一次都必须先加 -n 试运行:
rsync -avn --delete /data/www/ 10.0.0.2:/var/www/ # 先看清楚要删哪些文件
本地与远程互传
# 本地 → 本地(也可以当增量 cp 用)
rsync -av /data/www/ /backup/www/
# 本地 → 远程(推送)
rsync -avz /data/www/ deploy@10.0.0.2:/var/www/html/
rsync -avz -e 'ssh -p 2222' /data/www/ deploy@10.0.0.2:/var/www/html/
# 远程 → 本地(拉取)
rsync -avz deploy@10.0.0.2:/var/log/nginx/ /backup/nginx-logs/
rsync -avzP -e 'ssh -p 2222 -i ~/.ssh/id_rsa_prod' deploy@10.0.0.2:/data/db.sql /backup/
# 配好 ~/.ssh/config 后可以极简
rsync -avzP /data/www/ web1:/var/www/html/
实用实例
# ① 代码发布:排除版本控制与临时文件,删除目标端多余文件
rsync -avz --delete \
--exclude='.git/' --exclude='node_modules/' --exclude='*.log' --exclude='.env' \
/home/dev/project/ deploy@10.0.0.2:/var/www/app/
# ② 每日备份:保留完整属性,限速避免占满带宽,出错重试
rsync -az --delete --bwlimit=5000 --stats \
/data/ backup@10.0.0.9:/backup/$(hostname)/ >> /var/log/rsync-backup.log 2>&1
# ③ 断点续传大文件
rsync -avzP /iso/CentOS-7-x86_64-DVD.iso 10.0.0.2:/data/iso/
# 中断后重复执行同一条命令,从断点继续
# ④ 覆盖前保留旧版本,便于回滚
rsync -av --backup --backup-dir=/backup/$(date +%F) /data/www/ 10.0.0.2:/var/www/
# ⑤ 从排除列表文件读取规则
cat > /root/rsync-exclude.txt <<'EOF'
.git/
node_modules/
*.tmp
/cache/
EOF
rsync -avz --exclude-from=/root/rsync-exclude.txt /app/ 10.0.0.2:/app/
# ⑥ 只同步某类文件(include 要写在 exclude 之前)
rsync -avz --include='*/' --include='*.conf' --exclude='*' /etc/ 10.0.0.2:/backup/etc/
# ⑦ 配合 crontab 定时同步
# 0 2 * * * /usr/bin/rsync -az --delete /data/ backup@10.0.0.9:/backup/data/
10.4 三者选型对照
| 维度 | scp | sftp | rsync |
|---|---|---|---|
| 底层通道 | SSH | SSH 子系统 | 默认走 SSH(也可用 rsync 守护进程 873/tcp) |
| 交互方式 | 一次性命令 | 交互式会话(可浏览目录) | 一次性命令 |
| 增量传输 | 不支持,每次全量 | 不支持 | 支持,核心优势 |
| 断点续传 | 不支持 | 支持(reget/reput) |
支持(-P) |
| 删除同步 | 不支持 | 手工 rm |
--delete |
| 排除过滤 | 不支持 | 不支持 | --exclude |
| 保留属性 | -p(部分) |
有限 | -a(最完整) |
| 压缩 | -C |
-C |
-z |
| 限速 | -l(Kbit/s) |
-l |
--bwlimit(KB/s) |
| 远程需安装 | 无(sshd 自带) | 无(sshd 自带) | 两端都要装 rsync |
| 学习成本 | 最低 | 低 | 中(斜杠、过滤规则有坑) |
| 适用场景 | 临时拷几个文件、脚本里一次性传输 | 不确定远程有什么文件、需要边看边传 | 备份、代码发布、目录镜像、定期同步 |
一句话选型:临时拷文件用 scp,要浏览着传用 sftp,反复同步目录一律用 rsync。
# rsync 不是默认安装的,注意两端都要装
yum -y install rsync # CentOS
rpm -q rsync
十一、排错清单
11.1 连不上:分层排查流程
无论报什么错,都按这五层从下往上查,每一层确认通过再进入下一层。
第 1 层:物理链路与网卡状态
mii-tool eth0 # link ok / no link(CentOS 6)
ethtool eth0 | grep -E 'Link detected|Speed|Duplex'
ip link show # state UP 且有 LOWER_UP 才算物理通
ip addr show # 确认 IP 配上了
no link / Link detected: no → 网线、光模块、交换机端口问题,不用往上查了。
第 2 层:IP 与路由(ping)
ping -c 2 127.0.0.1 # 协议栈本身
ping -c 2 本机IP # 本机网卡
ping -c 2 网关IP # 同网段与网关
ping -c 2 目标IP # 目标主机
ping -c 2 8.8.8.8 # 外网连通性
ping -c 2 www.baidu.com # DNS 解析
ip route # 默认网关是否正确
traceroute -n 目标IP # 断在哪一跳
注意:很多环境(云安全组、Windows 防火墙)默认禁 ICMP,ping 不通不代表 SSH 连不上,应该直接测端口。
第 3 层:端口可达性
# 客户端侧测试
telnet 10.0.0.2 22 # 出现 SSH-2.0-OpenSSH_xxx 即端口通
nc -zv 10.0.0.2 22 # Connection to 10.0.0.2 22 port succeeded!
nc -zv -w 3 10.0.0.2 22
nmap -p 22 10.0.0.2
timeout 3 bash -c 'cat < /dev/null > /dev/tcp/10.0.0.2/22' && echo open
# 服务端侧确认
ss -tnlp | grep 22
firewall-cmd --list-all # CentOS 7+
iptables -nL # CentOS 6
第 4 层:sshd 服务本身
systemctl status sshd # CentOS 7+
service sshd status # CentOS 6
sshd -t # 配置语法
sshd -T | grep -E '^port|listenaddress|permitrootlogin|passwordauthentication'
journalctl -u sshd -n 50 --no-pager
tail -50 /var/log/secure
第 5 层:认证
ssh -v user@10.0.0.2 # 看认证方式协商
grep -E 'Failed|Invalid|Accepted' /var/log/secure | tail -20
id user # 用户是否存在
passwd -S user # 密码是否被锁(LK 表示锁定)
chage -l user # 密码是否过期
grep user /etc/shadow # 密码字段以 ! 或 * 开头表示锁定
grep user /etc/passwd # Shell 是否为 /sbin/nologin
ls -ld ~/.ssh ~/.ssh/authorized_keys # 权限
分层口诀:先看灯(链路),再通 IP,再探端口,再查服务,最后查认证。
11.2 Permission denied (publickey)
报错:
Permission denied (publickey).
Permission denied (publickey,gssapi-keyex,gssapi-with-mic).
含义:网络与服务都正常,是认证阶段被拒。而且服务端只允许公钥认证(提示里没有 password),说明密码认证已被关闭。按顺序排查:
① 权限问题(最常见,占一半以上)
# 服务端上,被登录用户的家目录
ls -ld /home/deploy /home/deploy/.ssh /home/deploy/.ssh/authorized_keys
chmod 755 /home/deploy # 家目录不能组/其他可写
chmod 700 /home/deploy/.ssh
chmod 600 /home/deploy/.ssh/authorized_keys
chown -R deploy:deploy /home/deploy/.ssh
# 客户端上,私钥权限
chmod 600 ~/.ssh/id_rsa
StrictModes yes(默认)会因为「家目录组可写」这种看起来无关的问题直接拒绝认证,且日志里才有原因,客户端看不到:
tail -f /var/log/secure
# Authentication refused: bad ownership or modes for directory /home/deploy
# Authentication refused: bad ownership or modes for file /home/deploy/.ssh/authorized_keys
② authorized_keys 内容问题
cat ~/.ssh/authorized_keys | head # 确认公钥确实写进去了
wc -l ~/.ssh/authorized_keys # 每把公钥必须占「一整行」,不能换行断开
ssh-keygen -l -f ~/.ssh/authorized_keys # 列出其中每把公钥的指纹
ssh-keygen -l -f ~/.ssh/id_rsa.pub # 与客户端公钥指纹对比,必须一致
常见错误:手工复制粘贴时公钥被编辑器折行、开头 ssh-rsa 少了、结尾多了空格或 ^M(从 Windows 复制)。
sed -i 's/\r$//' ~/.ssh/authorized_keys # 清除 Windows 换行符
③ sshd_config 配置问题
sshd -T | grep -Ei 'pubkeyauth|authorizedkeysfile|permitrootlogin|allowusers|allowgroups|strictmodes'
逐项确认:
PubkeyAuthentication yes # 必须为 yes
AuthorizedKeysFile .ssh/authorized_keys # 路径是否被改到别处
PermitRootLogin prohibit-password # 登 root 时相关
AllowUsers deploy # 你的用户是否在白名单里
StrictModes yes
④ SELinux 上下文问题
家目录是手工创建或从别处拷来的,.ssh 的 SELinux 类型可能不对,sshd 就读不到 authorized_keys:
getenforce # Enforcing 时才有此问题
ls -Zd ~/.ssh ~/.ssh/authorized_keys
# 正确:unconfined_u:object_r:ssh_home_t:s0
# 错误:unconfined_u:object_r:user_home_t:s0 或 admin_home_t
restorecon -Rv ~/.ssh # 修复上下文
ausearch -m avc -ts recent | grep sshd # 查看 SELinux 拒绝记录
grep denied /var/log/audit/audit.log | tail
⑤ 客户端调试
ssh -vvv deploy@10.0.0.2 2>&1 | grep -iE 'offering|authentications|denied|key'
# Offering public key: ~/.ssh/id_rsa 客户端确实提交了这把
# Authentications that can continue: publickey 服务端拒绝后仍要求公钥 → 服务端侧问题
ssh -i ~/.ssh/id_rsa -o IdentitiesOnly=yes deploy@10.0.0.2 # 明确指定密钥排除干扰
11.3 登录很慢(卡十几秒才出密码提示)
两大原因,服务端改配置解决:
# /etc/ssh/sshd_config
UseDNS no # ① 关闭客户端 IP 反向 DNS 解析
GSSAPIAuthentication no # ② 关闭 Kerberos/GSSAPI 协商
sshd -t && systemctl restart sshd # CentOS 7+
service sshd restart # CentOS 6
# 验证效果
time ssh user@10.0.0.2 'exit'
ssh -v user@10.0.0.2 # 看在哪一步停顿
UseDNS yes:sshd 反查客户端 IP 的 PTR 记录,内网 IP 通常没有 PTR,只能干等 DNS 超时。GSSAPIAuthentication yes:客户端先尝试 Kerberos,没有 KDC 环境时这一步注定失败但仍要走完协商。
客户端侧也可以规避:
ssh -o GSSAPIAuthentication=no user@host
# ~/.ssh/config
Host *
GSSAPIAuthentication no
第三个次要原因:/etc/hosts 里没有互绑主机名,或 /etc/resolv.conf 里配了不可达的 DNS。
# 多台服务器互绑,能显著加快连接
cat >> /etc/hosts <<'EOF'
10.0.0.2 qianyun.com
10.0.0.61 server61.com
EOF
11.4 连接一段时间自动断开
Write failed: Broken pipe
Connection to 10.0.0.2 closed by remote host.
client_loop: send disconnect: Broken pipe
三个可能的责任方,逐个排查:
① 服务端 sshd 主动踢人
sshd -T | grep -i clientalive
# clientaliveinterval 300
# clientalivecountmax 2 → 300 × 2 = 600 秒后断开
# 想让长连接保持:拉长总时长
ClientAliveInterval 60
ClientAliveCountMax 30 # 60 × 30 = 1800 秒
② Shell 层的空闲超时 TMOUT
echo $TMOUT # 有数值(秒)就是它在起作用
grep -rn TMOUT /etc/profile /etc/profile.d/ /etc/bashrc ~/.bashrc ~/.bash_profile
unset TMOUT # 当前会话临时解除
export TMOUT=0 # 等价
TMOUT 是 bash 的内置变量,到时间会直接退出登录 Shell,表现为「一段时间不动就被踢出去了」,常见于按等级保护要求做过安全基线的机器。注意:出于合规要求设置的 TMOUT 通常带 readonly,无法 unset,此时应该用 screen / tmux 保持工作现场。
③ 中间设备(NAT、防火墙、云负载均衡)回收空闲连接
客户端侧发保活包最有效:
ssh -o ServerAliveInterval=60 -o ServerAliveCountMax=3 user@host
# ~/.ssh/config,一次配好长期有效
Host *
ServerAliveInterval 60
ServerAliveCountMax 3
TCPKeepAlive yes
ServerAliveInterval(客户端发给服务端)与 ClientAliveInterval(服务端发给客户端)方向相反,两边配一个就够,通常配客户端更方便。
根治办法:用 tmux / screen
tmux new -s work # 新建会话
# 断线后重连
tmux attach -t work
tmux ls
screen -S work
screen -r work
网络断了会话仍在服务端运行,长时间任务(编译、数据迁移、yum update)都应该放在 tmux 里跑。
11.5 Too many authentication failures
Received disconnect from 10.0.0.2 port 22:2: Too many authentication failures
Disconnected from 10.0.0.2 port 22
成因:客户端把 ~/.ssh/ 下所有私钥(以及 ssh-agent 里加载的全部密钥)挨个提交给服务端尝试,还没试到对的那把,就先撞上了服务端的 MaxAuthTries 限制(默认 6,加固后常设为 3)。密钥越多越容易触发。
ssh-add -l # 看 agent 里加载了多少把密钥
ssh -v host 2>&1 | grep -i offering # 看客户端依次提交了哪些密钥
解决办法:
# ① 明确指定密钥 + IdentitiesOnly(最推荐)
ssh -i ~/.ssh/id_rsa_prod -o IdentitiesOnly=yes deploy@10.0.0.2
# ② 临时清空 agent
ssh-add -D # 删除 agent 中所有密钥
ssh-add ~/.ssh/id_rsa_prod # 只加载需要的那把
# ③ 强制只用密码认证登录一次
ssh -o PubkeyAuthentication=no -o PreferredAuthentications=password user@10.0.0.2
IdentitiesOnly yes 的含义是「只使用 IdentityFile 明确指定的密钥,忽略 agent 里的其他密钥」。写进 ~/.ssh/config 可永久解决:
Host web1
HostName 192.168.0.183
User deploy
IdentityFile ~/.ssh/id_rsa_prod
IdentitiesOnly yes
服务端侧也可适当放宽(但不建议为此把 MaxAuthTries 调很大,那会削弱防暴力破解能力)。
11.6 Host key verification failed
Host key verification failed.
本地 known_hosts 里的主机密钥与服务端出示的不一致(详见 8.3 节)。
ssh-keygen -R 10.0.0.2 # 删掉这一条记录,重连后重新确认指纹
ssh-keygen -R "[10.0.0.2]:2222" # 非默认端口
ssh-keygen -F 10.0.0.2 # 先查询确认有这条记录
ssh-keyscan -t rsa,ecdsa 10.0.0.2 >> ~/.ssh/known_hosts # 批量重建
如果是你自己刚重装了这台机器,那就是正常变更,清理即可;如果没有任何人动过这台机器,就要警惕中间人攻击,先通过带外渠道核对服务端指纹再继续。
# 到服务端上核对(对比客户端报错里显示的指纹)
ssh-keygen -lf /etc/ssh/ssh_host_rsa_key.pub
ssh-keygen -lf /etc/ssh/ssh_host_ecdsa_key.pub
11.7 Connection reset by peer
ssh_exchange_identification: read: Connection reset by peer
kex_exchange_identification: Connection closed by remote host
Connection reset by 10.0.0.2 port 22
服务端在完成握手前主动断开了连接(发了 RST)。可能原因:
| 原因 | 检查方法 |
|---|---|
被 /etc/hosts.deny(TCP Wrappers)拒绝 |
cat /etc/hosts.deny /etc/hosts.allow;CentOS 6 常用,7 之后 sshd 多数已不链接 libwrap |
| 被 fail2ban / DenyHosts 封禁了你的 IP | fail2ban-client status sshd;fail2ban-client set sshd unbanip 你的IP |
| 服务端连接数达到上限 | sshd -T \| grep -i maxstartups;MaxStartups 10:30:100 |
| 服务端资源耗尽(内存/文件描述符/进程数满) | free -m、df -h、dmesg | tail、ulimit -n |
/var 分区写满导致无法记日志 |
df -h /var |
| 主机密钥文件损坏或权限错误 | ls -l /etc/ssh/ssh_host_*(私钥须 600)、sshd -t |
| 中间设备(IPS/WAF/负载均衡)重置连接 | 换网络环境测试,或在服务端抓包 tcpdump -i any port 22 -nn |
| 密钥交换算法不兼容(新客户端连老服务端) | ssh -o KexAlgorithms=+diffie-hellman-group1-sha1 -o HostKeyAlgorithms=+ssh-rsa user@host |
# 服务端排查组合
tail -50 /var/log/secure
journalctl -u sshd -n 50 --no-pager
df -h /var; free -m
ls -l /etc/ssh/ssh_host_*
tcpdump -i any port 22 -nn -c 20 # 确认包到没到、是谁发的 RST
11.8 scp 报 not a regular file
scp /data/www 10.0.0.2:/tmp/
# /data/www: not a regular file
原因:源路径是目录,而 scp 默认只传普通文件。加 -r 递归即可:
scp -r /data/www 10.0.0.2:/tmp/
同类错误还有:
scp *.log 10.0.0.2:/tmp/ # 目录里有子目录时报同样的错,加 -r 或用 tar 打包
tar zcf - /data/www | ssh 10.0.0.2 'tar zxf - -C /tmp' # 目录层级多时更快
另一个易混的报错:
scp: /tmp/newdir/: No such file or directory # 目标目录不存在,scp 不会自动创建
ssh 10.0.0.2 'mkdir -p /tmp/newdir' && scp -r /data 10.0.0.2:/tmp/newdir/
11.9 rsync 结尾斜杠导致目录层级错乱
现象:同步完成后目标端变成 /var/www/www/index.html,多了一层;重复执行还会继续加深成 /var/www/www/www/。
rsync -av /data/www 10.0.0.2:/var/www/ # 错:源不带斜杠 → /var/www/www/
rsync -av /data/www/ 10.0.0.2:/var/www/ # 对:源带斜杠 → /var/www/
规则复述一遍:源路径结尾带 / = 同步目录里的内容;不带 / = 把目录本身放进去。
补救与预防:
# 已经错了:删掉多出来的那层重新同步
ssh 10.0.0.2 'rm -rf /var/www/www'
rsync -av --delete /data/www/ 10.0.0.2:/var/www/
# 预防:任何 --delete 操作先 dry-run
rsync -avn --delete /data/www/ 10.0.0.2:/var/www/ | head -30
rsync -avn --delete --stats /data/www/ 10.0.0.2:/var/www/ # 看会删多少个文件
--delete 加上斜杠写错,等于「把目标目录下原有的全部内容删掉,再塞进一个嵌套目录」,在生产环境是可以造成事故的组合,务必先试运行。
11.10 其他常见报错速查
| 报错 | 原因 | 处理 |
|---|---|---|
ssh: Could not resolve hostname xxx |
主机名无法解析 | 检查 /etc/hosts、/etc/resolv.conf,或直接用 IP |
Permission denied, please try again. |
密码错误 / 用户被锁 | passwd -S user、chage -l user、faillock |
Received disconnect: Too many authentication failures |
密钥试太多次 | -o IdentitiesOnly=yes、ssh-add -D |
Bad owner or permissions on ~/.ssh/config |
配置文件权限过松 | chmod 600 ~/.ssh/config |
sign_and_send_pubkey: signing failed |
私钥损坏或 agent 异常 | ssh-add -D 后重新加载;检查私钥完整性 |
Agent admitted failure to sign using the key |
ssh-agent 未加载密钥 | ssh-add ~/.ssh/id_rsa |
no matching key exchange method found |
新客户端连老服务端,算法被弃用 | ssh -o KexAlgorithms=+diffie-hellman-group14-sha1 ... |
no matching host key type found |
同上,主机密钥算法被弃用 | ssh -o HostKeyAlgorithms=+ssh-rsa ... |
shell request failed on channel 0 |
用户 Shell 为 nologin,或服务端资源耗尽 | 检查 /etc/passwd 的 Shell 字段、df -h、进程数 |
Error, some other host already uses address x.x.x.x |
重启网络时检测到 IP 冲突 | 换一个未被占用的 IP;arping -I eth0 IP 定位占用者 |
ping: unknown host www.baidu.com |
DNS 未配置或不可达 | 配 DNS1= 或 /etc/resolv.conf,重启网络 |
sudo: no tty present and no askpass program specified |
ssh 远程执行 sudo 无终端 | ssh -t host 'sudo xxx' |
练习
基础作业
1. 将 192.168.1.55 主机的 /var/www/html/index.html 目录下的所有内容都拷贝到本机的 /soft 目录下。
# 先确保本地目标目录存在
mkdir -p /soft
# 方式一:scp(目录必须加 -r)
scp -r 192.168.1.55:/var/www/html/index.html/* /soft/
# 若 index.html 是目录,且要连目录本身一起拷过来
scp -r 192.168.1.55:/var/www/html/index.html /soft/
# 指定用户与非默认端口
scp -r -P 2222 root@192.168.1.55:/var/www/html/index.html/* /soft/
# 方式二:rsync(推荐,可增量、可续传)
rsync -avz 192.168.1.55:/var/www/html/index.html/ /soft/
要点说明:
- 传目录必须加
-r,否则报not a regular file。 - 「目录下的所有内容」对应源路径写
目录/*(scp)或目录/(rsync,注意结尾斜杠)。 - 不写
用户@时使用本地当前用户名登录远程主机。 - 本地
/soft不存在时 scp 会报No such file or directory,需先mkdir -p /soft。
2. 创建两台虚拟机,并为两台虚拟机都绑定一个永久有效的主机名。
# ===== CentOS 7 及以上 =====
# 第一台
hostnamectl set-hostname server1.qianyun.com
hostnamectl status
cat /etc/hostname # server1.qianyun.com
# 第二台
hostnamectl set-hostname server2.qianyun.com
# ===== CentOS 6 =====
# 临时生效
hostname server1.qianyun.com
echo "server1.qianyun.com" > /proc/sys/kernel/hostname # 等价写法
# 永久生效:编辑 /etc/sysconfig/network
vim /etc/sysconfig/network
NETWORKING=yes
HOSTNAME=server1.qianyun.com
# 验证(CentOS 6 需重启或重新登录后 PS1 才更新)
hostname
hostname -f # 显示 FQDN
uname -n
要点:主机名建议写成 FQDN(Full Qualified Domain Name,全限定域名),即 主机名.域名 格式,如 server1.qianyun.com。部分软件(如 Apache)启动时若解析不到 FQDN 会报警告。
3. 将创建的两台虚拟机互绑主机名。
假设 server1 是 10.0.0.61,server2 是 10.0.0.62。
# 在 server1(10.0.0.61)上执行
cat >> /etc/hosts <<'EOF'
10.0.0.61 server1.qianyun.com server1
10.0.0.62 server2.qianyun.com server2
EOF
# 在 server2(10.0.0.62)上执行同样内容
cat >> /etc/hosts <<'EOF'
10.0.0.61 server1.qianyun.com server1
10.0.0.62 server2.qianyun.com server2
EOF
# 双向验证
# server1 上
ping -c 2 server2
ssh root@server2 hostname
# server2 上
ping -c 2 server1
ssh root@server1 hostname
完整的 /etc/hosts 示例:
127.0.0.1 localhost localhost.localdomain
::1 localhost localhost.localdomain
10.0.0.61 server1.qianyun.com server1
10.0.0.62 server2.qianyun.com server2
为什么要互相绑定主机名? 用 SSH 连接另一台机器时,如果服务端开了 UseDNS yes 而客户端 IP 没有 PTR 记录,sshd 会一直等到 DNS 解析超时才给出密码提示,表现为「卡几秒才出现密码提示」。多台服务器在 /etc/hosts 中互相绑定(或服务端设 UseDNS no)可显著加快连接。
名称解析顺序:系统先查 /etc/hosts,再查 DNS,由 /etc/nsswitch.conf 的 hosts: 行控制:
grep '^hosts:' /etc/nsswitch.conf
# hosts: files dns ← files 就是 /etc/hosts,排在 dns 前面
服务器数量很多时怎么管理主机名? 逐台维护 /etc/hosts 不现实,可选方案:
- 脚本批量分发统一的
/etc/hosts(for ip in ...; do scp /etc/hosts $ip:/etc/; done) - 自动化运维工具(Ansible、Puppet、SaltStack)统一下发
- 搭建内部 DNS 服务器(规模上百台后的标准做法)
- 批量装机时(Kickstart / Cobbler)自动写入
动手练习
4. 为一台服务器配置静态 IP(192.168.0.183/24,网关 192.168.0.1,DNS 223.5.5.5)并验证。
# ===== CentOS 7+:编辑网卡配置文件 =====
vim /etc/sysconfig/network-scripts/ifcfg-ens33
TYPE=Ethernet
BOOTPROTO=none
NAME=ens33
DEVICE=ens33
ONBOOT=yes
IPADDR=192.168.0.183
PREFIX=24
GATEWAY=192.168.0.1
DNS1=223.5.5.5
DNS2=8.8.8.8
nmcli con reload && nmcli con up ens33 # CentOS 7+ 生效
systemctl restart network # 或重启网络服务
# ===== CentOS 6 =====
vim /etc/sysconfig/network-scripts/ifcfg-eth0
# BOOTPROTO=static / IPADDR / NETMASK=255.255.255.0 / GATEWAY / ONBOOT=yes / NM_CONTROLLED=no
service network restart
# ===== 验证四件事 =====
ip addr show ens33 | grep inet # ① IP 对不对
ip route | grep default # ② 默认网关对不对
cat /etc/resolv.conf # ③ DNS 写进去了吗
ping -c 2 192.168.0.1 # ④ 网关通不通
ping -c 2 223.5.5.5 # 外网 IP
ping -c 2 www.baidu.com # DNS 解析
5. 用 nmcli 创建一个新连接并激活(不手工编辑配置文件)。
# 查看设备与连接
nmcli dev status
nmcli con show
# 创建静态 IP 连接
nmcli con add type ethernet con-name static-183 ifname ens33 \
ipv4.method manual \
ipv4.addresses 192.168.0.183/24 \
ipv4.gateway 192.168.0.1 \
ipv4.dns "223.5.5.5 8.8.8.8" \
autoconnect yes
# 激活
nmcli con up static-183
nmcli con show static-183 | grep -E 'ipv4.addresses|ipv4.gateway|ipv4.dns'
# 修改已有连接
nmcli con mod static-183 ipv4.addresses 192.168.0.184/24
nmcli con mod static-183 +ipv4.dns 114.114.114.114
nmcli con up static-183 # 修改后必须重新激活才生效
# 创建 DHCP 连接
nmcli con add type ethernet con-name dhcp-conn ifname ens33 ipv4.method auto
# 删除连接
nmcli con delete dhcp-conn
远程操作时用
nmcli con up(原子切换)而不是nmcli con down+up,后者会立即断开你自己的 SSH 会话。
6. 修改 SSH 端口为 2222 并禁用 root 直接登录,然后验证。
# 【第 0 步】保留当前 SSH 会话不要退出!另开窗口验证
# ① 先创建可用的普通用户并验证能登录
useradd deploy && echo 'P@ssw0rd' | passwd --stdin deploy
usermod -aG wheel deploy
ssh deploy@192.168.0.183 # 必须先确认能登录成功
sudo -l # 确认 sudo 可用
# ② 备份并修改配置
cp -a /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%F)
vim /etc/ssh/sshd_config
Port 2222
PermitRootLogin no
PasswordAuthentication yes
UseDNS no
GSSAPIAuthentication no
MaxAuthTries 3
AllowUsers deploy
# ③ SELinux 放行新端口(否则 sshd 起不来)
semanage port -a -t ssh_port_t -p tcp 2222
semanage port -l | grep ssh_port_t
# ④ 防火墙放行
firewall-cmd --permanent --add-port=2222/tcp
firewall-cmd --reload
# ⑤ 语法检查后重启
sshd -t
sshd -T | grep -E '^port|permitrootlogin|allowusers'
systemctl restart sshd # CentOS 7+
service sshd restart # CentOS 6
# ⑥ 在新窗口验证(老会话保持不动)
ssh -p 2222 deploy@192.168.0.183 # 应该成功
ssh -p 2222 root@192.168.0.183 # 应该被拒:Permission denied
ssh 192.168.0.183 # 应该 Connection refused(22 已不监听)
ss -tnlp | grep 2222
# ⑦ 全部验证通过后,从防火墙移除旧端口
firewall-cmd --permanent --remove-service=ssh
firewall-cmd --reload
7. 用 ssh 远程执行命令,并写一个批量执行的脚本。
# 单条与多条
ssh 10.0.0.62 date
ssh 10.0.0.62 'hostname; uptime; df -h /'
ssh 10.0.0.62 'echo $HOSTNAME' # 单引号 → 远程展开(正确)
ssh 10.0.0.62 "echo $HOSTNAME" # 双引号 → 本地展开(对比观察差异)
# 需要 sudo 或交互程序时加 -t
ssh -t 10.0.0.62 'sudo systemctl restart sshd'
ssh -t 10.0.0.62 'top -n 1'
# 执行本地脚本,无需上传
ssh 10.0.0.62 'bash -s' < /root/check.sh
# 批量执行脚本
cat > /root/batch.sh <<'EOF'
#!/bin/bash
HOSTS="10.0.0.61 10.0.0.62 10.0.0.63"
CMD="$*"
[ -z "$CMD" ] && { echo "用法: $0 '要执行的命令'"; exit 1; }
for h in $HOSTS; do
echo "=============== $h ==============="
ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=accept-new \
-o BatchMode=yes root@$h "$CMD" || echo "[FAIL] $h 连接或执行失败"
done
EOF
chmod +x /root/batch.sh
/root/batch.sh 'uptime'
/root/batch.sh 'df -h / | tail -1'
/root/batch.sh 'systemctl is-active sshd'
要点:批量脚本必须加 ConnectTimeout(避免一台不通卡住全部)和 BatchMode=yes(禁止密码提示导致脚本挂起,前提是已配好密钥)。
8. 用 ~/.ssh/config 配置跳板机访问内网主机。
mkdir -p ~/.ssh && chmod 700 ~/.ssh
vim ~/.ssh/config
chmod 600 ~/.ssh/config
Host *
ServerAliveInterval 60
ServerAliveCountMax 3
ConnectTimeout 10
Host bastion
HostName 203.0.113.10
User ops
Port 2222
IdentityFile ~/.ssh/id_rsa_bastion
IdentitiesOnly yes
Host db1
HostName 10.0.0.51
User dbadmin
ProxyJump bastion
IdentityFile ~/.ssh/id_rsa_prod
IdentitiesOnly yes
ssh bastion # 先验证跳板机本身能连
ssh db1 # 一条命令直达内网主机
ssh -G db1 # 打印最终生效配置,确认 ProxyJump 已应用
ssh -v db1 2>&1 | grep -i proxy # 观察跳板过程
# 命令行等价写法
ssh -J ops@203.0.113.10:2222 dbadmin@10.0.0.51
ssh -J bastion1,bastion2 user@target # 多级跳板
# 老版本 OpenSSH(< 7.3)用 ProxyCommand
# ProxyCommand ssh -q -W %h:%p bastion
# scp / rsync 自动复用同一配置
scp dump.sql db1:/tmp/
rsync -avzP db1:/var/lib/mysql-backup/ /backup/db1/
9. 用 scp 和 rsync 分别传输同一个目录,对比二者差异。
# 准备测试目录
mkdir -p /tmp/testdir && dd if=/dev/zero of=/tmp/testdir/big.bin bs=1M count=200
for i in $(seq 1 500); do echo "line $i" > /tmp/testdir/f$i.txt; done
# ① scp 首次传输
time scp -r /tmp/testdir 10.0.0.62:/tmp/dest-scp/
# ② scp 再传一次(内容完全没变)
time scp -r /tmp/testdir 10.0.0.62:/tmp/dest-scp/
# 观察:耗时几乎相同 → scp 每次都是全量传输
# 还会发现变成了 /tmp/dest-scp/testdir/testdir(嵌套),这是 scp 传目录的经典坑
# ③ rsync 首次传输
time rsync -avz /tmp/testdir/ 10.0.0.62:/tmp/dest-rsync/
# ④ rsync 再传一次
time rsync -avz /tmp/testdir/ 10.0.0.62:/tmp/dest-rsync/
# 观察:第二次几秒完成,输出 "sent xxx bytes",数据量极小 → 增量同步
# ⑤ 只改一个文件,再同步
echo "changed" >> /tmp/testdir/f1.txt
rsync -avz --stats /tmp/testdir/ 10.0.0.62:/tmp/dest-rsync/
# 观察 Number of regular files transferred: 1 → 只传了变化的那一个文件
# ⑥ 对比结尾斜杠差异
rsync -avn /tmp/testdir 10.0.0.62:/tmp/x/ # 预览 → /tmp/x/testdir/...
rsync -avn /tmp/testdir/ 10.0.0.62:/tmp/x/ # 预览 → /tmp/x/...
# ⑦ 验证 --delete
touch /tmp/dest-rsync-extra.txt
ssh 10.0.0.62 'touch /tmp/dest-rsync/should-be-deleted.txt'
rsync -avn --delete /tmp/testdir/ 10.0.0.62:/tmp/dest-rsync/ # 先 dry-run 看要删什么
rsync -av --delete /tmp/testdir/ 10.0.0.62:/tmp/dest-rsync/
结论:一次性拷贝用 scp,反复同步一律用 rsync。
10. 故意把 sshd_config 改错,然后用 sshd -t 定位问题。
cp -a /etc/ssh/sshd_config /etc/ssh/sshd_config.ok
# 错误 ①:拼写错误的指令
echo 'PermitRootLogins no' >> /etc/ssh/sshd_config
sshd -t
# /etc/ssh/sshd_config line 155: Unsupported option PermitRootLogins
#(新版可能提示 Bad configuration option: PermitRootLogins)
# 错误 ②:非法取值
sed -i 's/^PermitRootLogin.*/PermitRootLogin maybe/' /etc/ssh/sshd_config
sshd -t
# /etc/ssh/sshd_config line 38: Bad yes/no/without-password/forced-commands-only argument
# 错误 ③:端口不是数字
echo 'Port abcd' >> /etc/ssh/sshd_config
sshd -t
# /etc/ssh/sshd_config line 156: Badly formatted port number.
# 错误 ④:Match 块缺少条件
echo 'Match' >> /etc/ssh/sshd_config
sshd -t
# Missing Match criteria
# 错误 ⑤:主机密钥权限错误(不是语法错,sshd -t 同样能查出来)
chmod 644 /etc/ssh/ssh_host_rsa_key
sshd -t
# @@@ WARNING: UNPROTECTED PRIVATE KEY FILE! @@@ Permissions 0644 ... are too open.
chmod 600 /etc/ssh/ssh_host_rsa_key
# 恢复
cp -a /etc/ssh/sshd_config.ok /etc/ssh/sshd_config
sshd -t && echo "配置正常"
systemctl restart sshd
sshd -t 查不出来的「逻辑错误」(必须靠实际登录验证)
# ① 把自己排除在白名单外 —— sshd -t 不报错,但重启后你就进不来了
echo 'AllowUsers someone-else' >> /etc/ssh/sshd_config
sshd -t # 通过!
# ② 关掉密码认证但密钥没配好 —— sshd -t 不报错
# ③ 改了 Port 但防火墙/SELinux 没放行 —— sshd -t 不报错
# 正确流程:sshd -t 通过后,用 sshd -T 看生效值,再在新窗口实际登录验证
sshd -T | grep -Ei 'allowusers|passwordauthentication|^port|permitrootlogin'
结论:sshd -t 只检查语法与密钥文件权限,不检查逻辑。所以「保留一个已登录会话 + 新窗口验证」这两步永远不能省。
本章小结
网络配置命令速查(ip / ifconfig / nmcli 对照)
| 任务 | ip(推荐,iproute2) | ifconfig / route(net-tools,已弃用) | nmcli(NetworkManager) |
|---|---|---|---|
| 查看所有网卡 IP | ip addr / ip a |
ifconfig -a |
nmcli dev show |
| 查看指定网卡 | ip addr show ens33 |
ifconfig ens33 |
nmcli dev show ens33 |
| 只看链路状态 | ip link show |
ifconfig -a |
nmcli dev status |
| 添加 IP | ip addr add 10.0.0.5/24 dev ens33 |
ifconfig ens33 10.0.0.5/24 |
nmcli con mod X ipv4.addresses 10.0.0.5/24 |
| 删除 IP | ip addr del 10.0.0.5/24 dev ens33 |
— | nmcli con mod X -ipv4.addresses ... |
| 添加第二个 IP(别名) | ip addr add 10.0.0.6/24 dev ens33 |
ifconfig ens33:0 10.0.0.6/24 |
nmcli con mod X +ipv4.addresses 10.0.0.6/24 |
| 启用网卡 | ip link set ens33 up |
ifconfig ens33 up / ifup ens33 |
nmcli dev connect ens33 |
| 禁用网卡 | ip link set ens33 down |
ifconfig ens33 down / ifdown ens33 |
nmcli dev disconnect ens33 |
| 修改 MAC | ip link set ens33 address 00:01:22:AB:EF:CD |
ifconfig ens33 hw ether 00:01:22:AB:EF:CD |
nmcli con mod X 802-3-ethernet.cloned-mac-address ... |
| 修改 MTU | ip link set ens33 mtu 9000 |
ifconfig ens33 mtu 9000 |
nmcli con mod X 802-3-ethernet.mtu 9000 |
| 查看路由 | ip route / ip r |
route -n / netstat -rn |
nmcli con show X \| grep ipv4.route |
| 添加默认网关 | ip route add default via 10.0.0.1 |
route add default gw 10.0.0.1 |
nmcli con mod X ipv4.gateway 10.0.0.1 |
| 添加静态路由 | ip route add 172.16.0.0/16 via 10.0.0.254 |
route add -net 172.16.0.0/16 gw 10.0.0.254 |
nmcli con mod X +ipv4.routes "172.16.0.0/16 10.0.0.254" |
| 查看 ARP 表 | ip neigh / ip n |
arp -n |
— |
| 清空 ARP 缓存 | ip neigh flush all |
arp -d IP |
— |
| 查看监听端口 | ss -tnlp |
netstat -ntlup |
— |
| 查看已建立连接 | ss -tnp |
netstat -nt |
— |
| 查看统计 | ip -s link |
netstat -i |
— |
| 生效方式 | 立即生效,重启丢失 | 立即生效,重启丢失 | 写入配置文件,永久生效 |
yum -y install net-tools iproute # ifconfig/netstat 在最小化安装中需单独装
网卡配置文件参数速查
文件位置:/etc/sysconfig/network-scripts/ifcfg-<网卡名>
| 参数 | 说明 | 示例 |
|---|---|---|
DEVICE |
设备名,必须与文件名 ifcfg-xxx 后缀一致 |
DEVICE=eth0 |
NAME |
连接名称(CentOS 7+) | NAME=ens33 |
TYPE |
接口类型 | TYPE=Ethernet |
UUID |
连接唯一标识(克隆虚拟机时应删除) | UUID=xxxx-xxxx |
BOOTPROTO |
dhcp 动态 / static 或 none 静态 |
BOOTPROTO=none |
ONBOOT |
开机或重启网络时是否启用 | ONBOOT=yes |
IPADDR |
静态 IP 地址 | IPADDR=10.0.0.200 |
NETMASK |
子网掩码(与 PREFIX 二选一) | NETMASK=255.255.255.0 |
PREFIX |
掩码位数(与 NETMASK 二选一,推荐) | PREFIX=24 |
GATEWAY |
默认网关,也可写在 /etc/sysconfig/network 中对所有网卡生效 |
GATEWAY=10.0.0.1 |
DNS1 / DNS2 |
DNS 服务器,会自动写入 /etc/resolv.conf |
DNS1=223.5.5.5 |
DOMAIN |
搜索域 | DOMAIN=qianyun.com |
NM_CONTROLLED |
是否受 NetworkManager 控制,CentOS 6 服务器建议 no |
NM_CONTROLLED=no |
DEFROUTE |
是否作为默认路由出口(多网卡时用) | DEFROUTE=yes |
PEERDNS |
DHCP 时是否用服务器下发的 DNS 覆盖 resolv.conf | PEERDNS=no |
IPV6INIT |
是否启用 IPv6 | IPV6INIT=no |
HWADDR |
绑定的 MAC 地址(克隆虚拟机时常需删除或改正) | HWADDR=00:0C:29:... |
MTU |
最大传输单元 | MTU=1500 |
USERCTL |
普通用户是否可启停该网卡 | USERCTL=no |
ZONE |
firewalld 区域(CentOS 7+) | ZONE=public |
IP 别名(虚拟 IP)相关:
| 文件 | 参数 | 说明 |
|---|---|---|
ifcfg-eth0:0 |
DEVICE=eth0:0 + IPADDR |
单个别名 |
ifcfg-eth0-range0 |
IPADDR_START / IPADDR_END / NETMASK / CLONENUM_START |
批量别名,CLONENUM_START=10 表示从 eth0:10 开始编号 |
CentOS 6 与 7+ 差异对照
| 项目 | CentOS 6(RHEL 6) | CentOS 7 及以上 |
|---|---|---|
| 网卡命名 | eth0、eth1(内核顺序) |
ens33、eno1、enp0s3(一致性命名) |
| 网卡命名规则文件 | /etc/udev/rules.d/70-persistent-net.rules |
由 systemd/udev 按固件与总线位置生成 |
| 恢复传统 eth0 命名 | 默认即是 | 内核参数加 net.ifnames=0 biosdevname=0 |
| 网络服务 | network(SysV init) |
NetworkManager + network(systemd) |
| 重启网络 | service network restart/etc/init.d/network restart |
systemctl restart networknmcli con reload && nmcli con up <连接名> |
| 启停单块网卡 | ifup eth0 / ifdown eth0 |
nmcli dev connect/disconnect ens33(ifup/ifdown 仍可用) |
| 重启 sshd | service sshd restart/etc/init.d/sshd restart |
systemctl restart sshd |
| 重载 sshd 配置 | service sshd reload |
systemctl reload sshd |
| 查看 sshd 状态 | service sshd status |
systemctl status sshd |
| sshd 开机自启 | chkconfig sshd onchkconfig --list sshd |
systemctl enable sshdsystemctl is-enabled sshd |
| 启动 + 自启一步完成 | 需两条命令 | systemctl enable --now sshd |
| 查看主机名 | hostname |
hostname / hostnamectl |
| 永久改主机名 | 改 /etc/sysconfig/network 的 HOSTNAME= |
hostnamectl set-hostname xxx(写入 /etc/hostname) |
| 防火墙 | iptables(service iptables) |
firewalld(firewall-cmd) |
| 端口查看 | netstat -ntlup |
ss -tnlp(netstat 需装 net-tools) |
| 链路检测 | mii-tool、ethtool |
ethtool、ip link(mii-tool 多数已移除) |
| 日志查看 | tail /var/log/messages、/var/log/secure |
journalctl -u sshd、/var/log/secure |
| NetworkManager 处理 | 通常关掉:chkconfig NetworkManager off |
保留启用,是主要管理方式 |
| SSH 协议版本 | 需显式 Protocol 2 禁用 v1 |
已移除 v1,Protocol 指令也已废弃 |
UseDNS 默认值 |
yes(需手工改 no) |
no(OpenSSH 7.x 起) |
SSH 客户端常用选项速查
| 选项 | 作用 |
|---|---|
-p 端口 |
指定端口(小写,scp/sftp 用大写 -P) |
-l 用户 |
指定登录用户,等价于 user@host |
-i 私钥 |
指定私钥文件 |
-v / -vv / -vvv |
分级调试输出 |
-t / -tt |
强制分配伪终端(sudo、top、vim 需要) |
-T |
禁用伪终端 |
-X |
X11 转发(受限,较安全) |
-Y |
X11 信任转发(不安全,慎用) |
-J 跳板机 |
跳板机(OpenSSH 7.3+),多级用逗号分隔 |
-W host:port |
标准输入输出转发,老版本实现跳板用 |
-N |
不执行远程命令(只做端口转发时用) |
-f |
后台运行 |
-L 本地端口:目标:目标端口 |
本地端口转发 |
-R 远程端口:目标:目标端口 |
远程端口转发 |
-D 端口 |
动态转发(SOCKS 代理) |
-C |
压缩 |
-q |
静默模式 |
-o 选项=值 |
传递任意配置项 |
-G |
打印某主机最终生效的配置(排错神器) |
常用 -o |
ConnectTimeout=5、StrictHostKeyChecking=accept-new、BatchMode=yes、IdentitiesOnly=yes、ServerAliveInterval=60、UserKnownHostsFile=/dev/null |
sshd_config 关键项速查
| 配置项 | 默认 | 建议值 | 说明 |
|---|---|---|---|
Port |
22 | 高位端口 | 改端口需同步 SELinux + 防火墙 |
ListenAddress |
0.0.0.0 | 内网地址 | 多网卡时只在内网口开放 |
Protocol |
2 | 2 | 仅 CentOS 6 需写 |
PermitRootLogin |
yes | no | 或 prohibit-password(仅密钥) |
PasswordAuthentication |
yes | no(密钥配好后) | 关闭前必须验证密钥可用 |
PubkeyAuthentication |
yes | yes | 公钥认证开关 |
AuthorizedKeysFile |
.ssh/authorized_keys |
默认 | 公钥存放位置 |
PermitEmptyPasswords |
no | no | 绝不能开 |
MaxAuthTries |
6 | 3 | 单连接失败次数上限 |
LoginGraceTime |
120 | 30~60 | 认证超时(秒) |
ClientAliveInterval |
0 | 按需 | 探测间隔 |
ClientAliveCountMax |
3 | 按需 | 超时 = 间隔 × 次数 |
UseDNS |
no(新版) | no | yes 会导致登录卡十几秒 |
GSSAPIAuthentication |
yes | no | 同样是登录慢的元凶 |
AllowUsers / AllowGroups |
无 | 按需白名单 | 写错会锁死自己 |
DenyUsers / DenyGroups |
无 | 按需黑名单 | 优先级高于 Allow |
Banner |
none | 按合规要求 | 认证前的警告语 |
X11Forwarding |
no(RHEL 默认 yes) | 无图形需求设 no | 配合客户端 -X |
AllowTcpForwarding |
yes | 按需 no | 防被当跳板穿透内网 |
Subsystem sftp |
启用 | 保留 | 注释掉则 sftp 不可用 |
LogLevel |
INFO | INFO(排错 VERBOSE) | VERBOSE 会记录密钥指纹 |
StrictModes |
yes | yes | 权限过松即拒绝认证 |
SSH 加固清单
- 改默认端口 —— 作用有限(
nmap一扫就找到),但能挡掉绝大多数只扫 22 的自动化脚本,让日志清爽、真实告警不被淹没。改端口三件套:sshd_config+semanage port+firewall-cmd。 - 禁用 root 直接登录 ——
PermitRootLogin no,改用普通用户 +sudo。顺序:先建用户 → 验证能登录 → 验证 sudo 可用 → 才禁 root。 - 优先密钥认证,关闭密码认证 ——
PubkeyAuthentication yes+PasswordAuthentication no+ChallengeResponseAuthentication no。关闭前必须先验证密钥能登录。 - 限制来源与用户 ——
AllowUsers deploy@192.168.0.*、AllowGroups sshusers,或在防火墙层面用 rich-rule 只放行运维网段。 - 防暴力破解 ——
MaxAuthTries 3+LoginGraceTime 30+ fail2ban(maxretry/findtime/bantime,记得ignoreip加上自己的网段)。 - 审计暴力破解来源 ——
grep 'Failed password' /var/log/secure | awk '{print $11}' | sort | uniq -c | sort -rn;ss -tnp | grep :22;lastb、last、lastlog。 - 权限必须正确 ——
~不能组/其他可写,~/.ssh700,authorized_keys600,私钥 600,属主是本人;SELinux 上下文用restorecon -Rv ~/.ssh修。这是Permission denied (publickey)的头号原因。 - 关闭无用功能 ——
X11Forwarding no、AllowTcpForwarding no、PermitTunnel no、PermitEmptyPasswords no。 - 性能与体验 ——
UseDNS no+GSSAPIAuthentication no,消除登录卡顿。 - 改配置的铁律 —— 备份 → 改 →
sshd -t语法检查 →sshd -T看生效值 →reload/restart→ 在新窗口实际登录验证,全程保留一个已登录会话。sshd -t查不出逻辑错误(白名单漏了自己、端口没放行、密钥没配好)。
排错口诀
分层排查(自下而上五层)
先看灯,再通 IP,再探端口,再查服务,最后查认证。
链路(
ethtool/ip link)→ IP 路由(ping/ip route)→ 端口(nc -zv/ss -tnlp)→ 服务(systemctl status sshd/sshd -t)→ 认证(/var/log/secure/ssh -v)
四种连接失败报错
refused 找服务,timeout 找防火墙,no route 找路由,denied 找认证。
SSH 高频问题一句话对症
| 症状 | 一句话原因 |
|---|---|
| 登录卡十几秒 | UseDNS + GSSAPIAuthentication 都设 no |
Permission denied (publickey) |
九成是权限:.ssh 700、authorized_keys 600、家目录不可组写 |
HOST IDENTIFICATION HAS CHANGED |
ssh-keygen -R 主机,别删整个 known_hosts |
Too many authentication failures |
-o IdentitiesOnly=yes 或 ssh-add -D |
| 用一会儿就断 | ClientAliveInterval(服务端)/ ServerAliveInterval(客户端)/ TMOUT(Shell)三处查 |
Connection reset by peer |
fail2ban 封了、hosts.deny、/var 满、算法不兼容 |
sudo: no tty present |
ssh -t |
scp 报 not a regular file |
传目录忘了 -r |
| scp 端口连不上 | -P 是大写 |
| rsync 目录多出一层 | 源路径结尾斜杠:带 / = 传内容,不带 = 传目录本身 |
--delete 之前 |
一律先 -n dry-run |
| 改完 sshd 进不去了 | 永远保留一个已登录会话;sshd -t 不查逻辑错误 |
四条要点回顾
- IP 配置区分临时(
ip addr/ifconfig,重启丢失)与永久(ifcfg-xxx文件 + 重启网络 /nmcli)。 ss -tnlp(新)/netstat -ntlup(旧)是排查端口监听的核心命令。- SSH 连不上主要两类:密钥变更(清
known_hosts单行)和服务未启动(起sshd并enable)。 /etc/hosts优先于 DNS 解析(由/etc/nsswitch.conf的hosts: files dns决定),多主机环境应统一规划主机名绑定,规模上百台后改用内部 DNS。
此处评论已关闭