尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Ubuntu 20.04 DNS配置持久化:解决systemd-resolved自动重置问题

Ubuntu 20.04 DNS配置持久化:解决systemd-resolved自动重置问题 1. 问题现象与根源剖析如果你在Ubuntu 20.04上手动修改了DNS设置比如编辑了/etc/resolv.conf文件或者通过nmcli、netplan等工具配置了静态DNS但重启网络服务、重启系统甚至只是等上一段时间后发现DNS又变回了原来的样子——最常见的是被重置为127.0.0.53指向本地的systemd-resolved服务那么恭喜你你遇到了一个非常典型的“现代Linux网络管理”问题。这绝不是你的操作有误而是Ubuntu 20.04默认的网络管理架构在背后“自作主张”。很多从老版本迁移过来或者习惯了传统/etc/network/interfaces配置方式的朋友第一次遇到这个问题时都会感到困惑和恼火。简单来说问题的核心在于“管理权冲突”。在Ubuntu 20.04中DNS的解析权默认被一个名为systemd-resolved的系统服务牢牢掌控。这个服务设计了一套自己的配置逻辑和优先级它会监听并管理/etc/resolv.conf这个文件。你手动修改这个文件就像在一个被自动同步的云文档里直接打字保存后很快就会被系统进程覆盖回去。因此理解systemd-resolved的工作机制是解决这个问题的唯一钥匙。这个问题的普遍性从你提供的那些热搜词就能看出来“linux修改dns后重启网络还原”、“dns永久生效”、“ubuntu20.04安装后没有wifi”网络问题常伴随DNS异常等等。无论是为了获得更快的解析速度如使用114.114.114.114或8.8.8.8还是为了内网开发需要指定特定的DNS服务器比如解析内部域名亦或是为了解决某些网站访问异常的问题我们都需要一个稳定、持久的DNS配置方案。注意在开始任何操作前请先确认你的网络连接方式。是通过NetworkManager管理的无线/有线连接还是通过netplan配置的静态网络常见于服务器亦或是古老的/etc/network/interfaces不同的管理工具其“正确”的配置姿势也略有不同但最终大多需要与systemd-resolved“打好招呼”。2. 理解幕后主角systemd-resolved 服务要解决问题必须先了解“对手”。systemd-resolved是systemd项目的一部分它提供了一个本地DNS解析器主要目的是为了提升DNS解析的可靠性、安全性和性能如支持DNSSEC、DNS-over-TLS等。在Ubuntu 20.04上它是默认启用并处于活跃状态的。它的工作模式主要有三种可以通过/etc/systemd/resolved.conf文件中的DNSStubListener选项来控制整合模式Integration Mode默认模式。systemd-resolved会生成一个临时的/etc/resolv.conf文件并将其软链接或直接覆盖到标准的/etc/resolv.conf位置。这个临时文件里通常只有一行nameserver 127.0.0.53。所有应用程序的DNS查询都会先发往本地的53端口由systemd-resolved统一处理它再根据其内部配置向上游DNS服务器发起查询。转发模式Forwarding Modesystemd-resolved仍然运行但/etc/resolv.conf指向真实的上游DNS服务器。此时systemd-resolved可能只负责缓存或处理特定类型的查询。禁用模式Disabled Mode完全停用systemd-resolved的本地解析功能/etc/resolv.conf由其他网络管理工具完全控制。我们遇到的“自动重置”问题绝大多数发生在整合模式下。因为在此模式下/etc/resolv.conf被systemd-resolved视为一个由其管理的“符号链接”或“动态文件”。你直接修改它相当于破坏了它的管理规则它会在下次网络状态变更如重启systemd-resolved服务、NetworkManager重连时依据其内部状态重新生成该文件。那么systemd-resolved的“内部状态”从哪里来主要来自以下几个地方按优先级从高到低排列每个链接Per-Link的DNS配置这是最推荐的方式。通过NetworkManager或netplan为特定的网络接口如eth0,wlan0配置DNS。systemd-resolved会汇总所有活跃接口的DNS设置。全局DNS配置在/etc/systemd/resolved.conf中设置的DNS参数。从DHCP获取的DNS如果你的网络是通过DHCP获取IP的那么DHCP服务器下发的DNS地址也会被systemd-resolved接收。所以我们的目标不是去“打败”systemd-resolved而是学会如何“正确地告诉”它我们想要的DNS服务器是什么。3. 解决方案一通过 Netplan 配置静态DNS服务器/桌面版通用对于Ubuntu 20.04服务器版或者桌面版中使用了netplan进行网络配置的情况默认的服务器安装和某些云镜像常用这是最官方、最持久的方法。netplan是Ubuntu 17.10以后引入的新的网络配置抽象层它负责将简洁的YAML配置在后台渲染成systemd-networkd或NetworkManager所能理解的配置。3.1 定位并编辑 Netplan 配置文件首先找到你的Netplan配置文件。它们通常位于/etc/netplan/目录下文件名可能是01-netcfg.yaml、50-cloud-init.yaml或00-installer-config.yaml等。sudo ls -lh /etc/netplan/使用你喜欢的文本编辑器如nano或vim打开它。这里以nano为例假设文件是00-installer-config.yamlsudo nano /etc/netplan/00-installer-config.yaml3.2 配置DNS参数在配置文件中你需要为对应的网络接口如ens33,eth0添加nameservers字段。下面是一个配置静态IP和DNS的完整示例network: version: 2 ethernets: ens33: # 你的网卡名称请用 ip a 命令查看 addresses: - 192.168.1.100/24 # 静态IP地址和子网掩码 routes: - to: default via: 192.168.1.1 # 默认网关 nameservers: addresses: - 8.8.8.8 # 首选DNS - 8.8.4.4 # 备用DNS - 114.114.114.114 # 另一个备用DNS search: [localdomain] # 可选的搜索域如果你使用的是DHCP获取IP但想使用自定义DNS可以这样配置network: version: 2 ethernets: ens33: dhcp4: yes # 使用DHCP获取IP nameservers: addresses: - 8.8.8.8 - 8.8.4.4关键点解释nameservers下的addresses列表顺序即DNS查询的优先级。即使使用DHCP在这里指定nameservers后netplan也会在生成配置时指示底层的网络管理器systemd-networkd或NetworkManager忽略DHCP下发的DNS而采用此处定义的DNS。这是实现“持久化”的关键。3.3 应用配置编辑保存后使用以下命令测试配置语法并应用# 测试配置文件语法是否正确非常重要避免错误配置导致断网 sudo netplan try # 如果上一条命令执行成功并确认或者直接应用配置在可远程管理的服务器上慎用可能导致连接中断 sudo netplan apply执行netplan apply后它会重新配置网络并将DNS信息传递给systemd-resolved。此时你可以检查/etc/resolv.conf它应该仍然指向127.0.0.53但通过systemd-resolve --status命令可以看到上游DNS已经变成了你设置的值。实操心得在物理服务器或远程VPS上操作时强烈建议先使用sudo netplan try。这个命令会应用新配置并给你一个回滚的倒计时默认120秒。如果在倒计时内你失去了网络连接比如配置写错了网关没有在终端按回车确认配置会在倒计时结束后自动回滚到之前的状态这是救命的功能。在本地虚拟机或不怕断网的机器上可以直接用apply。4. 解决方案二通过 NetworkManager 配置桌面版图形界面/Cli对于Ubuntu 20.04桌面版图形界面通常使用NetworkManager来管理网络。通过GUI或命令行nmcli来配置效果与netplan类似都是设置“每链接DNS”能被systemd-resolved正确识别。4.1 图形界面配置这是最直观的方法点击屏幕右上角的网络图标选择“有线设置”或“Wi-Fi设置”。在弹出的设置窗口中找到你当前连接的网络点击旁边的齿轮图标。切换到“IPv4”或“IPv6”标签页。如果你的IP是自动获取DHCP将“自动(DHCP)”切换为“手动”。在“DNS”输入框中输入你想要的DNS服务器地址多个DNS用逗号分隔例如8.8.8.8, 114.114.114.114。点击“应用”。NetworkManager会将这个配置写入其自身的配置数据库中并在该网络连接激活时将此DNS信息推送给systemd-resolved。4.2 命令行配置nmcli如果你更喜欢命令行或者需要在脚本中操作nmcli工具非常强大。首先列出所有连接找到你要修改的连接名称CONNECTION列nmcli connection show假设你的连接名是“有线连接 1”你想设置DNS为8.8.8.8和1.1.1.1并同时配置静态IP可选# 修改IPv4的DNS服务器如果使用DHCP获取IP这个方法同样有效且持久 sudo nmcli connection mod 有线连接 1 ipv4.dns 8.8.8.8 1.1.1.1 # 如果你希望完全忽略DHCP下发的DNS只使用你设置的DNS sudo nmcli connection mod 有线连接 1 ipv4.ignore-auto-dns yes # 如果需要同时设置静态IP、网关和DNS sudo nmcli connection mod 有线连接 1 ipv4.method manual ipv4.addresses 192.168.1.100/24 ipv4.gateway 192.168.1.1 ipv4.dns 8.8.8.8 1.1.1.1 # 让配置立即生效重新激活连接 sudo nmcli connection down 有线连接 1 sudo nmcli connection up 有线连接 1 # 或者使用 reload 命令 sudo nmcli connection reload sudo nmcli connection up 有线连接 1关键参数解释ipv4.dns设置DNS服务器地址列表用空格分隔。ipv4.ignore-auto-dns设为yes后NetworkManager将不会使用从DHCP获取的DNS信息这对于强制使用自定义DNS非常有用。修改后必须重启down/up网络连接或重新加载配置更改才会生效。配置完成后可以通过以下命令验证systemd-resolved接收到的DNSsystemd-resolve --status | grep -A5 DNS Servers5. 解决方案三直接配置 systemd-resolved 全局DNS如果你希望为所有网络连接设置一个统一的、后备的DNS而不是针对每个连接单独设置可以修改systemd-resolved的全局配置文件。这个方法简单粗暴但优先级低于“每链接”配置。编辑/etc/systemd/resolved.conf文件sudo nano /etc/systemd/resolved.conf找到[Resolve]部分取消DNS和FallbackDNS行的注释删除行首的#并填入你想要的DNS服务器地址。FallbackDNS是在DNS服务器不可用时的备用选择。[Resolve] DNS8.8.8.8 114.114.114.114 FallbackDNS1.1.1.1 9.9.9.9 #Domains #DNSSECno #DNSOverTLSno #Cacheyes #DNSStubListeneryes保存文件后重启systemd-resolved服务使配置生效sudo systemctl restart systemd-resolved然后检查解析状态systemd-resolve --status在输出中你应该能看到在“Global”部分下有你设置的DNS服务器。注意事项这种方法设置的DNS是全局性的。如果某个网络连接通过NetworkManager或netplan配置了特定的DNS每链接DNS那么该连接的DNS将以每链接配置为准全局配置将不生效。这可以理解为一个“默认值”。6. 解决方案四禁用 systemd-resolved传统方法不推荐如果你实在无法适应systemd-resolved或者某些老旧应用、脚本必须直接读取/etc/resolv.conf中的真实IP你可以选择禁用它将/etc/resolv.conf恢复为一个普通的静态文件。但这意味着你将失去systemd-resolved带来的缓存、DNSSEC等特性。步骤1停止并禁用服务sudo systemctl stop systemd-resolved sudo systemctl disable systemd-resolved步骤2将/etc/resolv.conf从符号链接改为普通文件首先删除现有的符号链接sudo rm -f /etc/resolv.conf然后创建新的/etc/resolv.conf文件并写入你的DNS服务器sudo nano /etc/resolv.conf内容如下nameserver 8.8.8.8 nameserver 114.114.114.114 options edns0 trust-ad步骤3防止其他服务重新创建符号链接需要告诉系统不要再去管理这个文件。对于使用NetworkManager的系统还需要修改其配置告诉它不要管理resolv.confsudo nano /etc/NetworkManager/NetworkManager.conf在[main]部分确保或添加以下行[main] dnsnone然后重启NetworkManagersudo systemctl restart NetworkManager重要警告这是最不推荐的方法尤其是在桌面环境或依赖NetworkManager的系统中。它可能与其他系统组件产生冲突并且在系统更新后配置可能被还原。除非你非常清楚自己在做什么并且有充分的理由否则请优先使用前三种“合作”方案。7. 验证与诊断如何确认DNS配置已生效且稳定配置完成后如何验证一切工作正常且不会“自动重置”呢以下是一套组合诊断拳法。7.1 检查 systemd-resolved 状态这是最权威的视图显示了systemd-resolved内部认为的当前DNS配置。systemd-resolve --status你会看到类似下面的输出重点关注你的活动链接如ens33和“Global”部分下的“DNS Servers”Link 2 (ens33) Current Scopes: DNS LLMNR setting: yes MulticastDNS setting: no DNSSEC setting: no DNSSEC supported: no DNS Servers: 8.8.8.8 114.114.114.114 DNS Domain: ~local如果这里显示的是你配置的DNS服务器而不是DHCP下发的或其他奇怪的地址说明配置已被systemd-resolved成功接收。7.2 检查 /etc/resolv.conf 的实质/etc/resolv.conf现在通常是一个指向/run/systemd/resolve/stub-resolv.conf的符号链接。直接cat它大概率只看到127.0.0.53。这是正常的不代表配置失败。因为查询会发往本地的systemd-resolved再由它根据你上面的配置去查询上游DNS。你可以查看这个“存根”文件的内容cat /run/systemd/resolve/stub-resolv.conf也可以查看systemd-resolved使用的真实上游配置cat /run/systemd/resolve/resolv.conf这个文件里应该包含了你设置的真实DNS服务器IP。7.3 使用 dig 或 nslookup 测试解析使用dig命令测试域名解析并指定查询服务器为127.0.0.53即本地的systemd-resolveddig 127.0.0.53 baidu.com在输出的“SERVER”行你会看到127.0.0.53#53(127.0.0.53)。在“ANSWER SECTION”看到正确的IP地址说明解析功能正常。你也可以不指定服务器直接dig baidu.com默认就会使用/etc/resolv.conf中配置的DNS即127.0.0.53。7.4 模拟“重置”触发条件进行验证配置完成后进行以下操作然后再次执行systemd-resolve --status检查DNS服务器列表是否被篡改重启网络服务sudo systemctl restart systemd-networkd(如果使用) 或sudo systemctl restart NetworkManager。重启systemd-resolved服务本身sudo systemctl restart systemd-resolved。断开并重新连接网络桌面环境下点击网络图标断开再连接。最后重启整个系统。如果经过以上“折腾”你配置的DNS服务器依然坚挺地显示在systemd-resolve --status中那么恭喜你DNS“自动重置”问题已被彻底解决。8. 常见问题与排查技巧实录即使按照上述步骤操作你可能还是会遇到一些“坑”。以下是我在实际操作中遇到的一些典型问题及解决方法。8.1 问题配置了Netplan但重启后DNS又变回DHCP下发的了。排查思路检查Netplan配置语法运行sudo netplan generate看是否有错误输出。一个常见的错误是YAML格式不对比如缩进用了Tab键而不是空格。检查渲染器renderer确认你的Netplan配置文件指定的渲染器与系统实际使用的网络管理器一致。桌面版通常用network-manager服务器版用networkd。如果不确定可以都写上renderer: NetworkManager或renderer: networkd。检查DHCP覆盖在Netplan配置中即使你指定了nameservers如果dhcp4设为yes某些旧版本或特定环境下DHCP下发的DNS可能仍有较高优先级。尝试在接口配置下明确添加dhcp4-overrides: use-dns: false。network: version: 2 ethernets: ens33: dhcp4: yes dhcp4-overrides: use-dns: false # 关键禁止使用DHCP提供的DNS nameservers: addresses: [8.8.8.8, 1.1.1.1]8.2 问题使用nmcli配置后连接WiFi时DNS生效换到有线连接又失效了。原因与解决这是因为nmcli connection mod修改的是某个特定连接配置文件的DNS。你的WiFi和有线连接在NetworkManager里是两个不同的“连接”Connection。你需要分别为它们配置DNS。使用nmcli connection show列出所有连接找到你的有线连接名称例如“Wired connection 1”。对有线连接也执行一遍DNS设置命令sudo nmcli connection mod Wired connection 1 ipv4.dns 8.8.8.8 1.1.1.1 ipv4.ignore-auto-dns yes。重新激活该有线连接。8.3 问题所有方法都试了但某些容器或虚拟机内的应用还是解析不了域名。排查思路这可能是因为systemd-resolved的DNS存根监听器DNSStubListener没有在所有网络接口上监听。默认它只监听在回环地址127.0.0.53上。如果你的Docker容器或虚拟机使用的是桥接网络或另一个IP段它们可能无法访问到这个地址。解决方案A推荐在容器或虚拟机内将DNS服务器直接设置为宿主机的物理IP地址例如192.168.1.100并确保宿主机的防火墙允许53端口的入站连接。解决方案B修改systemd-resolved配置让其监听在所有接口上安全性需自行评估。编辑/etc/systemd/resolved.conf设置[Resolve] DNSStubListeneryes # 监听在特定地址例如 0.0.0.0所有IPv4接口 DNSStubListenerExtra0.0.0.0然后重启systemd-resolved。之后容器内就可以将DNS设置为宿主机的IP了。8.4 问题修改DNS后网络变慢了或者某些国内网站访问异常。原因这通常是因为你使用了国外的公共DNS如8.8.8.8这些DNS服务器可能对国内CDN的解析不够优化导致你被解析到距离很远的服务器上。解决使用国内运营商或更智能的DNS。可以配置多个DNS将国内的放在前面。例如阿里DNS223.5.5.5,223.6.6.6腾讯DNS119.29.29.29114DNS114.114.114.114,114.114.115.115运营商DNS通常网关地址就是如192.168.1.1延迟最低。在你的Netplan或NetworkManager配置中可以这样设置nameservers: addresses: [223.5.5.5, 114.114.114.114, 8.8.8.8]这样会优先使用阿里DNS失败时尝试114DNS最后才用Google DNS作为保障。8.5 终极排查工具查看 systemd-resolved 的日志如果问题非常诡异可以查看systemd-resolved的详细日志这能帮助你看到它到底在做什么决定。# 查看实时日志 sudo journalctl -fu systemd-resolved # 查看最近的相关日志 sudo journalctl -u systemd-resolved --since 5 minutes ago在日志中你可以搜索“Using DNS server”正在使用的DNS服务器、“Fallback DNS server”回退DNS等关键词来追踪DNS配置的变化来源。我个人在实际操作中的体会是Ubuntu 20.04的DNS管理虽然初期让人觉得复杂和“多管闲事”但一旦理解了systemd-resolved作为中央管理者的角色并学会通过netplan或NetworkManager这些“官方渠道”去和它沟通配置反而变得更加清晰和模块化。记住黄金法则忘掉直接编辑/etc/resolv.conf这个习惯转而通过配置管理工具来设置“每链接DNS”或“全局DNS”让系统服务去自动维护那个文件这样才能一劳永逸地解决DNS被自动重置的问题。
返回列表