Setting up a host
This page sets up one physical Linux server as a provider host, with the
steps that home and cloud hosts share. Becoming a provider
says what a host needs and which mode to choose. Every setting of
hypervisor.toml is listed in
Hypervisor configuration.
The checklist
Section titled “The checklist”- Confirming that KVM is available (Requirements)
- Installing the agent (Installing the agent)
- Preparing storage (Preparing storage)
- Creating the configuration, then adding the settings of home mode or cloud mode, and keeping the host’s state on its root pool’s drive (Creating the configuration)
- Enrolling the host, creating its enrollment token at this step (Enrolling once)
- Testing the agent in the foreground (Testing in the foreground)
- Enabling the systemd service (Running with systemd)
- Setting what the host earns (Pricing and SLA)
- Cloud host: registering its public addresses (Registering public addresses)
- Cloud host: making the checks that need no rental, while it is still paused (Checking a new host)
- Resuming new rentals (Controlling rental admission)
- Making the checks with a test VM, and pausing the host again if one fails (Checking a new host)
Requirements
Section titled “Requirements”The requirements are listed under Requirements at a glance. Before continuing, you can confirm that KVM is available:
test -c /dev/kvm && echo 'KVM is available'Choosing a network mode
Section titled “Choosing a network mode”You choose home mode or cloud mode before enrolling the host. The two are compared under Home host or cloud host.
Installing the agent
Section titled “Installing the agent”curl -fsSL https://api.gigahost.cloud/install/hypervisor.sh | sudo shThe agent is one binary, gigahost-hypervisor, built on Ubuntu 22.04 against
its glibc 2.35, so it runs on every supported distribution. It is published
on a signed release channel, and this one command installs it together with
its dependency installer and systemd unit.
- The script downloads the channel’s manifest and accepts it only if its
Ed25519 signature matches the release public key embedded in the script
(checked with OpenSSL 3, or with
python3where the OpenSSL is older). - It then downloads the release archive and accepts it only if its SHA-256 matches the signed manifest.
- Only then does it run the dependency installer and put
gigahost-hypervisorin/usr/local/sbin, the dependency installer beside it asgigahost-install-hypervisor-deps, and the unit in/usr/local/lib/systemd/system.
The website’s Provider page (/provider) and its Add a host page
(/provider/hosts/new) show the same command, with the requirements listed
apart (CPU: x86-64 with hardware virtualization; System: Ubuntu
22.04, 24.04 or 26.04, or Debian 12 or 13). The script does the signature
check itself; the website no longer shows the release key or manifest.
Updating the agent later is under
Updating the agent.
Checking the dependencies
Section titled “Checking the dependencies”sudo gigahost-install-hypervisor-deps --checkThe installer accepts only the distributions listed in the requirements, on amd64.
- It enables KVM/libvirt and installs the disk, image, and networking tools
used by the agent, including
smartmontoolsfor disk health. - It creates the state directories under
/var/lib/gigahost. --checkverifies an existing installation without changing the host.- The installer does not repartition disks, create storage pools, or change the management uplink.
A tmpfs /tmp
Section titled “A tmpfs /tmp”The installer makes one change to the system beside its packages. To make it by hand, run:
sudo mount -o remount,size=1G /tmpsudo systemctl mask tmp.mountDebian 13 and Ubuntu 26.04 mount /tmp as a tmpfs that may grow to half of
the RAM. What is written to a tmpfs is held in memory, the memory your host
sells to its guests. Whatever filled /tmp would take it from them, up to
the host running out of memory.
- The installer therefore caps a tmpfs
/tmpof more than 1 GiB at 1 GiB and maskstmp.mount, so that/tmpis on the root filesystem from the next boot, and says so. --checkreports a larger tmpfs/tmpwithout changing it, and Gigahost does not accept the enrollment of a host that has one.- A
/tmpon disk, or a tmpfs of 1 GiB or less, is left as it is.
CET shadow stacks
Section titled “CET shadow stacks”Gigahost keeps CET shadow stacks, a CPU feature, from every guest. Where
the host needs a kernel parameter for that, the dependency installer asks you
on the terminal, also under curl | sh, whether to add it to GRUB’s
configuration, and --check only reports. The enrollment asks too. To do it
yourself, run:
sudo gigahost-hypervisor shadow-stackssudo gigahost-hypervisor shadow-stacks --add-boot-parameter- A guest gets shadow stacks where the host’s Linux, 6.18 or later, virtualizes them for a CPU that has them.
- The agent turns them off in every guest’s CPU where the host’s libvirt and QEMU know them by name.
- Elsewhere only the kernel parameter
clearcpuid=519keeps them off, from the host’s next boot. The dependency installer says which in itscpuline.
What the commands answer, and what the parameter does, is under CET shadow stacks.
Turning off unattended upgrades
Section titled “Turning off unattended upgrades”Ubuntu’s images, and some providers’ Debian images, install
unattended-upgrades and run it daily. An upgrade may restart libvirt,
replace QEMU’s libraries under running guests or leave a new kernel waiting
for a reboot, on its own at any hour. The dependency installer warns in its
upgrades line where it runs, when installing and with --check, and
changes nothing about it, because the host is yours to run.
-
To keep the package lists fresh but the upgrade off, set
/etc/apt/apt.conf.d/20auto-upgradesto:APT::Periodic::Update-Package-Lists "1";APT::Periodic::Unattended-Upgrade "0"; -
To stop the timer, and to answer the package’s debconf question so that a reconfiguration does not switch it back on, run:
sudo systemctl disable --now apt-daily-upgrade.timerecho 'unattended-upgrades unattended-upgrades/enable_auto_updates boolean false' | sudo debconf-set-selections
Applying updates yourself is described under Applying system updates.
Preparing storage
Section titled “Preparing storage”-
You choose a layout for each pool, thin LVM or preallocated file storage, on a separate filesystem for guest storage where possible.
-
For a thin-LVM pool, LVM zeroing needs to be enabled before enrollment. To check it, and to enable it if needed, run:
lvs -o segtype,zero VG/POOLlvchange --zero y VG/POOL -
For a file-backed pool, you create its directory on the pool’s own filesystem, here one mounted at
/srv/gigahost-root:sudo install -d -m 0711 /srv/gigahost-root/root-images -
You add each pool to
hypervisor.toml. File-backed pools name their directory:[[file_storage_pools]]external_id = "root-images"kind = "root"directory = "/srv/gigahost-root/root-images"[[file_storage_pools]]external_id = "backups"kind = "backup"directory = "/srv/gigahost-backups"A thin-LVM pool is named by its volume group and thin pool, here as the root pool in place of the file-backed one above:
[[lvm_storage_pools]]external_id = "vg0/guest-root"kind = "root"
It is best not to advertise more usable capacity than the host can provide. Adding a backup pool to a host that is already enrolled is under Adding a backup pool to an enrolled host.
Storage layouts
Section titled “Storage layouts”Gigahost supports two guest root-storage layouts.
Thin LVM identifies a pool as volume_group/thin_pool.
- The pool needs to be sized so that all advertised guest disks and operational headroom fit on physical storage.
- Its metadata needs room for a thin volume for each VM the host can hold,
four for each logical CPU it sells, and a few of the host’s own: enrollment
works the need out with
thin_metadata_sizeand says how much is missing. - The configured thin pool needs to be dedicated to Gigahost and have LVM zeroing enabled.
Preallocated file storage places fallocate-reserved guest images in a dedicated filesystem.
- Its directory is created, and added to the configuration, before the agent starts.
- Every configured file pool needs a distinct filesystem, so capacity cannot be counted twice.
- A file-backed backup pool needs a filesystem of its own. When its directory is on the host’s root filesystem or on another pool’s filesystem, the agent takes it for a pool whose drive is not mounted (see A missing backup pool).
Pool kinds
Section titled “Pool kinds”Each pool has a kind:
- Exactly one root pool holds the guests’ root disks. On a cloud host it
also holds the 4 GiB root volume of the router VM. On every host it holds
32 GiB of scratch space for the backups of running guests: two scratches
of 16 GiB,
ghs-slot-0andghs-slot-1, where the blocks a guest overwrites during its backup are kept. - A backup pool holds the encrypted artifacts of local backups, each about the size of the guest’s root disk at most. Backup pools can use thin LVM or file storage.
The root pool’s backup scratch
Section titled “The root pool’s backup scratch”The root pool needs the 32 GiB of scratch space beside the root storage your capacity profile offers and the router’s volume. Enrollment checks that, and Gigahost does not accept a host whose root pool is too small, so that a running guest can be backed up whatever you have rented out.
- The agent makes the two scratches when it starts: in a file-backed root pool two files with all of their 16 GiB allocated, which it attaches as loop devices, and in a thin-LVM root pool two thin volumes with all of their blocks provisioned.
- They stay for the next backup, are no part of what the pool offers, and do not count toward the five percent of the root pool that has to stay free.
- The size of a scratch and their number are the same on every host and no setting of yours, so a renter does not need to know the host to know what a backup does.
A host makes two backups or restores at a time, of running guests or stopped ones, and further ones wait in the queue until one of the two is done.
A guest that overwrites more than 16 GiB of its disk while it is backed up fills its scratch. QEMU then pauses the guest, the backup reads the rest of the disk, and the agent resumes the guest when the backup ends. The guest’s writes are not lost, and it sees no error. A stopped guest is read without a scratch.
Backup pools
Section titled “Backup pools”A hosted backup needs no pool of its own, and a local backup needs a backup pool. Give the largest backup pool a little more than the largest root disk you offer, and more to keep several backups. A stored local backup keeps its room until it is deleted. Gigahost does not accept these backup requests, and answers each with the code shown:
| Answer | When |
|---|---|
local_backups_unavailable |
A local backup on a host without a backup pool |
backup_too_large_for_host |
A local backup whose artifact no backup pool could hold even when empty |
backup_storage_busy |
A local backup that fits only once other backups leave |
backup_pool_unavailable |
A restore of a local backup, or a new instance from one, whose backup pool the host is missing (see A missing backup pool) |
Each offering in the catalog shows renters, as backup_limits, which backups
of its root every host behind it has room for when nothing else holds its
backup pools.
A backup pool on hard disks works on one local backup or restore at a time: two at once would make the disks’ heads seek between them, and both would run far slower than one after the other. The agent tells from the disks below the pool, through LVM, software RAID and partitions, whether any of them rotates, and the host’s page shows such a pool as On hard disks. Hosted backups keep nothing in a backup pool, and a pool on SSD or NVMe works on two at a time, as the host does.
Creating the configuration
Section titled “Creating the configuration”-
To create private directories for configuration and durable state, run:
sudo install -d -m 0700 /etc/gigahostsudo install -d -m 0711 /var/lib/gigahost /var/lib/gigahost/instancessudo install -d -m 0700 /var/lib/gigahost/images -
You start
/etc/gigahost/hypervisor.tomlwith the following shared settings and the storage pools above:backend_url = "https://api.gigahost.cloud"host_label = "my-host"location = "sgp"cpu_core_limit_per_numa_node = 0memory_bytes_per_cpu_core = "4G"root_storage_bytes_per_cpu_core = "64G"allowed_numa_nodes = [0]libvirt_uri = "qemu:///system"cloud_uplink = "auto"dns_servers = ["8.8.8.8", "1.1.1.1"] -
You add the mode-specific settings from home mode or cloud mode.
-
To protect the completed file, run:
sudo chmod 600 /etc/gigahost/hypervisor.toml
The host’s state on the root pool’s drive
Section titled “The host’s state on the root pool’s drive”The agent keeps what Gigahost cannot give a host again: its identity and
keys (state.json), the job journal, the readings it has not sent yet, each
rental’s files (its definition, seed and console log) and the container
kernels. By default they are in /var/lib/gigahost on the system drive, and
a host whose system drive fails cannot come back, even with its rentals’
disks intact.
We recommend keeping them on the root pool’s drive instead, before the host is enrolled. Then the root pool’s drive is the one to protect, with RAID1 for example, and the system drive can be replaced: the host comes back with its own identity and rentals (see Recovering from a lost system drive). With the configuration and its pools in place, this command makes the state directory:
sudo gigahost-hypervisor prepare-state- For a file-backed root pool, the state directory is
.ghostrackin the pool’s directory. - For a thin-LVM root pool
VG/POOL, it is a thin volume of that pool,VG/ghostrack-state, with an ext4 that a mount unit of its own mounts at/var/lib/ghostrack. A drop-in in/etc/systemd/system/gigahost-hypervisor.service.d/has the agent start only once it is mounted, and both stay through reboots and agent updates. /var/lib/ghostrackis that mount point or, for a file-backed root pool, a link to the state directory, and/var/lib/gigahostbecomes a link to/var/lib/ghostrack, so every path on these pages stays the same.- The command refuses a host that has state already, and a pool directory
inside
/var/lib/gigahostor/var/lib/ghostrack.
The command prints three lines for hypervisor.toml: state_directory,
and the image and container caches in /var/cache/ghostrack, which stay on
the system drive since they are downloaded again. The layers disk a
container’s creation unpacks its image from, as large as the image, is
written beside the container cache too. From then on the agent refuses to
start when the state directory is not on the root pool, as when the pool’s
drive is not mounted, or when a cache is inside it.
The root pool keeps room for the state beside what it offers: 1 GiB, and
9 MiB for each rental the capacity profile allows, room for a container’s
two logs and its small files. A host without state_directory keeps its
state on the system drive as before.
Location
Section titled “Location”Both home and cloud hosts need a location. You choose a stable slug from
ghost catalog locations. Each location also carries country and
continent codes for catalog filtering.
CPUs, RAM and disk
Section titled “CPUs, RAM and disk”cpu_core_limit_per_numa_node, memory_bytes_per_cpu_core,
root_storage_bytes_per_cpu_core and allowed_numa_nodes set the host’s
saleable capacity.
- A CPU limit of
0auto-detects the smallest logical-CPU count among the listed NUMA nodes; a nonzero value sets a lower manual limit independently on every listed node. How0is read after enrollment is undercpu_core_limit_per_numa_node. - A node holds as many VMs as their CPU shares allow, up to four for each logical CPU; nothing else limits their number.
- RAM and root storage use binary
K,M, orGsuffixes and describe saleable capacity per logical CPU. A size may have decimals, such as1.6G. One that is no whole number of KiB is rounded down to one, so1.6Gis 1,677,721 KiB, and enrollment shows what it resolved to.
The sizes these settings give your host, and the platform’s minimums, are under Sizes.
How much RAM the host needs
Section titled “How much RAM the host needs”A VM’s own overhead is counted in its RAM. 64 MiB of each size’s RAM is the VM’s, for QEMU and its devices, and the guest gets the rest. A VM of 4 GiB boots with 4 GiB less 64 MiB.
- Beside its guests’ RAM, every listed node keeps 0.5 % of it for the VMs’ overhead that grows with their memory, such as page tables.
- What the node has beyond that is your host’s, for its own services, the router VM of a cloud host and its page cache.
- With 4 GiB for a logical CPU and a limit of 16, a node sells 64 GiB to
guests and needs 64.3 GiB of
MemTotalfor them. - Enrollment needs that and a margin of 512 MiB besides on every listed node.
What stays as enrolled
Section titled “What stays as enrolled”The enrollment command verifies the selected nodes, guest memory plus VM
overhead and the margin in each node’s MemTotal, and configured root pools
before registering the host.
- You can raise the CPU limit and the NUMA nodes later in place (see Raise a host’s capacity).
- The mode, the location and every other capacity setting stay as enrolled for that host identity. To change one of them, you drain and retire the host and enroll a new identity.
Identically configured hosts with matching CPU, location, price, and SLA appear as one catalog group. Gigahost chooses a physical host when a renter creates an instance.
Enrolling once
Section titled “Enrolling once”-
After you complete the home-mode or cloud-mode configuration, you create an enrollment token on the machine where you use
ghost:ghost account get-host-enrollment-token --label "my-host"The command prints the
tokenand when it expires (expires_at). The website creates one too: Provider › Add a host (/provider/hosts/new) shows it once, inside the enroll command for the server. -
To enroll the host, run the command below and paste the
tokenvalue when it asks. The token is read like a password, without echo:sudo gigahost-hypervisor enroll
A newly enrolled host starts paused; see Controlling rental admission.
What the command shows
Section titled “What the command shows”While it runs, the command shows every step on the terminal as it happens, each with how long it took:
- the host checks;
- on a home host, a
wireguardstep that installs a key on a throwaway tunnel; - the smoke-test image download with its size and speed;
- each smoke-test VM as it is created, booted, and removed again;
- the registration;
- the network tests.
A step that fails says what it was doing, and a failure before registration
leaves the token unused. A non-empty NO_COLOR turns the colors off, and
output that is not a terminal, such as a log file, gets one plain line per
step instead of a live line.
If the wireguard step fails, journalctl -k | grep -i denied shows
whether AppArmor or SELinux denied /usr/bin/wg. The running agent also
logs an error at start when the check fails later, such as after an upgrade.
The host-creation charge
Section titled “The host-creation charge”Successful first enrollment posts the configured non-refundable
host-creation charge. Reusing the same enrollment identity cannot post the
charge twice. The charge is paid from your available balance, not a trial
credit, and must leave your
protected balance; otherwise the
enrollment is refused with insufficient_balance and nothing is created.
The enrollment token
Section titled “The enrollment token”The command asks for the token first, before its checks, and reads it from
standard input instead when that is a pipe. To read it from a file, pass
--token-file PATH. The token is never a configuration setting or a
command-line argument, because other users of the host could read those.
If enrollment is interrupted, running the same command with the same token again resumes it. The host keeps the same identity and is not enrolled twice.
The host identity
Section titled “The host identity”Enrollment creates the host identity in the configured state_file. This
file belongs on durable storage. Copying it to a second running host, or
reusing it as part of a machine image, would give two machines one identity,
so both are best avoided.
What enrollment checks
Section titled “What enrollment checks”Before registering the host, the agent reads Linux CPU topology, NUMA memory, the usable capacity of every configured pool, and the root pool’s Linux-visible physical devices and RAID levels. Of a hardware RAID controller it reads the logical disk Linux exposes and the array’s level where that is told; see Hardware RAID.
The agent then boots the smallest and largest Ubuntu 24.04 configuration on every selected NUMA node.
- Each pass needs to reach cloud-init readiness, and libvirt needs to report the guest’s virtio balloon statistics, which tell the agent that a new guest’s kernel has started.
- The final pass also needs to accept a real key-only
rootSSH login using a newly generated temporary key and link-local bridge addresses. - Every mode creates an isolated temporary bridge. Temporary domains, volumes, bridges, addresses, and keys are removed before registration.
The agent tries to publish that inventory right after enrollment, and a network failure is kept for a retry when the persistent agent starts. Invalid CPU topology, undersized memory, a non-thin LVM target, disabled thin-pool zeroing, or overlapping file-pool filesystems make enrollment fail instead of advertising capacity the machine cannot provide.
Enrollment starts real smoke VMs and does not accept a host unless QEMU runs as a non-root user without effective capabilities, has seccomp filtering, and has an enforcing libvirt AppArmor or SELinux policy.
- On SELinux systems, both global enforcement and the QEMU domain type need
to be enforcing, and the
setoolspackage needs to be installed to check the loaded policy. - The agent also does not accept remote libvirt TCP/TLS listeners or any
libvirt URI other than
qemu:///system.
Libvirt runs QEMU as an unprivileged account. The agent makes each VM state
directory searchable but not listable by other users. Every ancestor of
instance_directory and each file-backed root-pool directory need to permit
search access likewise (chmod o+x PATH), while disk and key files keep
restrictive file permissions. Otherwise enrollment fails and names the exact
inaccessible path.
Testing in the foreground
Section titled “Testing in the foreground”-
To test the agent once in the foreground, run:
sudo gigahost-hypervisor run -
When the initial checks have completed,
Ctrl+Cstops it. -
Any reported KVM, libvirt, storage, network, or permission errors are best resolved before enabling the service.
Every command reads /etc/gigahost/hypervisor.toml unless --config PATH
or the environment variable GIGAHOST_CONFIG_FILE names another file.
What every start of the agent checks is under
The capacity check at every start.
Running with systemd
Section titled “Running with systemd”To enable and inspect the service, run:
sudo systemctl enable --now gigahost-hypervisorsudo systemctl status gigahost-hypervisorsudo journalctl -u gigahost-hypervisor -fThe host then appears online in your provider account.
The installer placed gigahost-hypervisor.service in
/usr/local/lib/systemd/system. It runs
/usr/local/sbin/gigahost-hypervisor run --config /etc/gigahost/hypervisor.toml
as root with a private /tmp, no new privileges, and the kernel-facing
protections systemd offers, and restarts the agent five seconds after any
exit.
Local changes belong in a drop-in under
/etc/systemd/system/gigahost-hypervisor.service.d/ rather than in the
unit, since an update replaces the unit.
Opening the host for rentals
Section titled “Opening the host for rentals”The host is enrolled and running, and still paused. What remains:
- Setting what it earns: Pricing and SLA.
- On a cloud host, registering its addresses: Registering public addresses.
- On a cloud host, making the checks that need no rental: Checking a new host.
- Resuming new rentals: Controlling rental admission.
- Making the checks with a small test VM: Checking a new host.
Recovering from a lost system drive
Section titled “Recovering from a lost system drive”A host whose state is on its root pool’s drive (The host’s state on the root pool’s drive) comes back after its system drive is lost, with its own identity, so it needs no new enrollment. Gigahost counts the time it was away as an outage, as for any host that goes offline.
-
You install the operating system and the agent on a new system drive, as in Installing the agent.
-
You attach the root pool’s drive. A file-backed pool’s filesystem needs to be mounted where it was before.
-
This command brings the host back, with
--lvmonly for a thin-LVM root pool:sudo gigahost-hypervisor recover \--state-directory /var/lib/ghostrack \--lvm VG/ghostrack-stateFor a file-backed root pool,
--state-directorynames the.ghostrackdirectory in the pool’s directory. -
The agent can then start again:
sudo systemctl enable --now gigahost-hypervisor
The command mounts the state volume of a thin-LVM pool, restores
/etc/gigahost/hypervisor.toml from the copy the agent keeps in the state
directory, checks that the configuration’s root pool is the drive’s, and
points /var/lib/ghostrack and /var/lib/gigahost at the state
directory. It refuses a drive of
another pool, and a configuration that differs from the kept copy unless
you pass --force (the present one is kept beside it as
hypervisor.toml.before-recover).
When the agent starts, it defines each rental from the definition it kept and starts the ones that were running, as after a reboot. A new mainboard or other changed hardware is reported to Gigahost as a new inventory, as any change of the machine is.
Raise a host’s capacity
Section titled “Raise a host’s capacity”Raising a host’s capacity has moved to Operating a host.
Retiring or re-enrolling an empty host
Section titled “Retiring or re-enrolling an empty host”Retiring or re-enrolling an empty host has moved to Operating a host.