Fix a duplicate machine-id after cloning a VPS
Two clones sharing one /etc/machine-id can fight over a DHCP lease. Regenerate it safely, and truncate it before you snapshot a golden image.
What /etc/machine-id is, and why a duplicate matters
A cloned VPS boots with the same /etc/machine-id as the server it was cloned from, and that value is supposed to belong to exactly one installation. The fix is four commands: empty the file, remove the D-Bus copy if it is a real file, regenerate, reboot. The reboot is the step people skip, and it is the step that makes the change take effect.
/etc/machine-id holds a newline-terminated, lowercase, 32-character hexadecimal string. Decoded, that is a 16-byte (128-bit) value. The machine-id(5) manual page calls it confidential and says it must not be exposed on the network, because anything that reads it can recognise your machine again later. It is written once, when the system is installed, and nothing changes it afterwards.
Three identifiers get confused here, so it is worth separating them. The hostname is a label you choose and can change at any time. The DMI (desktop management interface) product UUID in /sys/class/dmi/id/product_uuid comes from the hypervisor and is readable only by root. The machine ID is the third one: the operating system generates it, and every user on the box can read it.
What actually reads the machine ID
The DHCP client identifier. This is the one that hurts. systemd.network(5) documents ClientIdentifier= in the [DHCPv4] section as defaulting to duid, which sends an RFC 4361 client ID built from an IAID and a DUID (DHCP unique identifier). networkd.conf(5) documents the default DUID type as vendor, where the DUID value is generated using 43793 as the vendor identifier (systemd) and hashed contents of the machine ID. DHCPv6 uses the same DUID. Two clones with the same machine ID hash to the same DUID, and if they also kept the same interface name they send a byte-identical client identifier. The DHCP server then sees one client instead of two and offers both boxes the same lease. The symptom is an address that moves between the two servers, or one server losing its address whenever the other renews.
journald. Journal files live in /var/log/journal/<machine-id>/. The directory is literally named after the ID. Ship two clones' journals to one collector and they land under one directory and read as one host.
D-Bus. /var/lib/dbus/machine-id is where this file format started. On Debian and Ubuntu it is a symlink to /etc/machine-id. On some systems it is a separate real file holding its own copy, and that copy is the trap in the procedure below.
Per-host agents. Monitoring agents, licence checks, inventory tools and backup clients often use the machine ID as their default host identifier, because it is stable and needs no configuration. Two servers reporting one identity means one merged metrics series, or one licence seat covering two machines. Check how your agent derives its host ID rather than assuming it uses the hostname.
How to tell whether you have a duplicate
Run this on both servers and compare the output.
cat /etc/machine-id
ls -l /var/lib/dbus/machine-id
sudo cat /sys/class/dmi/id/product_uuidIdentical machine IDs on two live servers means one was cloned from the other. hostnamectl prints the same value on its Machine ID: line if you prefer one command.
The ls -l result decides the next step. A symlink looks like this:
lrwxrwxrwx 1 root root 15 Aug 21 09:12 /var/lib/dbus/machine-id -> /etc/machine-idA line starting with -rw-r--r-- means it is a real file holding its own copy of the old ID. You have to remove it, because systemd-machine-id-setup reads it before it does anything else.
The product UUID matters too. systemd-machine-id-setup(1) uses the KVM UUID before it falls back to random generation, so if your provider handed both clones the same SMBIOS (system management BIOS) UUID, regenerating gives you the same machine ID twice. Different product UUIDs on the two boxes mean you have nothing to worry about here.
Regenerate the machine ID on a cloned VPS
Order matters. systemd-machine-id-setup(1) states that if a valid D-Bus machine ID is already configured for the system, that D-Bus machine ID is copied and used to initialise /etc/machine-id. Leave a real /var/lib/dbus/machine-id in place and you will regenerate the exact value you were trying to get rid of.
sudo truncate -s 0 /etc/machine-id
sudo rm -f /var/lib/dbus/machine-id # only if ls -l showed a real file
sudo systemd-machine-id-setup
sudo ln -sf /etc/machine-id /var/lib/dbus/machine-id
cat /etc/machine-idTruncating first is required, because the tool acts only when the file is missing or empty and does nothing to a file that already holds a valid ID. systemd-machine-id-setup reports what it did on standard error. On a KVM VPS you will usually see:
Initializing machine ID from KVM UUID.Initializing machine ID from random generator. is the message when no hypervisor UUID is available. Either result is fine, as long as cat /etc/machine-id now prints something different from the other server.
The symlink keeps D-Bus and systemd on one value. If you prefer a separate real file, run sudo dbus-uuidgen --ensure instead: it creates the file with a new UUID when the file does not exist. If dbus is not installed there is no /var/lib/dbus directory at all, ln fails with No such file or directory, and you can skip both of those lines.
Then reboot.
sudo rebootWhy the reboot is not optional
Every process that already read the old value is still using it. sd_id128_get_machine() caches the ID inside the calling process, so a running daemon never notices that the file changed. journald already has /var/log/journal/<old-id>/system.journal open and keeps appending to it. systemd-networkd worked out its DUID when it started and keeps sending the old client identifier on every renewal, which is usually the exact failure you set out to fix. D-Bus read its ID at startup too. You can restart services one at a time, but you will miss one, and PID 1 is holding the old value as well.
After the reboot, check both halves:
cat /etc/machine-id
ls /var/log/journal//var/log/journal/ now holds a second directory named after the new ID, and fresh entries go there. Plain journalctl reads the current machine's directory only, so your pre-clone history disappears from the default view. It is still on disk: journalctl --merge reads every journal directory, including the old one. Delete the old directory once you are sure you no longer need those logs.
This is also why you cannot rehearse the procedure in a container. A container shares the host kernel and never boots its own PID 1, and the reboot is the whole point of the exercise. Test it the way it happens in production: clone a VM, run the commands, reboot, then compare the ID against the source machine.
Truncate before you snapshot, not after you clone
Fixing clones one at a time works. Fixing the image is better, because every server restored from a bad snapshot inherits the same value. Make this the last thing you do before you shut the template down.
sudo truncate -s 0 /etc/machine-id
sudo rm -f /var/lib/dbus/machine-id
sudo ln -s /etc/machine-id /var/lib/dbus/machine-id
sudo shutdown -h nowEmpty the file. Do not delete it. machine-id(5) recommends an empty file for images used on multiple machines, because an empty file in place allows a temporary file to be bind-mounted over the real file when the image is used read-only. On a read-only /etc, the ID generated at boot lives in that temporary file, and systemd-machine-id-setup --commit writes it down once the filesystem is writable.
One side effect to plan for: an unpopulated machine ID marks the next boot as a first boot, so units carrying ConditionFirstBoot=yes run on that boot and are skipped on every boot after it. See what your image would run with grep -rl ConditionFirstBoot /usr/lib/systemd/system/ before you build the template.
A template and a snapshot are different objects, and the difference decides whether identity gets copied. A template is a build artifact you prepare on purpose, while a snapshot is a point-in-time copy of one running server and carries that server's identity along with its data.
Why cloud images get this right and your snapshot does not
Distribution cloud images are built to be cloned, so they ship with the machine ID unpopulated and the first boot fills it in. cloud-init has a documented step for exactly this. cloud-init clean --machine-id sets /etc/machine-id to the literal string uninitialized on systemd systems, and the cloud-init CLI reference describes it as best practice when cloning a golden image, so the next boot of that image generates a unique machine ID.
A snapshot you took yourself is a different story. The file was already populated when you clicked snapshot, so every server restored from it carries that one value, and nothing in the restore path clears it. This is the same class of problem as moving a running server to a new VPS, where the copy is faithful and the identity is the part you did not want copied.
What else a clone duplicates
- SSH host keys.
/etc/ssh/ssh_host_*is copied too, so both servers present the same fingerprint to clients. Remove those files and runsudo ssh-keygen -A, orsudo dpkg-reconfigure openssh-serveron Debian and Ubuntu. Your clients will warn about a changed host key afterwards, which is the correct behaviour. - The hostname. Set it with
sudo hostnamectl set-hostname app02, then check that/etc/hostsstill resolves the new name. - Static network configuration. A clone of a box with a static address collides with the original the moment it comes up. Read
/etc/netplan/before the clone joins the network. - The clock. A restored snapshot resumes with the time it had when the snapshot was taken. A large clock jump on a restored VPS breaks TLS certificate validation and scrambles log order until time sync catches up.
Work through the first ten minutes checklist for a new VPS on the clone as well. A cloned box inherits the source box's user accounts, SSH keys, firewall rules and scheduled jobs, and none of that was reviewed for the job the clone is about to do.
FAQ
Do I have to reboot after changing /etc/machine-id?
Yes. Processes read the machine ID once and cache it, so the new value reaches nothing that is already running. journald keeps writing to the journal directory named after the old ID, and the DHCP client keeps sending a client identifier derived from the old value, which is usually the reason you changed it. Restarting individual services fixes some of them, but PID 1 holds the old value too. Reboot, then confirm with cat /etc/machine-id and by comparing against the other server.
Is /etc/machine-id the same as the hardware UUID?
No. The DMI product UUID in /sys/class/dmi/id/product_uuid comes from the hypervisor and is readable only by root. The machine ID is generated by the operating system and lives in a plain file any user can read. They connect in one direction: on a KVM guest, systemd-machine-id-setup seeds a new machine ID from the hypervisor UUID when there is no D-Bus ID to copy. If two clones share a product UUID, they will regenerate the same machine ID, so compare that file as well before you trust the result.
Should I delete /etc/machine-id or leave it empty?
Leave it empty when you are preparing an image. machine-id(5) prefers an empty file, because systemd can bind-mount a temporary file over it when the image runs with a read-only /etc. Deleting the file works on a writable system and some clone scripts do it that way, but the empty file is the safer default. cloud-init writes the word uninitialized into the file for the same purpose.
Why did my two cloned servers get the same DHCP address?
Because both sent the same client identifier. systemd-networkd defaults to ClientIdentifier=duid for DHCPv4, and the default DUID is built from a hash of /etc/machine-id, so identical machine IDs produce identical identifiers on clones that also kept the same interface name. The DHCP server matches on that identifier, treats both requests as one client, and hands out one lease. Give each box its own machine ID and reboot both. If the server still offers the old address, clear the stale lease on the DHCP server itself.