☰
Linux网卡配置全解:nmcli命令与ifcfg文件双路线实战
2026/10/21 22:49:54 网站建设 项目流程

给服务器配网卡这件事,看着简单,翻车的人一点都不少。我经常遇到的情况是:机器在机房,手边只有一条SSH通道,网卡参数一时半会儿对不上,网络直接断掉,整个人只能对着控制台干瞪眼。这种场景下,nmcli是救命的工具,而/etc/sysconfig/network-scripts/ 下的 ifcfg 网卡配置文件则是理解一切网络管理行为的根基。这篇文章就把两条配置路径完整讲一遍:NetworkManager 自带的命令行工具 nmcli,以及手工编辑网卡配置文件的全过程,最后附上一份可以直接套用的配置脚本。适合刚入门运维的朋友、经常搭测试环境的人,以及正准备规划批量网卡配置脚本的同学。

1. 为什么网络配置要同时掌握两条路线:nmcli与ifcfg的互补关系

1.1 一次救场的经历:命令行是最后一道保命手段

先说一个我自己的经历。有一回接手一台新到的服务器,系统装好之后,发现管理网卡没有自动获取到地址。整个机房没有图形界面可用,唯一能操作的是机器上的物理控制台。这种情况下,想打开图形化的网络设置工具是痴人说梦,唯一能快速把网络拉起来的办法,就是敲命令。

当时我先用nmcli device status看了一眼网卡状态,再用nmcli connection add临时建了一个静态IP连接,网络通了,后面才有余力慢慢核对网卡配置。但如果你只会 nmcli,会陷入另一个麻烦:批量部署几十台机器时,难道要一台一台手敲 nmcli 命令?这时候直接生成规范、统一的 ifcfg 配置文件再批量下发,效率高出一个量级。

所以这两条路线不是二选一,而是互相补位的。nmcli 适合现场快速操作,ifcfg 文件适合做基线管理、模板复用和脚本批量处理。真正干过运维的人都知道,两条腿走路才稳。

1.2 nmcli适合什么场景,手写文件又适合什么场景

拿日常场景来划分:临时调个IP、测试一下新网段通不通、快速看当前连接状态,这些用 nmcli 最方便。它自带的输出格式化、自动补全和对象化管理,让单台机器的操作成本极低。尤其是nmcli connection modify这种命令,改完立刻生效,还顺手把配置写回文件,省去手工编辑和重载的步骤。

手写 ifcfg 文件的场景则更偏向"工程化"。比如给新环境做标准化镜像,要求所有网卡配置文件格式统一、字段齐全;或者要做自动化脚本,准备在装机后自动生成配置,这时候如果不懂文件结构,脚本根本写不出来。还有一类情况是故障排查:nmcli 显示的参数终究是读取配置文件之后的结果,很多诡异问题,最后都要打开 ifcfg 文件才能找到根因。

一句话总结:nmcli 负责"快速改变现状",ifcfg 文件负责"定义稳定状态"。理解了这层关系,后面学的所有命令和字段都有落点。

2. nmcli从查看到配置:命令对象与实操链路

2.1 device和connection不是一回事

很多新手一上来就懵,因为 nmcli 里有两个高频词:device 和 connection。这俩不是同一层概念。device 是物理网卡,比如 eth0、ens33;connection 是保存在这个网卡上的一套配置方案,包括IP、网关、DNS、自动连接开关等等。一个网卡上可以挂多套 connection,比如一套DHCP方案、一套静态IP方案,但同一时刻只有一个 connection 处于 active 状态。

你可以把 device 理解成墙上的插座,connection 则是插在上面的各种电器。插座始终在那,你只需要切换插哪个电器。

区分清楚后,命令就很好理解了。nmcli device status看的是网卡设备状态,nmcli connection show看的是所有配置方案,nmcli connection show --active看的是当前正在生效的方案。实际工作中,我养成一个习惯:凡是涉及"改配置"的操作,一律在 connection 层面做;凡是涉及"查状态"的操作,device 和 connection 两个命令结合着看。

2.2 静态IP配置的完整命令链

给一块网卡配置静态IP,最稳妥的命令顺序是先新建一个 connection,再激活它,而不是直接在原来那个连接上改。原因很实际:原连接可能是系统装好时自动生成的,带有各种默认行为,改成静态IP时一个参数没写全,反而会把原有配置搞得更乱。新建一个命名清晰的连接,出问题可以随时切回去。

一条完整的命令链大致是这样:

# 创建名为 eth0-static 的以太网连接,绑定 eth0 网卡 nmcli connection add type ethernet con-name eth0-static ifname eth0 \ ipv4.method manual \ ipv4.addresses 192.168.100.10/24 \ ipv4.gateway 192.168.100.1 \ ipv4.dns "10.10.10.2 10.10.10.3" # 激活这个连接 nmcli connection up eth0-static

这里有一个关键点:ipv4.method manual必须显式写出来。如果不写,新建的连接可能默认还是 DHCP 或自动协商方式,后面即便填了 IP 地址,系统也不会乖乖用它。写完之后,可以顺手验证一下:

ip -4 addr show eth0 ip route

实际修改已有连接时,用的则是nmcli connection modify,写法和 add 差不多。比如把 DNS 改掉、把自动连接打开:

nmcli connection modify eth0-static ipv4.dns "10.10.10.4 10.10.10.5" nmcli connection modify eth0-static autoconnect yes nmcli connection up eth0-static

需要特别说明的是,nmcli connection modify在连接处于 active 状态时,通常会把改动直接应用到当前网络配置,而不是只改文件等重启。这就是它比手改文件"快"的原因。

2.3 排障时最高频的查询命令

配置做完不等于万事大吉,查询命令在排障时才是主角。我实际用得最多的几组命令,基本覆盖了 90% 的网卡状态判断需求:

# 查看设备整体状态 nmcli device status # 查看某个网卡当前生效的具体配置 nmcli device show eth0 # 查看连接列表(含非活动连接) nmcli connection show # 只看关键字段,脚本里也方便解析 nmcli -t -f NAME,DEVICE,TYPE connection show

其中-t是 terse 模式,输出不含多余表头,纯字段内容,适合写脚本时 grep 或 awk;-f是指定字段。比如我想知道所有活动连接的名字和对应网卡,一条命令搞定:

nmcli -t -f NAME,DEVICE connection show --active

还有一个容易忽略的命令是nmcli general status,它能看到 NetworkManager 整体运行状态、网络是否被全局禁用。有次机器上不了网,我查了半天网卡配置,最后发现是 NetworkManager 被整体停用了,nmcli general status一看便知。这类全局状态,平时排障必须排在第一步。

3. ifcfg配置文件逐字段拆解与手工修改全流程

3.1 最小可用的静态IP配置文件长什么样

以 RHEL 系发行版为例,网卡配置文件集中在/etc/sysconfig/network-scripts/,命名规则通常是ifcfg-网卡名,比如ifcfg-eth0。一个最小可用的静态IP配置,大概是这个模样:

DEVICE=eth0 NAME=eth0-static TYPE=Ethernet UUID=xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx ONBOOT=yes BOOTPROTO=none IPADDR=192.168.100.10 PREFIX=24 GATEWAY=192.168.100.1 DNS1=10.10.10.2 DNS2=10.10.10.3

注意这里的写法差别:在 nmcli 里,IP地址写成192.168.100.10/24这种 CIDR 格式,但在 ifcfg 文件里,必须拆成IPADDR=192.168.100.10和PREFIX=24两个字段。很多人直接写IPADDR=192.168.100.10/24,结果是地址根本不被识别。这个坑特别常见,我见过身边同事在这上面耗过小半天。

另外,BOOTPROTO=none表示不使用任何动态地址协商协议,纯手工指定地址。有的发行版也接受BOOTPROTO=manual,效果等同,但写成none更通用。DHCP 环境的机器,这个字段要写成dhcp,并删掉 IPADDR/GATEWAY 等字段。

3.2 关键字段的作用与容易出现的问题

ifcfg 文件里的字段不少,但真正高频接触的就那么十来个,我把它们分成几类说明。

连接识别类字段包括 DEVICE、NAME、UUID、TYPE。DEVICE 对应物理网卡名,NAME 是连接名,UUID 是连接的唯一标识。三个字段必须配合正确。有个容易出的问题:复制别人的配置文件时,DEVICE 忘了改,导致新配置挂到了错误的网卡上;或者 UUID 和现有连接冲突,NetworkManager 加载时出现奇怪行为。复制文件后第一件事,就是用uuidgen生成新 UUID 改掉,这个习惯能帮你躲掉很多莫名其妙的故障。

地址类字段是 IPADDR、PREFIX、GATEWAY。如果网段是传统分类掩码,也可以写NETMASK=255.255.255.0,但现代系统更推荐 PREFIX,两者写一个就行,两个都写时以 PREFIX 为准。

DNS与行为类字段同样关键。DNS1/DNS2 是首选和备选 DNS;ONBOOT=yes 表示开机激活该连接;DEFROUTE=yes 表示把该连接上的网关写入默认路由。多网卡机器尤其要小心 DEFROUTE:两块网卡都配了网关,默认路由就会冲突,流量往哪走全看路由表顺序,结果往往不稳定。至于 NM_CONTROLLED 这个字段,建议保持yes,让 NetworkManager 统一管理,否则可能出现"设备在、但连接不受管"的尴尬状态。

3.3 手工修改之后如何安全生效

手工改了文件,不能直接重启机器,也不能简单跑systemctl restart network就完事。正确的生效路径依赖 NetworkManager 的重载机制:

# 让 NetworkManager 重新读取配置文件 nmcli connection reload # 激活对应连接 nmcli connection up eth0-static

reload负责把磁盘上的新配置读进 NetworkManager 缓存,up让配置正式生效。很多新手漏掉 reload,直接 up,发现 nmcli 里看到的还是旧内容,其实不是文件没改对,而是缓存没刷新。

这里还要提醒一个高风险点:如果修改的是当前正在使用的网卡,nmcli connection up执行后可能瞬间断网,SSH 会话随之断开。所以在生产机器上操作,我强烈建议先确认有没有带外管理通道,或者在变更前准备一条延时回滚命令。资深的做法是:把旧配置备份好,变更失败时能在几分钟内恢复,而不是握着断开的 SSH 窗口束手无策。

4. 两条配置路线混用时的常见坑与完整排查链路

4.1 改完文件NM不认:缓存与reload时序

一次真实的排查过程是这样。同事新加了一个 ifcfg 文件,nmcli connection show里怎么都看不到,他在文件边上反复确认格式,还对照别的机器复制粘贴,依然无效。我看了一眼他的操作流程:他编辑文件后直接执行了nmcli connection up 新连接名,但 NetworkManager 此时完全不知道这个文件的存在。

问题就出在时序上。NetworkManager 启动时扫描一次配置文件目录,运行期间不会每秒盯着目录看。手动添加的文件,必须用nmcli connection reload通知它重新扫描。这时再看nmcli connection show,新连接才出现。所以正确顺序一定是:先改文件、再 reload、最后 up。缺少 reload 这一步,后续所有操作都会对着不存在的缓存操作,自然报错。

我在多次踩坑之后归纳了一条检查链路:先nmcli device status确认网卡内核态可见,再nmcli connection show确认配置文件有没有被 NetworkManager 加载,最后用ip addr核对实际生效地址。三步走完,九成问题都能定位到具体环节。

4.2 复制配置文件忘记改UUID导致连接状态诡异

另一个高频坑来自"复用配置文件"。为了省事,有人喜欢把一台机器的 ifcfg-eth0 直接 scp 到另一台机器,改个 IP 就完事。结果新机器上nmcli connection show里出现了两条一模一样的连接,或者旧的连接突然失联。

根因十有八九是 UUID 重复。UUID 在 NetworkManager 内部是连接的主键,两个文件共享同一个 UUID,系统无法区分它们。很多衍生问题也因此变得诡异:配置没错、文件没错,但状态怎么都对不上。

所以我处理这类任务时,有个固定动作:复制文件后立即执行uuidgen并替换 UUID,同时检查 DEVICE、NAME 是否匹配目标机器。脚本化批量部署时,每个节点的配置文件都要动态生成 UUID,绝不能直接复用模板里的固定值。顺便说一句,模板里可以用变量占位,由脚本在部署时把变量替换成新生成的 UUID,这样既保证了格式统一,又避免了主键冲突。

4.3 DNS被覆盖和默认路由冲突的根因

配置层面还有一个隐蔽问题,表现为"IP 通了但 DNS 解析总是不对"。我之前遇到一台机器,明明 /etc/resolv.conf 里写的是内网 DNS,隔一段时间就被改回别的地址。打开 ifcfg 文件一看,原来少了PEERDNS=no这个字段。DHCP 环境下,客户端默认会从 DHCP 服务器获取 DNS 并覆盖本地配置,PEERDNS=no就是阻止这种行为。

至于默认路由冲突,表现更为直接。双网卡机器,每块网卡各自配了 GATEWAY,默认路由被多次写入,实际上只有一条能生效,另一条链路就成了"能通但没流量走"的摆设。解决办法是让其中一块网卡承担默认路由,另一块只做内网通信,在 ifcfg 文件中通过 DEFROUTE=no 关闭非核心网卡的默认路由,或者给两条路由设置不同的 metric 权重。

排查这类问题时,不用急着改文件,先执行ip route看当前默认路由指向,再对照 ifcfg 文件确认哪个 GATEWAY 参与了默认路由生成,基本一眼定位。

5. 可套用的网卡配置脚本参考

5.1 脚本要解决什么问题

到这一步,我把日常经验收敛成一个可以直接使用的脚本。这个脚本解决的核心问题就是:一台新机器装好系统后,如何用一条命令、一套参数,快速生成规范的静态IP配置,并完成生效和验证。它的设计目标有三个:参数化、安全备份、结果可验证。

所谓参数化,就是网卡名、IP地址、网关、DNS全部通过命令行参数传入,不需要打开文件手动改。所谓安全备份,是脚本执行前自动把当前配置文件目录压缩备份,给变更上一道保险。所谓结果可验证,是脚本最后会自动显示 IP 地址和路由信息,让你立刻判断配置是否正确生效。

5.2 完整脚本

把下面的内容保存为configure-nic.sh,加执行权限后就能用。

#!/usr/bin/env bash # # 网卡静态IP配置脚本 # 用法: # ./configure-nic.sh -i eth0 -a 192.168.100.10 -p 24 \ # -g 192.168.100.1 -d "10.10.10.2 10.10.10.3" # # -i 网卡名 -a IP地址 -p 前缀长度 # -g 网关 -d DNS服务器(多个用空格隔开) # set -euo pipefail CONN_NAME="" DEVICE_NAME="" IP_ADDR="" PREFIX_LEN="" GATEWAY_IP="" DNS_SERVERS="" BACKUP_DIR="/root/nic-backup-$(date +%Y%m%d%H%M%S)" usage() { cat <<'EOF' 用法: configure-nic.sh -i <网卡名> -a <IP> -p <前缀> [-g <网关>] [-d <DNS>] EOF exit 1 } while getopts "c:i:a:p:g:d:h" opt; do case "$opt" in c) CONN_NAME="$OPTARG" ;; i) DEVICE_NAME="$OPTARG" ;; a) IP_ADDR="$OPTARG" ;; p) PREFIX_LEN="$OPTARG" ;; g) GATEWAY_IP="$OPTARG" ;; d) DNS_SERVERS="$OPTARG" ;; h) usage ;; *) usage ;; esac done # 参数校验:网卡名、IP、前缀是必填项 [ -n "$DEVICE_NAME" ] || usage [ -n "$IP_ADDR" ] || usage [ -n "$PREFIX_LEN" ] || usage # 必须用root执行,否则写不了配置文件 if [ "$EUID" -ne 0 ]; then echo "请使用root用户执行该脚本" exit 1 fi # 备份当前全部网卡配置文件 mkdir -p "$BACKUP_DIR" cp -a /etc/sysconfig/network-scripts/ifcfg-* "$BACKUP_DIR"/ 2>/dev/null || true echo "配置文件已备份到: $BACKUP_DIR" # 如果未指定连接名,默认使用 ethX-static 的命名方式 if [ -z "$CONN_NAME" ]; then CONN_NAME="${DEVICE_NAME}-static" fi # 为连接生成唯一UUID NIC_UUID=$(uuidgen) # 处理DNS,支持最多4个DNS服务器 DNS_LINES="" if [ -n "$DNS_SERVERS" ]; then idx=1 for dns in $DNS_SERVERS; do [ "$idx" -gt 4 ] && break DNS_LINES="${DNS_LINES}DNS${idx}=${dns}"$'\n' idx=$((idx + 1)) done fi # 写入配置文件 CONF_FILE="/etc/sysconfig/network-scripts/ifcfg-${DEVICE_NAME}" cat > "$CONF_FILE" <<EOF DEVICE=${DEVICE_NAME} NAME=${CONN_NAME} TYPE=Ethernet UUID=${NIC_UUID} ONBOOT=yes BOOTPROTO=none IPADDR=${IP_ADDR} PREFIX=${PREFIX_LEN} EOF # 网关和DNS只有在传入时才写入 if [ -n "$GATEWAY_IP" ]; then cat >> "$CONF_FILE" <<EOF GATEWAY=${GATEWAY_IP} DEFROUTE=yes EOF fi if [ -n "$DNS_LINES" ]; then cat >> "$CONF_FILE" <<EOF ${DNS_LINES}PEERDNS=no EOF fi echo "配置已写入: $CONF_FILE" cat "$CONF_FILE" # 让NetworkManager重新读取配置并激活 nmcli connection reload nmcli connection up "$CONN_NAME" # 验证结果 echo "---- 当前IP地址 ----" ip -4 addr show "$DEVICE_NAME" echo "---- 当前路由 ----" ip route

5.3 脚本流程解读

脚本虽然不长,但每一段都有实际用途。备份动作放在最前面,因为配置变更最容易出现"改坏了却回不去"的情况,自动备份能让你少长很多记性。UUID 用uuidgen生成,每次执行都是全新主键,避免复制模板导致的主键冲突。

DNS 处理那块,先用循环把传入的多个DNS拆成 DNS1、DNS2 这样的独立行,再追加PEERDNS=no,保证后续DHCP不会覆盖手工指定的DNS。配置文件写入主体后,网关字段和DNS字段用追加方式写入,这样做的好处是:不带-g或-d参数时,文件里不会留下一堆空字段,保持配置尽量干净。

最后nmcli connection reload和nmcli connection up顺序不能颠倒,这是前面反复强调过的时序问题。验证部分把 IP 地址和路由表直接打印出来,不用再额外敲命令。

6. 实测经验小结与高频问题速查

6.1 我习惯的变更前检查清单

配置网卡踩过的坑多了以后,我给自己立了几条规矩,这里一并分享。

第一条,永远先备份。不管是手改文件还是跑脚本,改之前花十秒钟备份整个 network-scripts 目录,成本极低,收益极高。第二条,变更前确认带外通道。如果当前网卡是 SSH 连接在用的,改 IP 前务必确认有控制台或带外管理可用,否则配置一失效,你可能连恢复的机会都没有。第三条,一个网卡只用一种管理方式。要么完全交给 NetworkManager,用 nmcli 管;要么在 ifcfg 文件中保持 NM_CONTROLLED=yes。很多"灵异问题"其实就是 nmcli 改完、又手动改文件,两边覆盖来覆盖去导致的。

6.2 高频问题速查表

现象可能原因处理思路
改完ifcfg文件 nmcli 看不到新连接未执行 reload,NetworkManager 还在用旧缓存执行nmcli connection reload后重试
新配置执行 up 后网卡地址没变BOOTPROTO 仍是 dhcp,或 method 未设为 manual把 BOOTPROTO 改为 none 并确保字段完整
复制其他机器的配置后状态诡异UUID 冲突或 DEVICE 未改uuidgen生成新UUID,核对DEVICE和NAME
静态IP配好了,DNS解析总被改DHCP 客户端覆盖了 resolv.conf在配置文件中添加PEERDNS=no
双网卡都配了网关,默认路由总错多块网卡的 GATEWAY 竞争默认路由非核心网卡设置 DEFROUTE=no 或调整路由 metric
网卡显示设备存在,但无连接管理NM_CONTROLLED=no 或 NetworkManager 未接管该设备设置 NM_CONTROLLED=yes 后重载配置

最后再分享一个小经验:如果你和我一样要经常跟网络配置打交道,建议在测试环境里把 nmcli 的常用命令反复敲熟,再故意制造几个小故障练手——改错网关、把 DNS 指向一个不存在的地址、把两个连接设为同 IP,然后靠命令排查出问题。整个流程跑一遍之后,你对两张配置路线的理解会通透很多,遇到真实故障时心态也稳得多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询