Dynamic Hostname Generation
This module provides runtime-generated, human-readable hostnames based on permanent hardware properties like MAC address or computer serial number.
Overview
Section titled “Overview”The dynamic hostname system consists of three modules:
dynamic-hostname.nix- Generates and exports the hostname on the host systemvm-hostname-export.nix- Makes the hostname available to VMs via environment variablesvm-hostname-setter.nix- Sets the actual VM hostname from the shared hostname file
Features
Section titled “Features”- Hardware-based: Deterministic hostname generation from stable hardware properties (DMI serial/UUID, MAC address, or machine-id as fallback)
- Human-readable: Format like
ghaf-1234567890where digits are derived from hardware - Propagated: Automatically shared with guest VMs through
/persist/commonvirtiofs mount - Non-invasive: Keeps static
networking.hostNameunchanged on host for network topology - Network-ready: NetVM uses the dynamic hostname for DHCP and external network services
- Fully deterministic: Hostname, device-id, and all VM machine-ids derived from hardware (no random values)
On Host
Section titled “On Host”Enable the dynamic hostname module in your host configuration:
{ ghaf.identity.dynamicHostName = { enable = true; source = "hardware"; # Optional: "hardware" (default), "static", or "random" prefix = "ghaf"; # Optional: default is "ghaf" digits = 10; # Optional: default is 10 };}Alternative configurations:
For static hardware ID (manual configuration):
{ ghaf.identity.dynamicHostName = { enable = true; source = "static"; staticValue = "my-unique-identifier"; };}For random ID (generated once and persisted):
{ ghaf.identity.dynamicHostName = { enable = true; source = "random"; };}This will:
- Generate a hostname like
ghaf-1234567890at boot - Export it to
/run/ghaf-hostnameand/var/lib/ghaf/identity/hostname - Share it via
/persist/common/ghaf/hostnamefor VMs - Make
$GHAF_HOSTNAMEenvironment variable available in shells - Host keeps static hostname “ghaf-host” for internal networking
In VMs
Section titled “In VMs”For VMs that need the hostname as an environment variable only (e.g., GUIVM):
{ ghaf.identity.vmHostNameExport = { enable = true; };}This makes the $GHAF_HOSTNAME environment variable available in the VM, reading from /etc/common/ghaf/hostname.
For VMs that need to set their actual hostname (e.g., NetVM for DHCP/network services):
{ ghaf.identity.vmHostNameExport = { enable = true; }; ghaf.identity.vmHostNameSetter = { enable = true; };}This sets the VM’s actual hostname from the shared file, which is useful for network services like DHCP client identification. It also configures NetworkManager (if enabled) to not override the hostname.
Hardware ID Source Options
Section titled “Hardware ID Source Options”The module supports three different sources for generating the hardware ID:
hardware (default)
Section titled “hardware (default)”Best-effort hardware detection that tries multiple sources in this priority order:
- DMI product serial (
/sys/class/dmi/id/product_serial) - DMI product UUID (
/sys/class/dmi/id/product_uuid) - Disk UUID (first available from
/dev/disk/by-uuid/) - First non-loopback MAC address (from
/sys/class/net/*/address) - Machine ID (
/etc/machine-id) as last resort
static
Section titled “static”Use a user-provided static value. Requires setting staticValue:
ghaf.identity.dynamicHostName.source = "static";ghaf.identity.dynamicHostName.staticValue = "my-unique-id";random
Section titled “random”Generate a random value on first boot and persist it to /var/lib/ghaf/identity/random-seed. The same random value is used across reboots:
ghaf.identity.dynamicHostName.source = "random";Implementation Details
Section titled “Implementation Details”- Uses CRC32 checksum modulo 10^N (default N=10) for deterministic digit generation
- Runs as a systemd oneshot service early in boot on the host
- Static
networking.hostNameremains as “ghaf-host” on the host for internal network topology - Host does not change its own hostname - only generates and shares the identity
- NetVM sets its actual hostname from the shared file for external network services
- VMs receive the hostname via existing
/persist/common→/etc/commonvirtiofs share - Environment variables are set via
environment.extraInitfor reliable shell initialization - NetworkManager is configured with
hostname-mode = "none"to prevent overriding the dynamic hostname - The hostname setter service runs before NetworkManager to ensure proper DHCP client identification
- All identity generation (hostname, device-id, machine-ids) happens atomically in single script
- VM machine-ids are deterministic MD5 hashes of (hardware key + VM name), not random UUIDs
- Uses sysfs directly for hardware detection (no dependency on iproute2 or other heavy tools)
Files Generated
Section titled “Files Generated”On Host
Section titled “On Host”/run/ghaf-hostname- Symlink to current hostname/var/lib/ghaf/identity/hostname- Generated hostname/var/lib/ghaf/identity/id- Numeric ID portion/persist/common/ghaf/hostname- Shared with VMs/persist/common/ghaf/id- Shared numeric ID/persist/common/device-id- Hardware-based device ID (hex format with dashes)/persist/storagevm/<vm-name>/etc/machine-id- Deterministic machine-id for each VM
In VMs
Section titled “In VMs”/etc/common/ghaf/hostname- Mounted from host via virtiofs/etc/common/ghaf/id- Mounted from host via virtiofs$GHAF_HOSTNAME- Environment variable- NetworkManager configuration (if
vmHostNameSetteris enabled) - Prevents hostname override
Example
Section titled “Example”On a laptop with serial number ABC123XYZ:
# On ghaf-host$ cat /run/ghaf-hostnameghaf-1234567890
$ hostnameghaf-host
$ echo $GHAF_HOSTNAMEghaf-1234567890
# On NetVM$ cat /etc/common/ghaf/hostnameghaf-1234567890
$ hostnameghaf-1234567890
$ echo $GHAF_HOSTNAMEghaf-1234567890
# In GUIVM$ cat /etc/common/ghaf/hostnameghaf-1234567890
$ hostnamegui-vm
$ echo $GHAF_HOSTNAMEghaf-1234567890Collision Probability
Section titled “Collision Probability”With 10 digits (default), there are 10 billion possible hostnames, which provides excellent uniqueness even for very large fleets. If you need fewer digits for brevity, you can reduce the digits option:
ghaf.identity.dynamicHostName.digits = 6; # 1 million possibilities- The static
networking.hostName = "ghaf-host"is intentionally unchanged on the host to preserve internal network topology and host mappings - The host does not change its own hostname - it only generates the identity
- NetVM sets its hostname to the generated value for use in DHCP client identification and external network services
- Other VMs (like GUIVM) keep their static hostnames but have access to the hardware-based identity via environment variables
- The shared directory
/persist/commonmust exist on the host (automatically created by the module)
Use Cases
Section titled “Use Cases”- DHCP Client Identification: NetVM uses the unique hostname when requesting DHCP leases, allowing network administrators to identify specific devices
- Network Service Identification: External services see a consistent, hardware-based hostname that persists across reboots
- Logging and Monitoring: All VMs can include the hardware-based identity in logs via
$GHAF_HOSTNAME - User Visibility: Users can identify their specific hardware instance across host and VMs
- Network Troubleshooting: Consistent hostname helps with debugging network issues and tracking device behavior
- Reproducible Testing: Deterministic identities allow consistent testing environments across rebuilds
- Fleet Management: Same hardware always produces same identities for reliable device tracking
Technical Details
Section titled “Technical Details”NetworkManager Integration
Section titled “NetworkManager Integration”When vm-hostname-setter is enabled on a VM with NetworkManager, the module:
- Sets
networking.networkmanager.settings.main.hostname-mode = "none"to prevent NetworkManager from managing the hostname - Ensures the
set-dynamic-hostnameservice runs beforeNetworkManager.service - Allows NetworkManager to use the hardware-based hostname for DHCP requests without modifying it
This ensures that the dynamic hostname is preserved even when NetworkManager obtains a DHCP lease or connects to different networks.
Virtiofs Share
Section titled “Virtiofs Share”The /persist/common directory on the host is mounted as /etc/common in VMs using virtiofs. This share must be configured in the VM’s microvm.shares configuration:
{ tag = "ghaf-common"; source = "/persist/common"; mountPoint = "/etc/common"; proto = "virtiofs";}NetVM and GUIVM have this share configured automatically.