Changing the hostname permanently on Linux: hostnamectl, /etc/hosts and cloud-init
hostnamectl, /etc/hostname and /etc/hosts working together, the switch against cloud-init resetting the name, and the effects on sudo, mail servers and certificates.
A server called debian, localhost or vm-01 works perfectly well. It only gets awkward once three of them are running at the same time, once log lines can no longer be told apart, or once the first mail server joins in and the remote end starts checking the name. This guide changes the hostname so that it survives the next reboot, so that sudo does not run into a timeout, and so that the services which read the name at startup know about it too.
This is the deep dive on step 6 of the checklist for a new root server. That article gives you the two commands that are usually enough. This one explains what happens behind them, and what to do when they are not enough.
Everything here applies to Debian 13 (trixie), Debian 12 (bookworm), Ubuntu 24.04 LTS and Ubuntu 22.04 LTS. The commands are written for running as root. As a regular user, put sudo in front of every command.
A server has three names, not one
The most common reason a rename only half works is that Linux does not know one hostname, it knows three. They live in different places, and different things overwrite them.
| Name | Where it lives | Read it with | What sets it |
|---|---|---|---|
| static | /etc/hostname | hostnamectl --static | hostnamectl set-hostname, cloud-init |
| transient | kernel only | hostnamectl --transient, uname -n | hostname NAME, DHCP client, systemd-networkd |
| pretty | /etc/machine-info | hostnamectl --pretty | hostnamectl set-hostname --pretty |
The kernel keeps the transient name, and that is the one every program receives through gethostname(). The static name is the template it is set from at boot. The pretty name may contain spaces and accented characters, and it only ever shows up in user interfaces, never on the network.
The second distinction matters just as much: which command takes its answer from where. Assume that /etc/hostname contains srv01 and that /etc/hosts holds the line 127.0.1.1 srv01.example.com srv01, then the picture looks like this.
| Command | Output | Source |
|---|---|---|
hostname | srv01 | kernel |
uname -n | srv01 | kernel |
hostnamectl --static | srv01 | /etc/hostname |
hostname -s | srv01 | kernel, cut off at the first dot |
hostname -f | srv01.example.com | name resolution |
hostname -d | example.com | name resolution |
dnsdomainname | example.com | name resolution |
domainname | (none) | NIS domain, not DNS |
The decisive row is hostname -f. That command does not read /etc/hostname. It takes the kernel name and pushes it through name resolution. The fully qualified name therefore comes from /etc/hosts or from DNS, never from the hostname file. Almost every problem in this article goes back to that one misunderstanding.
Before the first change: the way back
A rename on its own does not cut your SSH session. The dangerous part is the step after it: editing /etc/hosts. If the line for localhost disappears there, dozens of programs sit in timeouts, Postfix refuses to start, and sudo needs seconds per call. So sort out three things first.
1. Keep a second session open
Open a second terminal window with a live connection and do not close it until everything has been verified. An existing session survives every change to the hostname and to name resolution. If the connection itself is not properly set up yet, see Connecting to your server over SSH.
2. The route that bypasses SSH
KVM root servers and dedicated servers from KernelHost have no IPMI and no iDRAC. The access path that still works when nothing inside the guest system does is the VNC console in the customer panel. It hangs off the virtualization layer (or off the port itself) and does not depend on name resolution inside the guest system. Log in there once beforehand and make sure you know the root password. A rescue path you try for the first time during an emergency is not a rescue path.
3. Two copies and a rollback
cp -a /etc/hostname /root/hostname.bak
cp -a /etc/hosts /root/hosts.bak
hostnamectl > /root/hostnamectl-before.txt
That turns the way back into two lines, which you can type into the console if it comes to that:
cp -a /root/hosts.bak /etc/hosts
hostnamectl set-hostname "$(cat /root/hostname.bak)"
Taking stock in five commands
First have a look at what applies right now, and at what has a say in it.
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 not installed"
The output of hostnamectl deserves a close look. It normally starts with Static hostname:. If a Transient hostname: line shows up as well, the stored name and the running name differ, and something is actively resetting the name: almost always cloud-init or a DHCP client. Turn that off first, otherwise your change is gone again after the next reboot.
The hosts: line from /etc/nsswitch.conf defines the order of name resolution. The four entries you find there mean:
files:/etc/hostsis read.dns: the resolver queries the nameservers from/etc/resolv.conf.resolve: the query goes to systemd-resolved.myhostname: a systemd module that maps the local machine name to the locally configured IP addresses, even without an entry in/etc/hosts.
The last entry explains, further down, why the same mistake goes unnoticed for years on some servers.
Choosing the name: FQDN or short name
Letters, digits and the hyphen are allowed. No underscore, no dot at the beginning or the end, no hyphen at the beginning of a label. Write it in lower case: DNS compares without regard to case, while many programs compare literally. A label (the part between two dots) may be 63 characters long, the full name in DNS 253. The kernel, however, accepts at most 64 characters for the hostname, so a very long FQDN may not fit in at all. Pick the name below a domain that belongs to you: .local is reserved for mDNS, and invented endings such as .lan can turn into real top-level domains at any time.
That leaves the question of what goes into /etc/hostname. Both variants work, and they differ only in what you see displayed everywhere afterwards.
| Variant | /etc/hostname | hostname | hostname -f |
|---|---|---|---|
| Short name (the Debian convention) | srv01 | srv01 | srv01.example.com, resolved through /etc/hosts or DNS |
| FQDN (many cloud images) | srv01.example.com | srv01.example.com | srv01.example.com |
On Debian and Ubuntu the first variant is the one to go for: the short name in /etc/hostname, the fully qualified name as the first entry in /etc/hosts. That keeps the prompt and the log lines short, and the FQDN is still correct. The second variant is just as clean, as long as you keep it up consistently. The actual mistake is mixing the two: one FQDN in /etc/hostname and a different one in /etc/hosts.
Create the A record (with IPv6, the AAAA record) for the new name right now. It costs nothing, it makes hostname -f correct even without /etc/hosts, and it is the precondition for every certificate issued on that name.
Taming cloud-init before you set anything
On images that ship cloud-init, and on Ubuntu that is practically all of them, the hostname is set at boot from the metadata of the instance. The modules in charge are set_hostname and update_hostname, plus update_etc_hosts for the file /etc/hosts. All three run early, before your own services start. Two switches control this:
grep -rE '^(preserve_hostname|manage_etc_hosts)' /etc/cloud/cloud.cfg /etc/cloud/cloud.cfg.d/ 2>/dev/null
On Ubuntu server images, /etc/cloud/cloud.cfg carries the line preserve_hostname: false, so cloud-init is allowed to touch the name. The counter switch does not belong in that file, because a package update replaces it, but in /etc/cloud/cloud.cfg.d/. The files there are read in alphabetical order and the later one wins, hence the 99:
mkdir -p /etc/cloud/cloud.cfg.d
printf 'preserve_hostname: true\n' > /etc/cloud/cloud.cfg.d/99_hostname.cfg
The second switch concerns /etc/hosts. It is easily overlooked, even though it does more damage.
Value of manage_etc_hosts | Effect on /etc/hosts |
|---|---|
not set, or false | cloud-init leaves the file alone |
localhost | at every boot, cloud-init makes sure that the machine name resolves, and leaves the rest of the file as it is |
true | cloud-init regenerates the file at every boot from the template under /etc/cloud/templates/, and your own lines are gone afterwards |
If it says true and you need your own entries, set the value to localhost, or maintain the template instead (on Debian and Ubuntu that is hosts.debian.tmpl). Editing a file by hand that gets overwritten at every boot produces exactly the kind of fault you only notice weeks later.
cloud-init remembers what it set last under /var/lib/cloud/data/. That state is wiped by cloud-init clean. Please do not do this on a server that is already set up: at the next boot every module runs again, as if the machine were brand new.
The second name changer: DHCP
If the server gets its address over DHCP, the client can take the transient hostname from the reply (option 12). The static name stays untouched, which makes troubleshooting harder: hostnamectl --static shows your name, hostname a different one. Under netplan you switch it off like this:
network:
version: 2
ethernets:
eth0:
dhcp4: true
dhcp4-overrides:
use-hostname: false
Activate it with netplan try instead of netplan apply: try rolls the change back on its own after 120 seconds if you do not confirm. With systemd-networkd configured directly, the setting is called UseHostname=no in the [DHCPv4] section.
Setting the hostname
hostnamectl set-hostname srv01
Without further switches, hostnamectl sets the static and the transient name together. That is exactly what you want. With --static you only change /etc/hostname, and while a transient name is active the machine would keep running under the old one until the reboot. Newer systemd versions also know the short form hostnamectl hostname srv01, while set-hostname works on all four systems.
Verification: both names have to match, and the file has to carry the new content.
hostnamectl --static
hostnamectl --transient
cat /etc/hostname
Two side notes. First, hostname srv01 without the ctl changes only the transient name, and it is gone after the reboot. Second, your running shell keeps showing the old name in the prompt, because bash reads the hostname once when the session starts. That is not a failure, that is an old session. Log in again.
Optionally, you can store a pretty name that appears in user interfaces and is allowed to contain spaces:
hostnamectl set-hostname --pretty "Webserver Frankfurt"
cat /etc/machine-info
Writing /etc/hosts correctly
hostnamectl does not touch /etc/hosts. That file stays your job, and it is the reason why a rename so often only works halfway.
A line consists of an IP address, the canonical name and any number of aliases. The first name after the address is the canonical one, and that is exactly what hostname -f returns. This is why the fully qualified name comes first and the short name after it, never the other way round.
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
Why 127.0.1.1 and not 127.0.0.1: Debian and Ubuntu deliberately keep the machine name separate from localhost. If you append the server name as an alias to the localhost line, the canonical name of that line stays localhost, and hostname -f answers with localhost. Programs that derive their own name from it then write localhost into log files and email headers.
Append a missing entry, or edit an existing line:
grep -n '^127\.0\.1\.1' /etc/hosts
printf '127.0.1.1\tsrv01.example.com\tsrv01\n' >> /etc/hosts
If the first command already prints a line, edit that one instead of appending a second. With two lines for the same address the first one wins, and you would go on to edit a line that nobody reads any more.
Verification:
getent hosts srv01
getent hosts srv01.example.com
hostname -f
hostname -s
The two getent calls have to return one line each, hostname -f the fully qualified name and hostname -s the short one. If nothing comes back, the entry is not in effect, for example because the line carries a comment character.
One decision is left: 127.0.1.1 or the public address of the server. Some software binds to the address that its own name resolves to, or registers that address in the member list of a cluster. In that case the FQDN belongs on the public address. With a fixed address that is the cleaner variant, with a changing address it is 127.0.1.1, because that one also works without a network connection.
Why a missing entry makes sudo slow
sudo determines the machine name on every call and has it resolved. It needs the name for the log line and for matching against the host entries in /etc/sudoers.
Resolution follows the hosts: line from /etc/nsswitch.conf. If the name is in /etc/hosts, the matter is settled after one file access, so in well under a millisecond. If it is not there, the query moves on to the next entry, usually dns, and the resolver asks the nameservers from /etc/resolv.conf for a name that does not exist in DNS. The glibc defaults are a five second timeout and two attempts per nameserver. If nobody answers, that adds up, and it does so on every single call.
One thing makes it worse: a short name contains no dot and therefore falls below the default ndots:1. The resolver first appends every search domain from /etc/resolv.conf and only queries the bare name afterwards. Two search domains mean three query rounds instead of one.
You can see it in this warning, which is printed before every call:
sudo: unable to resolve host srv01: Name or service not known
Measure instead of guessing:
time getent hosts "$(hostname)"
time sudo -n true
Both should stay well below a tenth of a second. Anything above that is time spent waiting for a nameserver.
And now the reason why the fault does not stand out everywhere: if the hosts: line contains the entry myhostname, that module answers the query for the machine name itself, without DNS and without /etc/hosts. There the warning never appears, even though the file is incomplete. As soon as the same setup moves to a system without that entry, the fault is back.
A second, rarer problem concerns permissions: in /etc/sudoers, every rule can be restricted to specific machine names. The rules that Debian and Ubuntu ship use ALL and are harmless. Your own rules that name a machine, on the other hand, lose their effect, and the user in question is then allowed to do nothing at all. Check beforehand:
grep -rhvE '^[[:space:]]*(#|$)' /etc/sudoers /etc/sudoers.d/
Services that read the name at startup
Many programs query the hostname exactly once, at startup, and carry on with the old name afterwards. That explains a good part of the confusion after a rename.
- The running shell. The prompt shows the old name. Open a new session and you are done.
- rsyslog, where it is installed. A
systemctl restart rsyslogis enough. Minimal installations of Debian 12 and 13 do not ship rsyslog, journald does the writing there. - Log entries that have already been written keep the old name, and that is as it should be. If the old name turns up in new entries, restart the service that writes them.
- MariaDB and MySQL derive default file names such as the error log and the binary log from the hostname, unless the paths are stated explicitly in the configuration.
- Java applications.
InetAddress.getLocalHost()throws ajava.net.UnknownHostExceptionas soon as the machine name fails to resolve. Application servers are affected just as much as game servers. - Monitoring agents often carry the name in their own configuration file. Otherwise the same server turns up twice after the rename.
systemctl list-units --type=service --state=running
If a maintenance window is coming up anyway, a reboot is the most complete solution. How to register your own programs properly as a unit, so that they survive a reboot, is covered in Creating a systemd service.
Mail server: the name that others see
When mail is sent, the hostname stops being cosmetic. The remote end sees it in the EHLO and checks it. Three things have to fit together:
- The name your mail server announces itself with (in Postfix,
myhostname). - The PTR record of your IP address, that is the reverse lookup.
- An A record (with IPv6, an AAAA record) for exactly that name, pointing back to the same address.
If the chain does not close, many recipients downgrade the message or reject it. Checking without additional packages:
hostname -f
getent hosts 203.0.113.10
getent hosts srv01.example.com
You get more detail with dig from the bind9-dnsutils package:
apt install -y bind9-dnsutils
dig +short -x 203.0.113.10
dig +short srv01.example.com A
The PTR record does not belong to the server. It hangs off the IP address and is maintained by the operator of the network, at KernelHost through the customer panel. No hostnamectl call changes anything about it, and this is exactly where renames go wrong on mail servers.
Postfix does not pick up the rename on its own. On Debian and Ubuntu the package writes a fixed value into /etc/postfix/main.cf during setup, and next to it sits /etc/mailname with the name that Postfix uses as the sender domain for local mail. Both stay exactly as they were:
postconf myhostname mydomain myorigin
cat /etc/mailname
Adjust and restart, keeping in mind that /etc/mailname is a decision of its own and does not necessarily carry the same value as myhostname:
postconf -e "myhostname = srv01.example.com"
postfix check
systemctl restart postfix
SPF, DKIM and DMARC, by contrast, hang off the sender domain and not off the hostname. So a rename does not fix any delivery problem that has its cause there.
Certificates
The system name appears in no certificate, because a certificate covers the DNS names that were in the request. Even so, a rename makes itself felt in three places.
First, in the request. If you get a certificate for the server name itself, for the mail server for example, the name has to be in DNS before the certificate authority looks it up. Otherwise the run ends with a message such as DNS problem: NXDOMAIN looking up A for srv01.example.com. The A record belongs before the request, not after it.
Second, with the certificates you already have. They keep running on the old name and keep being renewed until you remove them:
certbot certificates
certbot delete --cert-name old.example.com
Only delete once no service points at the path any more, otherwise the web server will not start on its next reload.
Third, at the mail server. If Postfix announces itself with the new name but presents a certificate for the old one, remote systems that check the name strictly will fail. The certificate and myhostname belong on the same name.
There is no connection between the system name and server_name in nginx. nginx decides on the basis of the Host header of the request, not on the basis of the machine name. If you get the wrong site served after a rename, look in the server configuration, not at the hostname. The basics on that are in Installing nginx on Debian and Ubuntu.
Common errors and fixes
sudo: unable to resolve host srv01: Name or service not known
The machine name is not in /etc/hosts and is unknown in DNS. Add the line 127.0.1.1 srv01.example.com srv01. As long as it is missing, every call waits for a resolver timeout.
hostname: Name or service not known
The answer from hostname -f when the kernel name cannot be resolved anywhere. Same cause, same fix. Afterwards check with getent hosts "$(hostname)" whether something really comes back.
Could not set property: Access denied
hostnamectl was called without root privileges, or the call ran in a container that is not allowed to change the kernel name. On your own server, sudo helps. In an unprivileged container you set the name in its configuration, not inside it.
fatal: unable to use my own hostname
From the Postfix log. The value in myhostname does not resolve. Add the entry to /etc/hosts, then run systemctl restart postfix.
504 5.5.2 <srv01>: Helo command rejected: need fully-qualified hostname
Your mail server announces itself with the short name, and the remote end demands a fully qualified one. Set myhostname to the FQDN and restart Postfix.
450 4.7.1 Client host rejected: cannot find your reverse hostname
There is no PTR record for your IP address, or it points nowhere. This cannot be fixed on the server, only by the operator of the IP network.
java.net.UnknownHostException: srv01
A Java application tried to resolve its own name and failed. /etc/hosts again. Once the entry is in place, the application has to be restarted.
DNS problem: NXDOMAIN looking up A for srv01.example.com
The new name does not exist in DNS yet. Create the A record, wait for it to propagate, repeat the request.
The name is back to the old one after the reboot.
Check in this order: is preserve_hostname: true set under /etc/cloud/cloud.cfg.d/, does the DHCP client no longer deliver a name, does /etc/hostname actually contain the new name. If hostnamectl shows a Transient hostname: line after booting, one of these sources is still at work.
/etc/hosts is wiped clean again after every reboot.
manage_etc_hosts: true is set, and cloud-init regenerates the file from the template. Switch it to localhost or maintain the template.
Differences between distributions
| System | cloud-init out of the box | rsyslog | Notable difference |
|---|---|---|---|
| Debian 13 (trixie) | only on cloud images | missing in minimal installations | logs in the journal instead of in /var/log/syslog |
| Debian 12 (bookworm) | only on cloud images | depends on the installation variant | same as Debian 13 |
| Ubuntu 24.04 LTS | yes, preserve_hostname: false | present | systemd-resolved active, resolve appears in the hosts: line |
| Ubuntu 22.04 LTS | yes, preserve_hostname: false | present | same as Ubuntu 24.04 |
The same on all four systems: hostnamectl never changes /etc/hosts, and no tool of the operating system creates DNS or PTR records. Those two steps stay manual work.
The final check
A command without an error message is no proof. The only reliable test is the reboot, followed by these five lines:
hostnamectl --static
hostname -f
getent hosts "$(hostname)"
time sudo -n true
grep -c '^127\.0\.1\.1' /etc/hosts
What you expect: the new short name, the new fully qualified name, one line from /etc/hosts, a runtime well under a tenth of a second, and exactly one line for 127.0.1.1. Only when all five are correct is the rename complete, and only then may you close the second terminal window.
Frequently asked questions
Why is my hostname back to the old one after a reboot?
Why does sudo report "unable to resolve host" and suddenly need seconds?
Does /etc/hostname take the short name or the fully qualified name?
Why 127.0.1.1 in /etc/hosts and not 127.0.0.1?
Does hostnamectl change /etc/hosts as well?
Is the hostname command enough for a permanent change?
What else do I have to adjust for my mail server?
2026 KernelHost GmbH. All rights reserved. This guide is protected by copyright. Republishing it on other websites, in whole, in part or in edited form, is not permitted without our written consent. Quoting with a source credit and a link is expressly welcome.

