We previously made sure our machine can access the internet. In this post, we’ll configure our machine so that we can access it from the local network, without ever knowing its IP address.
Hi. What’s your name?
First of all, we need to set a hostname for our machine. We want to access our machine using an easy to remember name instead of its IP address. It’s so much easier to
ping centosvm instead of
ping 192.168.1.42 isn’t it? Plus, the IP address might change, but we won’t care since all we need to know is the hostname to access the machine.
Setting a hostname will not actually do anything by itself. Other computers will not be aware of this name, just because we set one. However, CentOS (or any other operating system) might use this name internally or to conveniently “advertise” itself to the network, or we can manually set up services that will do this on our behalf.
Now, according to the RHEL Documentation on host names (make sure you read the whole chapter, it’s very short), there are three different hostnames a system can have, and there are three different ways to set them.
There are three kinds of hostnames (according to the RHEL documentation). Static, pretty, and transient. Static is the one we’re interested in, as it’s the one that the rest of them fallback to. Pretty, is the one that the user sees, just in case you want it to be different. So for example, the static hostname can be “centos7vm” (only latin letters, digits, dots, dashes and underscores are allowed, along with some other restrictions), while the pretty hostname can be “CentOS 7 Virtual Machine Testbed“. Or you know, both can just be “centos7vm“… whatever…
And finally, transient… now, the documentation says the transient hostname is maintained by the kernel. Why? I don’t know, nor could I find any more information by googling it. Why won’t the kernel use the static hostname? Don’t look at me.
Anyway. We can set a hostname using either
nmcli. On both the documentation pages of nmtui and nmcli it mentions that “at time of writing, changing the host name in this way will not be noticed by hostnamectl“. This leads me to believe that
hostnamectl is the most appropriate tool to handle this job, although it’s doable with the others as well.
So, according to the documentation, we need to issue
hostnamectl status or just
hostnamectl (the status is implied) in order to see our current hostname.
localhost.localdomain is default to most Linux distributions, or at least the ones I’ve come across. Now, let’s change this bad boy.
I want to be able to ssh from my laptop into the VM by typing
ssh devvm as in “Development Virtual Machine“. That’s my static and pretty hostnames right there! Let’s type the following commands (note that the quotes are required if you want spaces in the pretty hostname):
hostnamectl set-hostname "Development Virtual Machine" hostnamectl status
We see that there is a new line on the status output, that says our pretty hostname is exactly what we typed, while the static hostname is a sanitized version of it,
developmentvirtualmachine, with spaces and capitalization removed. I however, don’t want to be typing this humongous hostname, so, let’s change it to
hostnamectl set-hostname devvm --static hostnamectl status
We can now see the static hostname changed to
devvm, as well as a new line added with the Transient hostname set to
developmentvirtualmachine. Why? I don’t know. Moving on.
Connect using the hostname
We’ve set a hostname for our machine. Great. Now, if you try to ping it from you host computer (i.e. the laptop that runs the virtual machine) you’ll get something like this:
Computers don’t magically know each other’s names. They need to somehow translate those names to IP addresses. There are various ways to achieve this, each one having its most appropriate use-case. Just read a few of the answers other users got when asking the same question. Specifically, read this answer as it’s better written than I ever could have written in.
In short, we are interested in Multicast DNS (mDNS for short). It does not require a server such as DNS, it does not require us modifying any files every time an IP address changes (and in the case of our VM, most probably on every restart), and it works with Linux, Mac and Windows. In short, it requires zero configuration! The perfect thing!
The software that implements the mDNS protocol for Linux is called Avahi. Let’s go and install it without delay! Logged in as root (yeah yeah, I know it’s not safe. We’ll stop using the root user when we’ll be done with most base system configuration), type
yum install avahi
Yum will determine the fasts mirror, will fetch information on the package we requested, check its dependencies, and ask us whether we want to install avahi and update its dependencies. Just type a
y and press enter to confirm. It will then ask us to import a GPG key, just say yes to that to. After a few seconds, avahi should be installed on your system.
Now, avahi makes our hostname discoverable by appending .local at the end, so I should be able to
ping devvm.local successfully. This is not the case however, since the avahi daemon does not run yet. Let’s reboot the VM, just in case the service is set to run on each boot.
Just a sidenote here that we can avoid rebooting every now and then, by restarting the various services (or daemons). However, I don’t want to mess around with systemd just now, and want to be sure whenever I start the VM everything works as expected. So, just reboots for a little while longer. They are very fast anyway.
In order to determine if avahi is going to be starting each time the machine starts, we can type
systemctl status avahi-daemon.service and we’ll get some information on the specific service. On the end of the Loaded: line we see the word enabled which means avahi is set to run on startup. If it was already running, we would see quite a lot more information.
Let’s reboot to confirm that it actually runs after a restart. Once the machine reboots, I run
nmcli d to make sure it’s connected, and then
systemctl status avahi-daemon.service to see if avahi is running. Everything looks perfect!
Let’s try and ping our VM from our host (i.e. my laptop): ping devvm.local
Argh! What’s wrong?
Let’s (virtually) disconnect the network cable and then reconnect it to see what happens. On your running virtual machine window, you’ll find a series of icons on the lower left border. Find the one that looks like two computer monitors. If you hover over it, it will read something similar to “Indicates the activity of the network interfaces:“. Click on it and then select “Connect Network Adapter” so as to uncheck it. Run
nmcli d continuously until the state reads unavailable (so we know linux got notified of the disconnect) and then go back and re-select “Connect Network Adapter” so it’s checked. Again, run
nmcli d to make sure we’re reconnected. Run
systemctl status avahi-daemon.service -l (that’s a lower-case L, it shows the full messages instead of truncating them) and we’ll see something similar to the screenshot below.
Four consecutive lines inform us that avahi understood the disconnect: “Withdrawing address record…“, “Leavind mDNS multicast group…“, “Interface enp0s3.IPv4 no longer relevant for mDNS“. Then, four lines showing that avahi got notified of the reconnect: “Joining mDNS multicast group…”, “New relevant interface…“, “Registering new address record…”
Let’s try and ping our VM again. Nope. No luck.
Let’s restart only the avahi daemon. Type
systemctl restart avahi-daemon.service and press enter. There’s no feedback, therefore no errors. That’s good! Let’s try pinging the VM again. Oh wow! It works!
So, we’re now in a good path, i.e. we know avahi works alas, not exactly as it should after boot. Rebooting my virtual machine confirms it again doesn’t work, and the whole process before can bring it to a working state.
I scoured the internet with search terms such as “centos 7 avahi doesn’t work“, “centos 7 virtualbox avahi problems“, and all the other ways I could phrase my problem, but to no avail. Pretty much, I can’t really explain why avahi won’t work after boot,
Furthermore, I noticed that after 5 minutes or so, avahi would stop working again, i.e. I couldn’t ping the machine using its hostname. I was about to dump CentOS for Debian, when searching for the term centos 7 avahi stops working I stumbled on this thread which mentions the firewall. It actually makes sense. If the firewall is configured to block incoming connections to avahi, this explains why it won’t work in general. When restarting the avahi daemon, it probably initiates some connections so the firewall temporarily whitelists it, and then it appears as working. After a specific time frame, it’s again blacklisted. Perhaps, when the machine boots, avahi starts before the firewall, so the firewall never has the chance to listen to the internally-initiated connection by avahi, therefore it never temporarily whitelists it. It’s a plausible explanation for my issues.
This hypothesis seems to be supported by this article (found while searching for centos 7 avahi firewall), where the author immediately configures the firewall after installing avahi. Let’s do what he does to configure the firewall:
firewall-cmd --zone=public --permanent --add-service=mdns
Let’s reboot the machine and ping. It works! Let’s wait 5-10 minutes as well and ping again. It works again!
I thought this nightmare would never end! Woohoooooooooo!
Thank you for your post. The firewall was what I was missing also!
Very nice article, especially the detail you brought to it, the many links and also what you searched for on Google.
This article is missing info on nss-mdns. If you don’t have that along with avahi, it won’t work out of the box because your system only knows to use dns servers in your /etc/resolv.conf file (which is populated by NetworkManager)…
On some fresh installs of CentOS 7 Avahi is enabled by default (for instance the GNOME Live edition) but nss-mdns isn’t and isn’t available in the default repos…
Easiest way to add the required repo to your system is:
sudo yum -y install epel-release
Then just do:
sudo yum -y install nss-mdns
Your default firewall zone Public, should already allow the mdns service by default. You can check this using firewall-config from the command line.
Finally, a transient hostname is when your system was automatically assigned a hostname through DHCP (common in large enterprises)…
Thanks, firewall command fixed problem for me! It was very baffling – would reboot Redhat vm (under VMware Fusion), my first ssh using the name.local would work but subsequent ones didn’t until I’d rebooted. I’d figured the first one was somehow changing things for subsequent ones, didn’t realise it was time related (although I do now recall sometimes doing another successful ssh).
Fantastic, thank you!
Thank you, saved me from some headache!