Hostname misconfiguration is the silent saboteur of TLS certificates, email deliverability, monitoring agent enrolment, and Kerberos authentication. The host's idea of itself, the DNS forward record, and the reverse PTR record must all agree โ and on most fleets, at least one of those three is wrong on at least one host. This guide focuses on automated verification: the commands that surface mismatches and the script that catches them before users do.
The three sources of truth
- Local hostname โ what
hostname -freturns; sourced from/etc/hostname+/etc/hosts+ DNS. - Forward DNS โ what
dig +short A <fqdn>returns; the public source of truth. - Reverse DNS (PTR) โ what
dig +short -x <ip>returns; controlled by whoever delegates the IP block.
All three should match. Mail servers in particular reject mail from hosts where the HELO name does not match the reverse PTR โ the #1 cause of "my notifications go to spam."
Reading what the host thinks
hostnamectl status
hostname # short name
hostname -f # FQDN (this is what services use)
hostname -d # domain part only
hostname -A # all FQDNs (multi-homed hosts)
hostname -i # IP per /etc/hosts (legacy)
hostname -I # all routable IPs
cat /etc/hostname
grep $(hostname) /etc/hosts
Verifying forward DNS
dig +short A $(hostname -f)
dig +short AAAA $(hostname -f)
host $(hostname -f)
getent hosts $(hostname -f) # uses nsswitch order
If getent returns a different IP than dig, your /etc/hosts is overriding DNS โ sometimes intentional (split-horizon, dev workstations), often a leftover from a past migration.
Verifying reverse DNS
ip=$(hostname -I | awk '{print $1}')
dig +short -x "$ip"
host "$ip"
nslookup "$ip"
The PTR query should return your FQDN. If it returns nothing, the network operator who manages your IP block has not configured PTR โ request it. If it returns a different name (like 192-0-2-10.cust.isp.net), mail and Kerberos will fail.
The complete verification routine
#!/bin/bash
fqdn=$(hostname -f)
short=$(hostname -s)
ip4=$(hostname -I | tr ' ' '\n' | grep -E '^[0-9.]+$' | head -1)
ip6=$(hostname -I | tr ' ' '\n' | grep -E '^[0-9a-f:]+$' | head -1)
ok() { printf ' \e[32mOK\e[0m %s\n' "$*"; }
fail() { printf ' \e[31mFAIL\e[0m %s\n' "$*"; PROBLEMS=$((PROBLEMS+1)); }
PROBLEMS=0
echo "Host identity:"
echo " fqdn=$fqdn"
echo " short=$short"
echo " ipv4=$ip4 ipv6=$ip6"
echo
echo "Hostname checks:"
[[ "$fqdn" == *.* ]] && ok "FQDN contains a domain" || fail "FQDN has no domain"
[[ "$short" != "localhost" ]] && ok "short hostname is not localhost" || fail "hostname is localhost"
echo
echo "Forward DNS:"
fwd=$(dig +short A "$fqdn" | head -1)
if [ -n "$fwd" ]; then
ok "forward A: $fwd"
[ "$fwd" = "$ip4" ] && ok "forward matches local IPv4" || fail "forward $fwd != local $ip4"
else
fail "no forward A record for $fqdn"
fi
echo
echo "Reverse DNS:"
if [ -n "$ip4" ]; then
rev=$(dig +short -x "$ip4" | sed 's/\.$//')
if [ -n "$rev" ]; then
ok "reverse PTR: $rev"
[ "$rev" = "$fqdn" ] && ok "reverse matches FQDN" || fail "reverse $rev != fqdn $fqdn"
else
fail "no reverse PTR for $ip4"
fi
fi
echo
echo "Roundtrip:"
ssh -o BatchMode=yes -o ConnectTimeout=3 "$fqdn" hostname 2>/dev/null \
| grep -q "$short" && ok "ssh roundtrip works" || fail "ssh to $fqdn failed or returned wrong name"
echo
[ "$PROBLEMS" -eq 0 ] && echo "All checks passed." || echo "$PROBLEMS problem(s) detected."
exit "$PROBLEMS"
Drop into /usr/local/sbin/check-hostname, run from a systemd timer weekly, ship output to your log collector. Any non-zero exit is an actionable ticket.
Common misconfigurations and fixes
| Symptom | Likely cause | Fix |
|---|---|---|
hostname -f returns "localhost" | /etc/hosts missing FQDN line | Add 192.0.2.10 host.example.com host to /etc/hosts |
| Forward DNS returns wrong IP | DNS not updated after server move | Update DNS A record at your provider |
| Reverse DNS missing | ISP/cloud provider did not delegate PTR | Open ticket with the IP-block owner |
| Mail rejected as spam | HELO ≠ reverse PTR | Set Postfix myhostname= to FQDN; confirm PTR matches |
| Kerberos auth fails | Forward and reverse mismatch | Align DNS or use FQDN explicitly in keytab |
Cloud-init traps
On AWS, GCP, Azure, and OpenStack, cloud-init may rewrite /etc/hostname and /etc/hosts on every boot from instance metadata. Pin behaviour:
# /etc/cloud/cloud.cfg.d/99-hostname.cfg
preserve_hostname: true
manage_etc_hosts: false
fqdn: web-01.prod.example.com
hostname: web-01
Common pitfalls
- Using underscores in hostnames; legal in DNS, rejected by many TLS implementations.
- Setting
127.0.1.1in/etc/hostsfor the FQDN (Debian default) โ many services bind only to loopback. - Forgetting to reload services after hostname change; the running process keeps the old name.
- Trusting only one of the three checks (local, forward, reverse).
Hostname verification is the unloved chore that prevents an entire category of "the platform is acting weird" tickets. Run the verification script weekly on every host, alert on any failure, and fix DNS gaps as you find them โ your TLS certificates, mail server reputation, and on-call sleep all benefit.