Как изменить имя хоста в Linux навсегда: hostnamectl, /etc/hosts и cloud-init
hostnamectl, /etc/hostname и /etc/hosts во взаимодействии, параметр, который не даёт cloud-init сбросить имя, и последствия для sudo, почтового сервера и сертификатов.
Сервер с именем debian, localhost или vm-01 работает безупречно. Неприятности начинаются позже: когда таких машин одновременно три, когда строки логов уже не отличить друг от друга или когда появляется первый почтовый сервер и принимающая сторона начинает проверять имя. Это руководство меняет имя хоста так, чтобы оно пережило ближайшую перезагрузку, чтобы sudo не упирался в таймаут и чтобы новое имя знали и те службы, которые читают его при запуске.
Это подробное продолжение шага 6 из чек-листа по настройке нового root-сервера. Там приведены две команды, которых чаще всего достаточно. Здесь разобрано, что за ними стоит и что делать, когда их не хватает.
Все сведения относятся к Debian 13 (trixie), Debian 12 (bookworm), Ubuntu 24.04 LTS и Ubuntu 22.04 LTS. Команды рассчитаны на работу от имени root. Если вы работаете под обычным пользователем, добавляйте перед каждой командой sudo.
У сервера три имени, а не одно
Самая частая причина наполовину удавшегося переименования в том, что Linux хранит не одно имя хоста, а три. Они лежат в разных местах, и переписывают их разные механизмы.
| Имя | Где хранится | Чем посмотреть | Кто его задаёт |
|---|---|---|---|
| статическое | /etc/hostname | hostnamectl --static | hostnamectl set-hostname, cloud-init |
| временное | только в ядре | hostnamectl --transient, uname -n | hostname NAME, DHCP-клиент, systemd-networkd |
| описательное | /etc/machine-info | hostnamectl --pretty | hostnamectl set-hostname --pretty |
Временное имя ведёт ядро, именно его получает каждая программа через gethostname(). Статическое имя — это образец, из которого временное выставляется при загрузке. Описательное имя может содержать пробелы и символы за пределами ASCII, и оно появляется только в интерфейсах, никогда в сети.
Не менее важно и второе различие: откуда каждая команда берёт свой ответ. Допустим, в /etc/hostname записано srv01, а в /etc/hosts стоит строка 127.0.1.1 srv01.example.com srv01. Тогда картина получается такая.
| Команда | Вывод | Источник |
|---|---|---|
hostname | srv01 | ядро |
uname -n | srv01 | ядро |
hostnamectl --static | srv01 | /etc/hostname |
hostname -s | srv01 | ядро, обрезано до первой точки |
hostname -f | srv01.example.com | разрешение имён |
hostname -d | example.com | разрешение имён |
dnsdomainname | example.com | разрешение имён |
domainname | (none) | домен NIS, а не DNS |
Ключевая строка здесь — hostname -f. Эта команда не читает /etc/hostname: она берёт имя из ядра и прогоняет его через разрешение имён. Полное имя приходит, таким образом, из /etc/hosts или из DNS, но никогда из файла с именем хоста. Почти все проблемы, разобранные в этой статье, вырастают именно из этого недоразумения.
Перед первым изменением: путь назад
Само по себе переименование вашу SSH-сессию не обрывает. Опасен следующий шаг: правка /etc/hosts. Если из этого файла пропадёт строка для localhost, десятки программ начнут ждать таймаутов, Postfix перестанет запускаться, а sudo будет тратить секунды на каждый вызов. Поэтому заранее проясните три вещи.
1. Вторая сессия остаётся открытой
Откройте второе окно терминала с активным подключением и не закрывайте его, пока всё не проверено. Уже установленная сессия переживает любое изменение имени хоста и разрешения имён. Если сам порядок подключения ещё не отработан, поможет статья Подключение к серверу по SSH.
2. Путь в обход SSH
У KVM root-серверов и выделенных серверов KernelHost нет ни IPMI, ни iDRAC. Доступ, который работает даже тогда, когда в гостевой системе уже ничего не работает, это VNC-консоль в личном кабинете. Она подключена к уровню виртуализации, а на выделенном сервере непосредственно к самой машине, и не зависит от разрешения имён внутри гостевой системы. Зайдите туда один раз заранее и убедитесь, что знаете пароль root. Запасной путь, который впервые пробуют в аварийной ситуации, запасным путём не является.
3. Две копии и откат
cp -a /etc/hostname /root/hostname.bak
cp -a /etc/hosts /root/hosts.bak
hostnamectl > /root/hostnamectl-before.txt
После этого путь назад умещается в две строки, которые в крайнем случае можно набрать через консоль:
cp -a /root/hosts.bak /etc/hosts
hostnamectl set-hostname "$(cat /root/hostname.bak)"
Инвентаризация в пяти командах
Сначала посмотрите, что действует сейчас и кто в это вмешивается.
hostnamectl
cat /etc/hostname
cat /etc/hosts
grep '^hosts:' /etc/nsswitch.conf
command -v cloud-init >/dev/null && cloud-init status --long || echo "cloud-init не установлен"
На вывод hostnamectl стоит посмотреть внимательно. Обычно он начинается со строки Static hostname:. Если дополнительно появляется строка Transient hostname:, значит статическое и работающее имя расходятся и что-то активно переставляет имя: почти всегда это cloud-init или DHCP-клиент. Такой источник нужно отключить в первую очередь, иначе после ближайшей перезагрузки ваша правка снова исчезнет.
Строка hosts: из /etc/nsswitch.conf задаёт порядок разрешения имён. Четыре записи, которые там встречаются, означают следующее:
files: читается/etc/hosts.dns: резолвер опрашивает серверы имён из/etc/resolv.conf.resolve: запрос уходит к systemd-resolved.myhostname: модуль systemd, который отображает собственное имя машины на локально настроенные IP-адреса, даже без записи в/etc/hosts.
Последний пункт объясняет ниже, почему одна и та же ошибка на некоторых серверах годами остаётся незамеченной.
Выбор имени: FQDN или короткое имя
Разрешены буквы, цифры и дефис. Никакого подчёркивания, никакой точки в начале или в конце, никакого дефиса в начале метки. Пишите строчными буквами: DNS сравнивает имена без учёта регистра, а многие программы, наоборот, буквально. Метка (часть между двумя точками) может занимать 63 символа, полное имя в DNS 253. Ядро при этом принимает для имени хоста не больше 64 символов, поэтому очень длинный FQDN может в него просто не поместиться. Выбирайте имя внутри домена, который принадлежит вам: .local зарезервирован для mDNS, а придуманные окончания вроде .lan в любой момент могут стать настоящими доменами верхнего уровня.
Остаётся вопрос, что именно записать в /etc/hostname. Работают оба варианта, различаются они тем, что вы потом видите повсюду.
| Вариант | /etc/hostname | hostname | hostname -f |
|---|---|---|---|
| Короткое имя (принято в Debian) | srv01 | srv01 | srv01.example.com, разрешается через /etc/hosts или DNS |
| FQDN (многие облачные образы) | srv01.example.com | srv01.example.com | srv01.example.com |
На Debian и Ubuntu стоит выбрать первый вариант: короткое имя в /etc/hostname, полное имя первой записью в /etc/hosts. Так приглашение командной строки и строки логов остаются короткими, а FQDN при этом остаётся верным. Второй вариант столь же аккуратен, пока его выдерживают последовательно. Настоящая ошибка — это смесь: один FQDN в /etc/hostname и другой в /etc/hosts.
A-запись (при IPv6 запись AAAA) для нового имени лучше всего создать прямо сейчас. Она ничего не стоит, делает вывод hostname -f правильным даже без /etc/hosts и служит условием для любого сертификата на это имя.
Укротить cloud-init, прежде чем что-то менять
В образах с cloud-init, а у Ubuntu это практически все образы, имя хоста при загрузке берётся из метаданных инстанса. Отвечают за это модули set_hostname и update_hostname, а за файл /etc/hosts модуль update_etc_hosts. Все три отрабатывают рано, ещё до старта ваших собственных служб. Управляют этим два параметра:
grep -rE '^(preserve_hostname|manage_etc_hosts)' /etc/cloud/cloud.cfg /etc/cloud/cloud.cfg.d/ 2>/dev/null
В серверных образах Ubuntu в /etc/cloud/cloud.cfg стоит строка preserve_hostname: false, то есть cloud-init имеет право трогать имя. Противоположному параметру в этом файле не место, потому что обновление пакета его заменит: он должен лежать в /etc/cloud/cloud.cfg.d/. Файлы оттуда читаются по алфавиту, и побеждает более поздний, отсюда и 99:
mkdir -p /etc/cloud/cloud.cfg.d
printf 'preserve_hostname: true\n' > /etc/cloud/cloud.cfg.d/99_hostname.cfg
Второй параметр касается /etc/hosts. Его охотно упускают из виду, хотя вреда от него больше.
Значение manage_etc_hosts | Как это влияет на /etc/hosts |
|---|---|
не задано или false | cloud-init файл не трогает |
localhost | при каждой загрузке cloud-init следит за тем, чтобы собственное имя разрешалось, а остальную часть файла оставляет как есть |
true | cloud-init при каждой загрузке заново создаёт файл из шаблона в /etc/cloud/templates/, и ваши собственные строки после этого пропадают |
Если там стоит true, а вам нужны собственные записи, поставьте значение localhost или ведите вместо файла сам шаблон (на Debian и Ubuntu это hosts.debian.tmpl). Править вручную файл, который перезаписывается при каждой загрузке, значит создавать ровно тот сорт ошибок, которые замечают лишь недели спустя.
Что cloud-init выставил в последний раз, он запоминает в /var/lib/cloud/data/. Это состояние стирает команда cloud-init clean. На уже настроенном сервере так делать не стоит: при следующей загрузке все модули отработают заново, как будто машина только что создана.
Второй источник перезаписи: DHCP
Если сервер получает адрес по DHCP, клиент может перенять временное имя хоста из ответа (опция 12). Статическое имя при этом остаётся нетронутым, что усложняет поиск причины: hostnamectl --static показывает ваше имя, а hostname другое. В netplan это отключается так:
network:
version: 2
ethernets:
eth0:
dhcp4: true
dhcp4-overrides:
use-hostname: false
Применяйте правку командой netplan try, а не netplan apply: try сам откатывает изменение через 120 секунд, если вы его не подтвердите. При напрямую настроенном systemd-networkd параметр называется UseHostname=no в секции [DHCPv4].
Задаём имя хоста
hostnamectl set-hostname srv01
Без дополнительных ключей hostnamectl задаёт статическое и временное имя разом. Именно это вам и нужно. С ключом --static вы меняете только /etc/hostname, и при активном временном имени машина до перезагрузки продолжала бы работать под старым. Более новые версии systemd понимают также краткую форму hostnamectl hostname srv01, а set-hostname работает на всех четырёх системах.
Проверка: оба имени должны совпадать, а файл содержать новое значение.
hostnamectl --static
hostnamectl --transient
cat /etc/hostname
Два замечания на полях. Во-первых, команда hostname srv01 без ctl меняет только временное имя, и после перезагрузки оно исчезает. Во-вторых, ваша текущая оболочка продолжает показывать в приглашении старое имя, потому что bash читает имя хоста один раз при старте сессии. Это не провал, а просто старая сессия. Войдите заново.
При желании задайте описательное имя, которое появляется в интерфейсах и может содержать пробелы:
hostnamectl set-hostname --pretty "Веб-сервер Франкфурт"
cat /etc/machine-info
Как правильно записать /etc/hosts
hostnamectl не трогает /etc/hosts. Этот файл остаётся вашей заботой, и именно из-за него переименование так часто срабатывает лишь наполовину.
Строка состоит из IP-адреса, канонического имени и произвольного числа псевдонимов. Первое имя после адреса и есть каноническое, именно его возвращает hostname -f. Поэтому впереди стоит полное имя, а короткое за ним, и никогда наоборот.
127.0.0.1 localhost
127.0.1.1 srv01.example.com srv01
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
Почему 127.0.1.1, а не 127.0.0.1: Debian и Ubuntu намеренно отделяют собственное имя машины от localhost. Если дописать имя сервера псевдонимом в строку localhost, каноническим именем этой строки останется localhost, и hostname -f ответит именно localhost. Программы, которые выводят отсюда собственное имя, запишут потом localhost в логи и в заголовки писем.
Отсутствующую запись вы дописываете, а уже имеющуюся строку правите:
grep -n '^127\.0\.1\.1' /etc/hosts
printf '127.0.1.1\tsrv01.example.com\tsrv01\n' >> /etc/hosts
Если первая команда уже выводит строку, правьте именно её, а не дописывайте вторую. При двух строках для одного и того же адреса побеждает первая, и дальше вы будете править строку, которую никто уже не читает.
Проверка:
getent hosts srv01
getent hosts srv01.example.com
hostname -f
hostname -s
Оба вызова getent должны вернуть по одной строке, hostname -f полное имя, а hostname -s короткое. Если в ответ ничего не приходит, запись не действует, например потому что строка начинается со знака комментария.
Одно решение остаётся за вами: 127.0.1.1 или публичный адрес сервера. Некоторые программы привязываются к адресу, в который разрешается их собственное имя, или записывают его в список участников кластера. Тогда FQDN должен указывать на публичный адрес. При постоянном адресе это более аккуратный вариант, при меняющемся лучше 127.0.1.1, потому что он работает и без сетевого подключения.
Почему отсутствующая запись замедляет sudo
sudo при каждом вызове определяет собственное имя машины и отправляет его на разрешение. Имя нужно ему для строки лога и для сверки с указаниями хостов в /etc/sudoers.
Разрешение идёт по строке hosts: из /etc/nsswitch.conf. Если имя есть в /etc/hosts, дело закрывается одним обращением к файлу, то есть меньше чем за миллисекунду. Если имени там нет, запрос переходит к следующей записи, обычно это dns, и резолвер спрашивает у серверов имён из /etc/resolv.conf про имя, которого в DNS не существует. По умолчанию в glibc заданы таймаут в пять секунд и две попытки на каждый сервер имён. Если никто не отвечает, всё это складывается, причём при каждом отдельном вызове.
Есть и усиливающий фактор: короткое имя не содержит точки и потому попадает под настройку по умолчанию ndots:1. Поэтому резолвер сначала подставляет к нему каждый поисковый домен из /etc/resolv.conf и только затем спрашивает само имя. Два поисковых домена означают три круга запросов вместо одного.
Заметно это по предупреждению, которое предваряет каждый вызов:
sudo: unable to resolve host srv01: Name or service not known
Измерять, а не гадать:
time getent hosts "$(hostname)"
time sudo -n true
Оба вызова должны укладываться заметно быстрее десятой доли секунды. Всё, что сверх того, это ожидание ответа от сервера имён.
А теперь причина, по которой ошибка бросается в глаза не везде: если в строке hosts: присутствует запись myhostname, этот модуль сам отвечает на запрос о собственном имени, без DNS и без /etc/hosts. Там предупреждение не появляется, хотя файл заполнен не полностью. Как только та же конфигурация переезжает на систему без этой записи, ошибка возвращается.
Вторая, более редкая проблема касается прав: в /etc/sudoers любое правило может быть ограничено определёнными именами машин. Штатные правила Debian и Ubuntu используют ALL и потому безобидны. А вот собственные правила с указанием имени машины теряют силу, и затронутому пользователю после этого не разрешено уже ничего. Проверьте заранее:
grep -rhvE '^[[:space:]]*(#|$)' /etc/sudoers /etc/sudoers.d/
Службы, которые читают имя при запуске
Многие программы запрашивают имя хоста ровно один раз, при запуске, и дальше продолжают работать со старым именем. Этим объясняется изрядная часть путаницы после переименования.
- Текущая оболочка. Приглашение показывает старое имя. Откройте новую сессию, и всё.
- rsyslog там, где он установлен. Достаточно
systemctl restart rsyslog. В минимальных установках Debian 12 и 13 rsyslog отсутствует, там пишет journald. - Уже записанные строки логов сохраняют старое имя, и это правильно. А вот если старое имя стоит в новых записях, перезапустите ту службу, которая их пишет.
- MariaDB и MySQL формируют стандартные имена файлов, например лога ошибок и бинарного лога, на основе имени хоста, если пути не заданы явно в конфигурации.
- Java-приложения. Вызов
InetAddress.getLocalHost()бросаетjava.net.UnknownHostException, как только собственное имя перестаёт разрешаться. Это касается и серверов приложений, и игровых серверов. - Агенты мониторинга часто держат имя в собственном конфигурационном файле. Иначе после переименования один и тот же сервер появится в списке дважды.
systemctl list-units --type=service --state=running
Если окно обслуживания и так запланировано, самое полное решение это перезагрузка. Как аккуратно оформить собственные программы в виде unit-файла, чтобы они переживали перезагрузку, описано в статье Создание собственной systemd-службы.
Почтовый сервер: имя, которое видят другие
При отправке почты имя хоста перестаёт быть косметикой. Принимающая сторона видит его в EHLO и проверяет. Три вещи должны сойтись:
- Имя, которым представляется ваш почтовый сервер (в Postfix это
myhostname). - PTR-запись вашего IP-адреса, то есть обратное разрешение.
- A-запись (при IPv6 запись AAAA) именно для этого имени, которая снова указывает на тот же адрес.
Если цепочка не замыкается, многие получатели понижают оценку письма или отклоняют его. Проверка без дополнительных пакетов:
hostname -f
getent hosts 203.0.113.10
getent hosts srv01.example.com
Точнее получится с dig из пакета bind9-dnsutils:
apt install -y bind9-dnsutils
dig +short -x 203.0.113.10
dig +short srv01.example.com A
PTR-запись серверу не принадлежит. Она привязана к IP-адресу, и ведёт её оператор сети, у KernelHost это делается через личный кабинет. Никакой вызов hostnamectl тут ничего не изменит, и именно на этом переименования почтовых серверов и срываются.
Postfix не подхватывает переименование сам по себе. На Debian и Ubuntu пакет при настройке записывает фиксированное значение в /etc/postfix/main.cf, а рядом лежит /etc/mailname с именем, которое Postfix использует как домен отправителя для локальной почты. Оба остаются в прежнем виде:
postconf myhostname mydomain myorigin
cat /etc/mailname
Меняем и перезапускаем, причём /etc/mailname это отдельное решение, и он не обязан нести то же значение, что и myhostname:
postconf -e "myhostname = srv01.example.com"
postfix check
systemctl restart postfix
А вот SPF, DKIM и DMARC привязаны к домену отправителя, а не к имени хоста. Переименование, таким образом, не чинит проблемы доставки, причина которых лежит именно там.
Сертификаты
Системное имя не фигурирует ни в одном сертификате, потому что сертификат покрывает те DNS-имена, которые были указаны в заявке. И всё же переименование отзывается в трёх местах.
Во-первых, при выпуске. Если вы получаете сертификат на само имя сервера, например для почтового сервера, это имя должно быть в DNS до того, как удостоверяющий центр начнёт проверку. Иначе запуск закончится сообщением вроде DNS problem: NXDOMAIN looking up A for srv01.example.com. A-запись создают до заявки, а не после.
Во-вторых, при уже существующих сертификатах. Они продолжают действовать на старое имя и продолжают продлеваться, пока вы их не удалите:
certbot certificates
certbot delete --cert-name old.example.com
Удаляйте только тогда, когда на этот путь больше не ссылается ни одна служба, иначе веб-сервер при следующей перезагрузке конфигурации не поднимется.
В-третьих, на почтовом сервере. Если Postfix представляется новым именем, но предъявляет сертификат для старого, у принимающих сторон со строгой проверкой имени соединение не состоится. Сертификат и myhostname должны указывать на одно и то же имя.
Никакой связи между системным именем и директивой server_name в nginx нет. nginx принимает решение по заголовку Host из запроса, а не по имени машины. Если после переименования отдаётся не та страница, искать нужно в конфигурации сервера, а не в имени хоста. Основы по этой теме есть в статье Установка nginx на Debian и Ubuntu.
Частые ошибки и решения
sudo: unable to resolve host srv01: Name or service not known
Имени машины нет в /etc/hosts, и в DNS оно неизвестно. Добавьте строку 127.0.1.1 srv01.example.com srv01. Пока её нет, каждый вызов ждёт таймаута резолвера.
hostname: Name or service not known
Ответ команды hostname -f, когда имя из ядра нигде не разрешается. Та же причина, то же решение. После этого командой getent hosts "$(hostname)" проверьте, действительно ли что-то возвращается.
Could not set property: Access denied
hostnamectl был вызван без прав root, либо вызов прошёл в контейнере, которому не разрешено менять имя в ядре. На собственном сервере помогает sudo. В непривилегированном контейнере имя задают в его конфигурации снаружи, а не изнутри.
fatal: unable to use my own hostname
Из лога Postfix. Значение в myhostname не разрешается. Добавьте запись в /etc/hosts, затем выполните systemctl restart postfix.
504 5.5.2 <srv01>: Helo command rejected: need fully-qualified hostname
Ваш почтовый сервер представляется коротким именем, а принимающая сторона требует полное. Поставьте в myhostname FQDN и перезапустите Postfix.
450 4.7.1 Client host rejected: cannot find your reverse hostname
Для вашего IP-адреса нет PTR-записи либо она указывает в пустоту. На самом сервере это не чинится, только у оператора IP-сети.
java.net.UnknownHostException: srv01
Java-приложение попыталось разрешить собственное имя и не смогло. Снова /etc/hosts. После добавления записи приложение нужно перезапустить.
DNS problem: NXDOMAIN looking up A for srv01.example.com
Нового имени в DNS ещё не существует. Создайте A-запись, дождитесь её распространения, повторите заявку.
После перезагрузки имя снова старое.
Проверяйте в таком порядке: задан ли preserve_hostname: true в /etc/cloud/cloud.cfg.d/, перестал ли DHCP-клиент присылать имя, действительно ли в /etc/hostname лежит новое имя. Если hostnamectl после загрузки показывает строку Transient hostname:, значит один из этих источников всё ещё срабатывает.
/etc/hosts после каждой перезагрузки снова вычищен.
Задано manage_etc_hosts: true, и cloud-init создаёт файл заново из шаблона. Переключите значение на localhost или ведите сам шаблон.
Различия между дистрибутивами
| Система | cloud-init из коробки | rsyslog | Особенность |
|---|---|---|---|
| Debian 13 (trixie) | только в облачных образах | отсутствует в минимальных установках | логи в журнале вместо /var/log/syslog |
| Debian 12 (bookworm) | только в облачных образах | зависит от варианта установки | как в Debian 13 |
| Ubuntu 24.04 LTS | да, preserve_hostname: false | присутствует | systemd-resolved активен, resolve стоит в строке hosts: |
| Ubuntu 22.04 LTS | да, preserve_hostname: false | присутствует | как в Ubuntu 24.04 |
Одинаково на всех четырёх системах: hostnamectl никогда не меняет /etc/hosts, и ни один инструмент операционной системы не создаёт записи DNS или PTR. Эти два шага остаются ручной работой.
Финальная проверка
Команда без сообщения об ошибке ещё не доказательство. Единственная надёжная проба это перезагрузка, а после неё вот эти пять строк:
hostnamectl --static
hostname -f
getent hosts "$(hostname)"
time sudo -n true
grep -c '^127\.0\.1\.1' /etc/hosts
Ожидаются: новое короткое имя, новое полное имя, одна строка из /etc/hosts, время выполнения заметно меньше десятой доли секунды и ровно одна строка для 127.0.1.1. Только когда сходятся все пять пунктов, переименование доведено до конца, и только тогда можно закрывать второе окно терминала.
Частые вопросы
Почему после перезагрузки имя хоста снова старое?
Почему sudo сообщает «unable to resolve host» и вдруг тратит секунды?
Что записывать в /etc/hostname: короткое имя или полное?
Почему в /etc/hosts указывают 127.0.1.1, а не 127.0.0.1?
Меняет ли hostnamectl ещё и /etc/hosts?
Достаточно ли команды hostname для постоянного изменения?
Что дополнительно настроить для почтового сервера?
2026 KernelHost GmbH. Все права защищены. Эта инструкция охраняется авторским правом. Публикация на других сайтах, в том числе частично или в изменённом виде, без нашего письменного согласия не разрешается. Цитирование с указанием источника и активной ссылкой мы приветствуем.

