DEBUG.WIKI
V.PS:让项目靠近用户,亚太、欧洲、北美 KVM VPS
IPPeak:从目标地区访问网页,住宅代理、SEO 监测、广告验证
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国

修改主机名后 sudo 报 unable to resolve host

修改主机名后,sudo 提示 unable to resolve host。比较当前名称、/etc/hostname 与 NSS 解析结果,确认旧 hosts 映射后备份修正,并检查 sudo、云主机配置覆盖和回退方法。

改完主机名,普通命令正常,执行 sudo 却出现下面的提示,有时还会先停顿一会儿:

sudo: unable to resolve host webserver: Name or service not known

webserver 是示例主机名,以报错中实际出现的名字为准。这条信息指向主机名解析,不等于密码错误,也不一定表示后面的命令没有执行。

改名后,/etc/hostname 已是新名称,而 /etc/hosts 仍把本机地址映射到旧名称时,系统可能无法解析自己的新主机名。先确认系统实际使用的解析路径,再更新已确认的本机映射。

本文适用于 Debian、Ubuntu 等使用 glibc/NSS 的 Linux 环境,处理改名后本机解析记录没有同步的问题。容器、WSL、集中管理的解析环境或其他 libc 实现,应先按各自的配置来源核对,不能直接套用这里的文件修改步骤。

比较当前名称、持久名称和本机解析结果

先用普通用户执行这些只读命令:

current_hostname=$(hostname) || exit 1
printf 'Current hostname: %s\n' "$current_hostname"
cat /etc/hostname
cat /etc/hosts
grep -nE '^[[:space:]]*hosts[[:space:]]*:' /etc/nsswitch.conf
getent ahosts "$current_hostname"

hostname 不带参数显示内核当前使用的名称;/etc/hostname 保存的则是持久配置。两者可能不一致,例如只编辑了文件,当前运行的系统尚未应用新名称。排查这次警告时,以报错中的名字和当前 hostname 输出为线索,不要只看终端提示符或云平台给实例起的显示名称。

getent ahosts把名称交给系统的 getaddrinfo() 查找,能检查当前 NSS 解析路径是否返回地址。没有输出或报错时,先记下结果;有输出也要确认地址符合这台机器的用途,不能只以“随便查到了一个地址”为成功。

如果使用 systemd,还可以查看:

hostnamectl status

hostnamectl区分 static、transient 和 pretty 等名称。用于显示的名称与系统实际使用的名称不一定相同。不要为了消除警告再随意给机器改一个名字,这可能影响依赖原名称的服务和配置。

确认系统确实会读取 hosts 文件

在典型的 Debian、Ubuntu 配置中,本机名称可以通过 /etc/hosts 提供映射,但这不是唯一的解析来源。/etc/nsswitch.conf 的 hosts: 行决定使用哪些服务、按什么顺序查找,以及遇到不同结果后是否继续。

例如,files 表示读取本地文件。它出现在配置中,并不保证每次查找都能走到这里:前面的服务及方括号中的返回规则也会影响结果。不要把整行直接替换成网上的 hosts: files dns,否则可能移除系统原来需要的解析模块。

可以单独检查 files 服务:

getent -s files hosts "$current_hostname"

GNU/glibc 的 getent -s 用于覆盖查找服务;该功能从 glibc 2.2.5 起支持。对照前面的 getent ahosts,可以缩小范围:

  • files 查不到,完整系统查找也查不到,且 hosts 中仍只有旧名称:符合本篇的修复条件。
  • files 能找到新名称,但完整系统查找失败:继续核对 NSS 顺序、返回规则及其他解析模块,不要重复追加同一条 hosts 记录。
  • 完整系统查找已经返回预期地址,sudo 仍报错:确认 sudo 报的是否为同一个名称,以及是否在相同机器、容器或运行环境中执行。解析调用的参数和地址族也可能不同,不能用一次 getent 成功证明所有调用均正常。

sudo 的主机名解析回调通过 getaddrinfo() 查找名称,并在失败分支生成这条警告。是否需要这类查找与 sudoers 的配置有关;这不能概括成“所有 sudo 命令必然访问公网 DNS”。本机记录、DNS 或其他 NSS 服务都可能参与。网页能打开、公共域名能解析,也不能证明系统能解析自己的主机名。

备份 hosts,再修正已确认的那条映射

先确认仍能执行管理命令。如果只是显示警告,可以用一个无副作用的命令检查实际结果:

sudo true
printf 'sudo exit status: %s\n' "$?"

不要只看最后一行报错来判断执行状态。若 sudo 无法取得权限、持续等待或还有其他错误,应使用已有的管理员会话或已授权的服务器控制台处理。没有管理权限时,修改 hosts 的步骤无法完成;不需要为此放开文件权限或把 sudo 配成免密码。

下面假设 /etc/hosts 是普通文件,且未被其他工具自动管理。如果它是符号链接、挂载文件或由管理系统生成,先确认实际来源与修改入口,不要强行替换。

backup_dir=$(sudo mktemp -d /var/backups/hosts-rename.XXXXXX) || exit 1
sudo cp -p -- /etc/hosts "$backup_dir/hosts" || exit 1
printf 'Backup: %s\n' "$backup_dir/hosts"

记下备份路径,确认复制成功后再编辑。mktemp -d 创建的目录默认只允许所有者访问,权限还可能被 umask 进一步收紧。

如果当前主机名已经确定为 webserver,而这台普通 Ubuntu、Debian 主机使用回环地址提供本机名称,可以把原先指向旧名称的本机映射改成新名称。相关两行的示例如下:

127.0.0.1 localhost
127.0.1.1 webserver

这是局部示例,不是整份文件的替换内容。hosts 条目的格式是“地址、规范名称、可选别名”,127.0.1.1 可以用于本机名称映射。保留原有 localhost、IPv6 和其他服务记录。

如果原本为这台服务器配置了固定地址与 FQDN,应按现有网络设计更新名称,保留正确地址及所需别名,而不是一律换成回环地址。使用主机名限定的 sudoers 规则、服务配置或旧名称别名的环境,还要核对这些依赖;规范名称的顺序可能影响匹配,不能随意交换。

已有条目就修改该条目,避免在文件末尾留下新旧名称指向不同地址的冲突记录。不要把主机名写成登录用户名,也不要直接取 hostname -I 输出的第一个地址:多网卡环境没有保证它就是应该使用的地址。

可以使用系统提供的编辑入口:

sudoedit /etc/hosts

sudoedit 需要相应的策略授权。保存退出后还要确认文件已经写回;如果工具报无法更新原文件,临时编辑副本存在不等于修改完成。不支持此入口的受管系统,使用其指定的配置编辑方式。

再查解析,再检查 sudo

修改完成后,重复检查当前名称和系统解析,然后执行无副作用的 sudo 命令:

hostname
getent -s files hosts "$current_hostname"
getent ahosts "$current_hostname"
sudo true
printf 'sudo exit status: %s\n' "$?"

确认本机名称返回预期地址、sudo 不再出现相同解析警告,且测试命令成功。修复前若执行过业务命令,还应另外核对其结果;警告消失不能补证此前的命令成功。

hosts 文件的修改通常立即生效,应用缓存是例外,不必把整机重启作为默认步骤。仍有问题时,重新比较报错名称、当前名称和实际解析结果,再查相关缓存或配置。此时直接修改 /etc/resolv.conf、换公共 DNS、重启整套网络,可能扩大影响,也不一定解决本机条目仍是旧名称的问题。

云主机重启后再次出现警告

如果修改当时有效,重启后 hosts 又变回去,先检查文件头的生成说明,以及 cloud-init 或配置管理工具的设置。

cloud-init 的 manage_etc_hosts 默认为 false;设为 true 时,会根据模板在每次启动时重新生成 hosts。模板路径为 /etc/cloud/templates/hosts.tmpl,应以当前发行版及实例实际使用的模板为准。localhost 模式则维护本机名称映射,处理范围不同。

因此,不是所有云主机都必须关闭 cloud-init。先确认它是否管理 hosts,以及主机名和 FQDN 来自本地配置还是实例元数据,再从该管理来源修正。保留其管理能力时,应同步修改正确的配置或模板,并备份相应文件。不要只为验证 hosts 修复就清理 cloud-init 状态、重新初始化实例或重跑全部模块。

需要回退时恢复这一份文件

修正本机映射可能影响使用该名称连接服务的程序。如果出现意外,保留当前管理员会话,比较修改前后的内容;确认没有其他应保留的新改动,再恢复备份。替换下面的目录为刚才实际输出的备份目录:

sudo cp -p -- /var/backups/hosts-rename.XXXXXX/hosts /etc/hosts

恢复后重新检查本机解析及相关服务。旧映射回归时,原先的 sudo 警告也可能回来。如果 hosts 由工具生成,应同时回退本轮确实改过的管理配置;只恢复生成结果,可能在下次启动时再次被覆盖。