Command-line client
ghost is the GigaHost command-line client. It prints results for reading, in
tables and with colors on a terminal, and as JSON when you pass --json, so
the same commands serve interactive use and automation.
Pricing, reviews, and history
Section titled “Pricing, reviews, and history”Publish what a host earns before opening a newly enrolled host to rentals:
ghost provider pricing HOST_IDghost provider set-pricing HOST_ID --file pricing.json --expected-revision 0 --reason "Initial pricing"Use the returned revision for later updates. You can also change them on the
host’s Pricing tab on the website (/provider/hosts/HOST_ID/pricing);
neither needs a new enrollment or a deployment.
The file names what you earn (fixed_instance_earnings_microusd_per_month;
the compute earnings, either compute_earnings per vCPU,
{"microusd_per_month": ..., "vcpus": 1}, or a whole-host total,
base_host_earnings_microusd_per_month, kept for the host’s vCPUs then;
network_earnings_microusd_per_tib and sla_target_basis_points); see
Pricing and SLA.
New rentals use published prices immediately. Existing
instances receive a notice and switch after 90 full days; already-created
backups keep their recorded storage and restore rates. An SLA change applies
only to new rentals. Each host can publish once per 24 hours.
Review your charges, receipts, and usage:
ghost account history --limit 50ghost account depositsghost account sla-creditsghost instance usage INSTANCE_ID --resolution dailyghost catalog reviews PROVIDER_IDghost account review PROVIDER_ID --rating 5 --message "My experience"History commands accept --cursor from the preceding response. For reading,
account history prints one line per entry: its time, kind, the part of your
balance it moves (available, reserved, or credit at a provider), the
amount, and the instance it is for; --json adds each entry’s
transaction_id. A VM’s usage at --resolution current is empty while the VM
is not running, and after a power change, reinstall, or restore until its
first new sample. At the daily resolution the first page starts with today
(UTC) so far, its intervals summed and what the billed ones were charged,
with "in_progress": true; --resolution monthly sums each UTC month’s days
(the current month with today so far), at most 12 months a page. Reviews
require paid usage with the provider in the last year, and are public under
your account alias. To change a review, pass its current revision as
--expected-revision; a wrong one is refused with review_revision_conflict.
The first change may follow publication at once, and later ones once a day;
one that comes too soon is refused with 429 limit_reached, whose message
names when the next is allowed.
Restoring a hosted backup from the website, over its instance or into a new instance, is approved locally, since only your account key decrypts it; the website makes local and hosted backups, restores local ones and creates instances from them itself:
ghost account approve REQUEST_IDghost account approve REQUEST_ID --yesInspect the request before approving it; the command prints what it costs. Keep the CLI running through restore-key authorization. If interrupted, repeat the same command to resume its admitted job without creating a second charge. An unapproved request expires after 15 minutes. Your account key and recovery private key stay in the CLI. When the backend refuses an approved request, for example because your balance does not cover it, the website’s approval page says why and that nothing was charged; once the cause is gone, approving again works until the request expires.
Install
Section titled “Install”The released ghost is one statically linked x86-64 Linux binary: it needs
no system libraries, so it runs on any x86-64 Linux distribution, old or new.
It is published on a signed release channel; one command installs it for
you, without root, as ~/.local/bin/ghost:
curl -fsSL https://api.gigahost.cloud/install/ghost.sh | shghost --versionThe script needs curl, jq, and openssl. It refuses the release unless
the manifest’s Ed25519 signature matches the release public key embedded in
the script and the archive’s SHA-256 matches the signed manifest. It checks
the signature with OpenSSL 3, or with python3 on systems whose OpenSSL is
older, such as Ubuntu 20.04, Debian 11, and RHEL 8; with neither, it stops
and says so. Run the same command to update. It tells you if ~/.local/bin
is not on your PATH. Run it as root to install for every user under
/usr/local, or set GIGAHOST_INSTALL_PREFIX to another prefix.
ghost --version prints the installed release.
ghost names its release with every request. Gigahost serves every release
for at least 90 days after it was built (a release’s name starts with its
build time, such as 20261010T120000Z-…); update at least that often with
the install command above. A release Gigahost no longer serves gets
client_release_unsupported for every command that needs your account,
with the release to install and the command that installs it.
Use ghost --help or add --help after any command to see the options
supported by the installed version.
Create and activate your account
Section titled “Create and activate your account”The client defaults to https://api.gigahost.cloud. Generate your account key with:
ghost key generateghost key inspectkey generate creates the account key’s directory, and any missing one above it,
for your user alone (mode 0700). A directory that exists keeps its mode, so
make an existing ~/.config/ghost private with chmod 700 yourself.
For an IP-addressed test backend, override it with GHOST_API_URL or
--api-url. Plain HTTP is accepted only when the URL contains a literal IP
address; hostname APIs require HTTPS, and API redirects are not followed.
By default, the account key is stored at $XDG_CONFIG_HOME/ghost/account.seed, or
~/.config/ghost/account.seed when XDG_CONFIG_HOME is not set. Generation
refuses to overwrite an existing account key. To use a different location, set
GHOST_SEED_FILE or pass --seed-file.
Back up this file offline before funding the account. Anyone who obtains it can control the account; losing every copy can also make encrypted hosted backups permanently unrecoverable.
Read the current activation terms:
ghost account activation-termsSend one or more payments to the returned address with the exact 16-character
deposit_memo; their confirmed sum must reach the returned minimum. Once the
payments have enough confirmations, activate without supplying transaction IDs
and verify the account:
ghost account activateghost account showghost account balanceactivate for an account key whose account exists already returns that account. A
deployment that takes no MMX deposits has no self-service activation: there
activation-terms and activate answer activation_unavailable (404), and
its operator registers accounts from the output of ghost key inspect.
Private CLI requests are signed locally with a key derived from the account key. There is no bearer or website session token to configure. Keep using HTTPS for any non-loopback API endpoint.
For the full activation, website-login, and key-migration model, see Accounts and security.
Log in to the website
Section titled “Log in to the website”Ask the CLI for a short-lived, single-use login URL:
ghost account loginOpen the login_url from the response before it expires. This creates a
browser session without sending your account key or private key to the
website.
To end every website session of the account and cancel unused login URLs, for example after losing a device, run:
ghost account revoke-sessionsLog out everywhere on the website’s Account page (/account) does the
same, and that page also ends single sessions, as ghost account sessions
and ghost account revoke-session do in the CLI. Your CLI keys keep
working.
To log in from a browser without the CLI at hand, set a website password.
ghost generates it and shows it once; --print writes only the password,
for a password manager, and --expires-in DAYS makes it stop working after
that many days. Setting it again replaces it and ends the website sessions
the old one began; remove-password turns password login off:
ghost account set-passwordghost account set-password --expires-in 90 --printghost account remove-passwordThe website’s Log in page then takes the account alias and the password. See Website password.
Find an offering and image
Section titled “Find an offering and image”List currently available VM configurations and operating-system images:
ghost catalog locationsghost catalog offeringsghost catalog offering <OFFERING_ID>ghost catalog imagesghost catalog alone is ghost catalog offerings, and takes the same
filters, such as ghost catalog --min-vcpu 4.
For reading, catalog offerings prints one line per offering: its ID,
location, host mode, size, monthly price from the base price to the price at
full CPU use (for a home offering with its default gateway’s monthly base, as
the website lists it), traffic price per TiB (for a home offering through that
same default gateway, such as $5.00/TiB), the bandwidth limit with that
address (BANDWIDTH, such as 200 Mbit/s or no limit), and how many
hosts have room for it (HOSTS). catalog offering shows one
listed offering in full: its hardware and storage, network readings, each
gateway tier’s traffic price, monthly base and bandwidth limit, backup
limits, creation fee and balance hold. The quote ghost instance create
prints names the limit of the chosen network, and ghost instance get
shows an instance’s as bandwidth. --json gives every
field of every offering. The catalog is public, so these commands need no
account key.
Use a location slug from ghost catalog locations in provider configuration
and catalog filters; display_name is its human-readable UI label. Locations
also include ISO two-letter country_code and geographic continent_code
values. US is a country in continent NA; EU denotes geographic Europe.
Filter offerings when you already know what you need:
ghost catalog offerings \ --mode cloud_routed \ --country SG \ --continent AS \ --provider gh-abcdefgh \ --min-vcpu 4 \ --min-ram 8GiB \ --min-disk 100GiB--provider takes a provider’s alias, such as gh-abcdefgh, or its UUID; the
list’s PROVIDER column shows each offering’s alias. --min-ram and
--min-disk take a size in binary units, such as 512MiB,
8GiB or 1TiB. M, G and T stand for MiB, GiB and TiB, so 8G is
8GiB, and a bare number is GiB. Decimal units such as 8GB are refused.
The same geography filters can narrow the location list:
ghost catalog locations --country USghost catalog offerings --continent EUValid modes are home_gateway and cloud_routed, spelled as the catalog
shows them; home-gateway and cloud-routed still work. The server applies
every filter before it cuts the list, and refuses an unknown --location, and
a --country or --continent that no location is in, instead of matching
nothing.
--ip dedicated|shared chooses the address the list prices, orders by and
offers, as the website’s IP filter does: dedicated, the default, is an
address of the instance’s own, and shared a range of a shared address’s
ports. An offering without that address is not listed, and the price column
and the cursor below are that address’s.
Offerings are listed cheapest first by their listed price (the base price
plus a home offering’s default gateway base price, or with --ip shared the
shared IP’s), at most 500 at a time;
--limit lists fewer. When a list comes back full, the CLI says on standard
error how to get the next one, with the same filters; --after takes the
last offering’s listed price in micro-USD and its ID, joined by a dot:
ghost catalog offerings --min-vcpu 4 --limit 50ghost catalog offerings --min-vcpu 4 --limit 50 --after 3100000.of2_F95QS_EuMsVz4IG5EulOewEvery host offers one ladder of sizes: 1 vCPU on a quarter of a core and on
half a core, 2 vCPUs on one core and on two, then 4, 8, 16 vCPUs and so on
up to the largest VM the host takes, each of these with twice the RAM and
disk of the one before. Between two of those of N and 2N vCPUs with a core
each, a mid-step has 2N vCPUs on N cores with the RAM and disk of the
smaller one, for more CPU without more memory: 4 vCPUs on 2 cores, 8 vCPUs
on 4 cores, and so on, where the larger size exists. A host whose largest VM
has 1 vCPU offers 1 vCPU on a quarter, a half, and a whole core instead. A
size’s RAM follows the cores it reserves, and a size with less than the
platform’s least RAM for a VM, currently 768 MiB, is left out: a host with
less than 3 GiB of RAM per core offers no quarter-core size, and one with
less than 1.5 GiB no size of 1 vCPU. A VM boots with its size’s RAM less 64
MiB, which the VM itself uses on its host (QEMU and its devices): an
offering of 4 GiB gives its guest 4 GiB less 64 MiB.
The catalog lists only the sizes a host has room for now, and a cloud host
with one free public address left only the largest that fits and the
mid-step on as many cores. An offering is told by its vCPUs, RAM, disk, and
prices; ghost prints its vCPUs alone, such as 4 vCPU, for a mid-step
and a size on part of a core too. Its base price follows the cores it
reserves, a mid-step’s 1.5 times
the size whose cores it shares; the price at full CPU use follows the number
of vCPUs alone, so a mid-step’s is that of the next size. With --json an
offering also carries cpu_tier, how the platform accounts for what a vCPU
reserves.
Copy the offering ID, of2_ and 22 more letters, digits, -, or _, and
the image’s slug, such as debian-13, or its UUID from the response. An
offering ID names a configuration group and its exact terms: hardware,
prices, and SLA. It is not one physical host; the backend chooses an
available matching host during creation. Once the provider changes those
terms, or no host with them takes new rentals, the ID no longer works:
creation is refused with offering_unavailable, and the catalog lists the
current offerings with their new IDs. ghost catalog offering
(GET /v1/catalog/offerings/{offering_id}) reads one offering while it is
listed.
Each offering lists what creating a VM from it costs besides its monthly
prices: instance_creation_charge_microusd is the one-time creation fee, and
balance_reservation_microusd is the part of your balance held while the VM
exists. A home VM also holds its gateway tier’s monthly base charge.
The list shows each offering’s vCPUs and CPU model, its RAM and the hosts’
memory technology, such as DDR4, its disk with its RAID level, such as
25 GiB raid 1, its monthly prices, and its
cheapest traffic rate. Prices are shown to the cent, and an amount under two
cents to the hundredth of a cent without trailing zeros, such as $0.0016 or
$0.007; --json has every amount in micro-dollars.
ghost catalog offering lists every network option of a home offering: a
shared gateway at each location it may be placed at, with the location’s
distance from the host and its prices, and a gateway of the VM’s own.
Each offering includes its provider UUID. Inspect that provider before renting: its name, rating and review count, the hosts, offerings and locations it lists now, and its completed-day 365-day uptime and abandonment sample:
ghost catalog provider <PROVIDER_ALIAS_OR_UUID>The reliability record includes observed time and distinct rented-instance counts. An empty or small sample is not equivalent to an established reliability record.
Each offering also lists its hosts under host_ids and their best network
readings under network, which ghost catalog offering and --json show,
each with the location of the test server it was taken against. Inspect each
test location’s latest upload, download and latency result for one host
with:
ghost catalog network-test <HOST_UUID>A reading flagged at_limit reached the test server’s own uplink limit and
is reported as that limit with a plus sign, such as 1 Gbit/s+. Null
readings are unknown, not zero.
Control host rental admission
Section titled “Control host rental admission”Every newly enrolled host starts paused. This gives you time to verify its inventory, pricing, storage, and networking before customers can rent it. List the host UUID and explicitly resume new rentals when it is ready:
ghost provider hostsghost provider host resume <HOST_UUID>ghost provider hosts lists your hosts as the website’s hosts table does:
each host’s state (accepting, paused, unverified, offline, and so on), when
its agent was last seen, its type, location, rentals, CPU, RAM and disk, and
its SLA and prices. Retired hosts are left out unless you pass --retired.
ghost provider host <HOST_UUID> shows one host in full, and --json
gives every field of every host.
A cloud-mode host can be resumed only once its public path is verified; until
then resume fails with public_path_unverified. See
Manage provider public IPs.
See everything the platform knows about a host, and what it and its rentals are using:
ghost provider host <HOST_UUID>ghost provider host metrics <HOST_UUID> --resolution currentghost provider host metrics <HOST_UUID> --resolution dailyghost provider host instance-usage <HOST_UUID> <INSTANCE_UUID> --resolution 15mThe detail shows the last heartbeat and the health the agent derived from
its own measurements, the agent version and uptime, hardware, the inventory
revision, the revisions of the host’s capacity with their reasons
(capacity_revisions, the newest first), and per NUMA node and storage pool
how much of the saleable capacity rentals hold. Metrics carry CPU busy and steal time, load, memory
and hugepages, disk I/O and SMART health per pool and device, traffic per
uplink, and temperatures, at the current, 15-minute, daily, and monthly
resolutions.
Each row also sums the rentals’ usage for the same period, so the platform’s
overhead is visible; a current row counts only running rentals sampled since
their last power change, reinstall, or restore. A single rental’s usage can be
read at the resolutions the renter sees to find a noisy neighbour. On the
website, the host’s Overview tab (/provider/hosts/HOST_ID) shows the
current readings, its Usage tab the history each UTC month (the
default), each UTC day, or every 15 minutes, and Rentals each rental’s
usage (/provider/hosts/HOST_ID/rentals/INSTANCE_ID/usage), also each month
by default.
ghost provider host <HOST_UUID> also shows the image cache (image_cache) of a
host that downloads the catalog’s images ahead of demand, a home host by
default: each image with its state and why, and what the cache takes of its
limit and filesystem.
Pause admission before planned maintenance. This affects only new rentals; existing VMs and already queued jobs continue normally:
ghost provider host pause <HOST_UUID>To permanently retire a host that still has rentals, give customers at least seven full days of notice:
ghost provider host retire <HOST_UUID> --notice-days 7 --yesThe backend calculates and returns the exact deadline using its own clock. The notice immediately pauses new rentals and cannot be shortened or cancelled. Every affected customer sees the deadline on their instance. At the deadline, instance usage, gateway base charges, and the refundable balance hold stop, and the platform queues durable VM deletion. Addresses, gateways, and physical capacity remain reserved until cleanup is confirmed. Local-backup billing also ends and those backups leave the platform-managed lifecycle; hosted backups remain available. A persistent deletion failure is shown as requiring operator attention instead of being retried forever.
To retire one rental without draining the host, use the same minimum notice:
ghost provider retire-instance <INSTANCE_UUID> \ --notice-days 7 \ --reason 'retiring this workload class' \ --yesIf the physical host is permanently lost and cannot serve the notice, declare an emergency instead:
ghost provider host emergency <HOST_UUID> \ --reason 'unrecoverable hardware loss' \ --yesEmergency declaration immediately stops affected billing, revokes the host, records its active VMs as abandoned in provider reliability history, and sends durable renter notifications. It is irreversible and is not a substitute for planned retirement.
To change enrollment settings, other than a higher CPU limit or more NUMA nodes, which raise the host’s capacity in place, first ensure the host has no rentals, then permanently retire its current identity:
ghost provider host delete <HOST_UUID> --yesThe API rejects retirement while any rental, unreleased instance resource, gateway, local backup a renter still keeps, or active job remains. The historical host and tenant records are not erased. Stop the agent and run the local reset on that machine before enrolling it again with a newly generated enrollment token:
sudo systemctl stop gigahost-hypervisorsudo gigahost-hypervisor reset-enrollment --yesThe reset archives the old identity, job journal, and telemetry spool using a
.retired-<HOST_UUID> suffix. It leaves local backup files in place for the
provider to retain or remove according to their policy. Their platform records
and storage billing close when the host retires; hosted backups remain
available.
Manage provider public IPs
Section titled “Manage provider public IPs”If you operate a cloud-mode host, register the public IPv4 addresses that its guests may use. First find the enrolled host and create a pool:
ghost provider hostsghost provider ip-pool create \ --label cloud-eu-1 \ --scope host \ --host <HOST_UUID>Use --scope account and repeat --host only when the upstream provider lets
the same addresses move between those hosts. Add one or more addresses with
the route settings supplied by the server provider:
ghost provider ip add \ --pool <POOL_UUID> \ --address 203.0.113.10 \ --address 203.0.113.11 \ --prefix-length 32 \ --gateway 203.0.113.1ghost provider ip-poolsPass --mac-address <MAC> when the server provider assigns a virtual MAC to
the address. Add addresses separately if their gateway, prefix, or MAC values
differ. An address can be live in only one of your pools at a time, but
another provider may register the same address: Gigahost cannot tell who
routes an address upstream.
Gigahost therefore checks each address once, before any rental may get it:
an online host of the pool boots a small temporary VM that answers on the
address, and Gigahost logs in on it over SSH from outside with a one-time key.
New rentals are not checked themselves. The pool listing shows each address’s
allocation status and its verification: pending, checking, verified, or
failed with the reason. A failed address is never assigned and is not
checked again on its own; correct the upstream routing, then ask for another
check:
ghost provider ip check --pool <POOL_UUID> --address 203.0.113.10A host’s public path is verified once one of its pools’ addresses has
answered through it, and only then can the host be resumed. ghost provider hosts shows public_path_verified_at, public_path_checking, and, after a
check through the host had no answer, public_path_error. Check the path
again after correcting the routing:
ghost provider host check-path <HOST_UUID>See Cloud mode for how a check works and what it needs. Remove an address that no rental holds with:
ghost provider ip remove \ --pool <POOL_UUID> \ --address 203.0.113.10 \ --yesThe backend rejects removal while an address is reserved or assigned to a
rental, or while a check is using it. An address that no rental ever held is
deleted; one that a rental held stays in the pool, disabled, for that
rental’s history. ghost provider ip add re-enables a disabled address in its
pool, or adds it to another of your pools. An address added again after its
removal, or with a different gateway, prefix, or MAC, is checked again before
a rental may get it.
An address that a rental was reached at rests for an hour after the rental
ends before another rental gets it, and ghost provider ip-pools shows until
when (available_at). Removing it and adding it again, to this pool or
another, or handing its pool over, keeps its rest. A resting address does
not count as free, so a host with few free addresses may refuse its smaller
sizes for up to an hour after deletions: it keeps its last free address for
the largest size that fits.
Once every host of a pool is retired and no rental holds one of its addresses, you can delete the pool so that its addresses can be added to another pool:
ghost provider ip-pool delete <POOL_UUID> --yesAs with removing one address, addresses that no rental used are deleted and the others stay disabled with the deleted pool for their history. That history does not hold the addresses back: every one of them, those that served a rental included, can be added to another pool right after.
A host’s mode, location, and capacity settings are fixed, so changing one means retiring the host and enrolling the machine again. Hand the retired host’s pool to the new identity instead of deleting it and typing its addresses again:
ghost provider ip-pool hand-over <POOL_UUID> --host <NEW_HOST_UUID>The host gets a pool with the same label and every address of the old one, with their gateways, prefixes, and MAC addresses, and the old pool is deleted as above. Each address is checked again through the new host before a rental may get it. Only the pool of one host is handed over, and only to a cloud-routed host of yours in the same location.
Review provider incidents
Section titled “Review provider incidents”The backend records actionable host warnings without waiting for a renter to open a support request. List the inbox, inspect an item, and acknowledge that you are working on it:
ghost provider incidentsghost provider incidents --state open --severity errorghost provider incident get <INCIDENT_UUID>ghost provider incident acknowledge <INCIDENT_UUID>Incidents can report host outages or degraded health, failed jobs, root-storage pressure, telemetry gaps, and a bandwidth reading well below the host’s previous reading against the same test server. A failed job is an incident only when it failed on the host’s side, one for each kind of job, step, and error: not when it failed at a step the platform runs itself, such as setting up a home VM’s gateway, or because of the renter, such as a restore the renter did not authorize in time, or a guest that starts no operating system again after its renter’s reboot, reset, upgrade or restore, whose system is the renter’s. A guest that does not boot a catalog image when it is created or reinstalled is still an incident of yours. A failed address check opens no incident; the pool listing shows it. They show the first and latest occurrence, count, affected resource IDs, and a recommended action. Their context is limited to operational data and does not contain renter SSH keys, startup commands, or guest initialization secrets.
Resolve a condition after correcting it:
ghost provider incident resolve <INCIDENT_UUID>If the backend observes the same condition again, the stable incident is reopened instead of creating an unrelated warning. Acknowledging or resolving an incident does not itself change the host or VM.
Provider payouts
Section titled “Provider payouts”ghost provider balance shows what you earned and was not paid out yet,
what is available to pay out now, what is still held, and what is on its
way. Earnings become available after the 1-, 5-, or 20-day hold associated
with the VM’s accepted SLA tier; an outage on one of your hosts whose SLA
credits are not settled yet blocks payouts until it is.
Every payout goes to your payout address. Set it once, and change it later, with this signed command; the website cannot set it:
ghost provider set-payout-address <MMX_ADDRESS>Then check the balance and request payouts, here or on the website’s
Provider › Payouts (/provider/payouts):
ghost provider balanceghost provider payoutghost provider payoutsOmit the amount to pay out everything available, or add --amount-microusd
for an exact smaller payout; a payout takes from your earnings exactly what
it pays. The request returns immediately, and the backend
processes the payout without further action. The payout list shows its state:
queued, preparing, submitting, submitted, confirmed, under_review,
action_required, or cancelled. The backend stores one exact signed MMX
transaction, broadcasts only those bytes, sends them again while the node does
not know them, and requires six confirmations by default before settling the
payout. A payment the wallet may have sent without reporting it is found on
chain rather than sent again. A signed transaction that fails on chain or
expires unincluded ends as action_required, and its amount can be requested
again. A confirmed transaction that does not pay the payout as prepared leaves
it under_review, still reserved, until an operator has checked it.
Create a VM
Section titled “Create a VM”Provide at least one SSH public key. You can repeat --ssh-key-file or
--ssh-key to install more than one. A key is one OpenSSH public key line of
type ssh-ed25519, ssh-rsa, ecdsa-sha2-nistp256, ecdsa-sha2-nistp384,
ecdsa-sha2-nistp521, sk-ssh-ed25519@openssh.com, or
sk-ecdsa-sha2-nistp256@openssh.com; DSA keys and certificates are refused.
Pass public keys only, such as the .pub file: ghost refuses a private key
before it sends anything. The keys are installed for root, so log in as
root: the image’s usual default user, such as ubuntu or debian, is not
set up, and SSH password login is off. Add other users with a
--cloud-init-file.
ghost instance create \ --offering <OFFERING_ID> \ --image debian-13 \ --hostname database-1.example \ --startup-command 'systemctl enable --now my-service' \ --ssh-key-file "$HOME/.ssh/id_ed25519.pub" \ --wait--image takes an image’s slug from ghost catalog images, such as
debian-13, or its UUID. --hostname is optional and must be a lowercase
RFC 1123 hostname. --name is optional too: the name the website and
ghost show the VM by, by the same rules; without it the VM is named after
its hostname. Use --startup-command-file instead of --startup-command
for a multiline first-boot shell program. Raw --cloud-init-file remains
available for advanced initialization, but cannot be combined with either
startup-command option.
Home-mode offerings also require a public connectivity tier:
ghost instance create \ --offering <OFFERING_ID> \ --image debian-13 \ --gateway-tier high_bandwidth \ --ssh-key-file "$HOME/.ssh/id_ed25519.pub" \ --waitThe available tiers are shared_bandwidth, high_bandwidth and
shared_ip; the spellings with a hyphen work too. Their recurring and
traffic prices are included in the offering information: the monthly base
charge and the traffic price of the gateway the VM would be placed on,
which can differ by gateway location.
A shared bandwidth VM is reached through a shared gateway at one of a few
locations. The offering lists them as gateway_locations, closest to the
host first, each with its distance, its gateway’s monthly base charge and
traffic price, and whether traffic between the host and it crosses a
bottleneck, a congested or long-haul path; one is preselected, the
closest with room that crosses no bottleneck, and taken unless you choose
another with --gateway-location:
ghost catalog offering <OFFERING_ID>ghost instance create \ --offering <OFFERING_ID> \ --image debian-13 \ --gateway-tier shared_bandwidth \ --gateway-location us-charlotte \ --ssh-key-file "$HOME/.ssh/id_ed25519.pub" \ --waitA location across a bottleneck is yours to choose knowingly. When no
listed location without a bottleneck has room, the creation is refused
and names the closest location with room, which you may choose. instance get shows the VM’s gateway_location, and you can move the VM to
another listed location later; it gets a new public address there, is
unreachable for the seconds its move takes, and pays that location’s
gateway prices from the move on, as the offering lists them:
ghost instance gateway-location <INSTANCE_UUID> us-charlotte --yes --waitA shared_ip VM has no address of its own: it shares a shared gateway’s
address with other VMs and gets a range of its ports, as many as the
offering’s shared_ip_ports (20), TCP and UDP. Each forwards to a port of
the VM: by default the first to port 22, for SSH, and every other to the
same number on the VM. The VM’s outgoing connections leave from a range of
source ports of its own, so other VMs on the address cannot use them up.
It pays the shared IP’s price per the price list, which the offering shows,
and is placed at a gateway location as a shared bandwidth VM is,
--gateway-location included. ghost instance create --wait ends with
the SSH command, such as ssh -p 1020 root@203.0.113.7. instance get
shows port_forwards, each public port with the VM’s port it goes to, and
outgoing_ports; instance ports shows them with the SSH command, and
instance ports ... set sends public ports elsewhere, the others staying:
ghost instance ports <INSTANCE_UUID>ghost instance ports <INSTANCE_UUID> set 1021=80 1022=443The gateway follows a change within a minute and drops the connections of a port whose target changed. When the VM moves to another gateway, by your choice or because its gateway is taken out of service, it gets that gateway’s address and other ports, each going where the one in its place went, and you are told the new address and ports when it moves: update your DNS records and the ports you connect to.
A cloud offering whose hosts share their own address lists a shared_ip
price among its network_prices beside the price without a tier, an address
of the VM’s own (an offering whose hosts have no address left lists the
shared IP alone). --gateway-tier shared_ip on such an offering gives the
VM a slice of its host’s address instead of an address of its own, its
ports forwarded and changed as above with instance ports, included in
the instance’s price (the shared_ip entry’s monthly price is 0, shown as
“included”), with the provider’s traffic price; no
--gateway-location, since its address is its host’s. It keeps its address
and ports while it exists. Without --gateway-tier a cloud VM gets an
address of its own, at the offering’s address_microusd_per_month.
The gateway prices a VM pays are those of the gateway it was placed on. When GigaHost changes them, the VM takes the new prices after 90 days, as with a provider’s prices, and you are notified. GigaHost never moves a VM with an address of its own to another address: when its gateway is taken out of service, you are asked to move the VM to another location at a time of your choosing, and it keeps running where it is until you do.
Creating a VM posts a one-time creation
fee, refunded if the creation fails, unless you caused the failure, and
holds a separate refundable part of your balance for the VM’s lifetime.
Before it creates anything, ghost instance create prints the offering’s
terms and costs on stderr: the creation fee, with --backup the backup’s
restore charge, which is not refunded, the balance hold (for a home VM plus
its gateway’s base charge), the monthly prices, and the traffic price. It
refuses a --hostname that is not a lowercase RFC 1123 hostname at once, and,
once it has read the offering, a --gateway-tier other than shared_ip
given for a cloud offering or one missing for a home one, whose tiers and
prices the refusal lists, and a
backup whose disk is larger than the offering’s root disk. An offering that
is no longer listed, or a tier the offering does not list now, gets only a
warning there; the backend then decides whether it can still be rented.
--compact prints none of this, and leaves the checks after the hostname’s
to the backend.
With --wait, once the new VM’s kernel has started, ghost waits up to
five minutes more for cloud-init in the guest to report how the first boot
went, and warns when it reported errors or finished degraded, listing its
messages, or says that it has not reported yet; --compact does not wait.
The command then ends with a line on stderr that says where the new VM is:
instance ID (HOSTNAME) is running at ADDRESS. Repeating a
creation with the same --idempotency-key returns the job of the first
request, and ghost says so, with when that job was made: nothing new is
charged. backup create and backup restore say the same of a repeat.
A home VM has a public IPv4 address of its own on a hosted gateway. With
shared_bandwidth the VM shares a gateway in one of a few central regions
with other home VMs, and every protocol and port of its address reaches the
VM. With high_bandwidth the VM has a gateway of its own in the region
nearest to the provider’s server and a lower traffic rate; its address is
the gateway’s, and every protocol and port of it reaches the VM but port
27492, which the gateway keeps. Either way the VM’s traffic crosses the
provider’s home connection, so it is never faster than that. Compare the
offering’s network readings before paying for high_bandwidth. An offering lists only the tiers
there is room for now, and names high_bandwidth in full_gateway_tiers
while the platform can set up no gateway of its own for another VM; when
the gateways have no room for the VM, the
creation is refused with capacity_unavailable, and nothing is charged. Its
message says what is short: no public address free at the location, with
when one is free again and whether high_bandwidth could be placed, or no
gateway that can be set up for high_bandwidth or has room for another
shared_bandwidth VM.
A home VM’s network interface has an MTU of 1420, that of the WireGuard tunnel to its gateway, and the MSS of TCP connections through the tunnel is clamped to 1380, so ordinary traffic needs nothing of you. A tunnel of your own inside the VM, such as a WireGuard or other VPN server, carries its packets inside that one and needs a smaller MTU: 1340, the tunnel’s 1420 less WireGuard’s 80 bytes, works for WireGuard. With the default of 1420 its connections stall.
Use --cloud-init-file cloud-init.yaml to supply additional cloud-init user
data. ghost checks the file before anything is created: a #cloud-config
must be a YAML mapping, a #cloud-config-archive a list, and a
#cloud-config-jsonp a JSON Patch array; a script starts with #!, and a
MIME multipart document needs a MIME-Version header. Without an SSH key,
ghost warns when a #cloud-config sets no SSH key or password of its own.
Do not put secrets in files that you do not control.
Manage VMs
Section titled “Manage VMs”ghost instance listghost instance get <INSTANCE_UUID>ghost instance power <INSTANCE_UUID> stopped --waitghost instance power <INSTANCE_UUID> running --waitghost instance power <INSTANCE_UUID> reboot --waitghost instance power <INSTANCE_UUID> reset --waitghost instance console-log <INSTANCE_UUID>ghost instance rename <INSTANCE_UUID> shopEvery command that takes a VM’s ID also takes its name, as instance list
shows it, in any case: ghost instance delete shop --yes first prints the ID
the name stands for. A name two VMs share needs the ID.
For reading, instance list prints one line per VM: its ID, name, state,
the job running on it with its progress when there is one, public IPv4
address, location, image, and size. instance get, and --json for either,
show all of a VM: its size (vCPUs, RAM, and root disk), firmware, location,
provider, and host mode, and its
image: the image its root disk now holds, which after a restore is the
backup’s. While a job runs on the VM or one of its backups, active_job
names it with its kind, current step, and progress: the job that holds the
VM, such as a restore, rather than a backup deletion that runs beside it.
last_restore names the newest backup restored over the VM, and
restored_from_backup_id the backup the VM was created from. name is
what the website and ghost call the VM, and hostname the hostname
Gigahost set in the guest at its creation or last reinstall.
guest_initialization is what cloud-init in the
guest reported of its latest boot: done, degraded or error, with its
messages and when it came. A deleted VM also shows when it was deleted
(deleted_at) and when its billing ended (billing_ended_at).
instance rename gives a VM another name, by the rules of a hostname: a
lowercase RFC 1123 hostname of at most 253 bytes. It changes only what the
website and ghost show, at once and without a job, in any state but
deleted; the guest and its hostname stay as they are. A reinstall’s
--hostname changes the hostname and leaves the name.
A stopped VM keeps its capacity and address and is billed like a running one, except that it uses no CPU time: its base price and metered traffic are still charged. Delete a VM to stop paying for it.
A VM cannot send mail straight to other mail servers: its outgoing TCP
connections to port 25 and to port 465 (SMTPS) are dropped, on every host,
so that a VM that sends spam cannot put the addresses of its host or of
GigaHost’s gateways on blocklists. Send mail through a mail service instead,
with a login on port 587 (submission) or through its HTTPS API, which every
VM may use; receiving mail works on every port. instance get shows
outgoing_mail_allowed, false unless support lifted the block for your
account: open a ticket in the networking category saying what the mail
is for, and once lifted, every VM of the account sends freely within a
minute, running ones too.
stopped asks the guest to shut down, again every five seconds while it
runs, and forces it off if it has not after two minutes. reboot does the
same and starts the guest again, keeping its address, so a guest that
ignores the request is rebooted all the same, up to about two minutes later;
with --wait it ends once the guest’s operating system has started, which
can be a little before SSH answers. reset forces the guest off at once,
without asking it, as a reset button does, and starts it again like
reboot: use it for a guest that hangs, since whatever the guest had not
written to its disk is lost. A guest that starts no operating system within
five minutes fails the reboot or reset with guest_boot_timeout, and keeps
running. A guest that is paused, or that never got as far as starting its
operating system, cannot act on the request and is forced off at once. A
stopped VM cannot be rebooted or reset: the request is refused with
instance_stopped.
ghost instance console-log prints the end of what the guest wrote to its
serial console: the boot messages of its kernel and system, a kernel panic,
and cloud-init’s result. It shows at most the last 64 KiB the host sent,
which it does within about ten seconds of the guest writing (--bytes N
for less), without the escape sequences that restyle a terminal, and then
on stderr when the host sent it and whether older output precedes it;
--json has the output as the guest wrote it. Once the platform has
started the VM again, for a reset, a reboot, a stop and start, an upgrade,
a reinstall or a restore, the output is what the guest wrote since, and
the end of what it wrote before, at most 64 KiB too, comes first, above the
line --- the platform started the instance again here ---
(previous_boot in --json): a verbose boot cannot push out the kernel
panic you reset the VM for. A VM created before consoles were recorded has
its console recorded from its next start.
Asking for the state a VM is in already, running for a running VM or
stopped for a stopped one, sends nothing to the host: the answer is a job
that has already succeeded, whose result says changed: false, and --wait
returns at once. A VM counts as running only when its guest has reported a
reading since its last power change, reinstall, upgrade, or restore;
otherwise running goes to the host, which starts a guest that powered
itself off. A reboot always goes to the host.
For a home VM, read what its hosted gateway counted over the last hour and the last day in each direction:
ghost instance gateway-traffic <INSTANCE_UUID>These figures are for information; billing never uses them. See Charges and resource limits for what the gateway bills.
If a home VM’s WireGuard key on its host may be lost or compromised, replace it:
ghost instance rotate-gateway-keys <INSTANCE_UUID> --waitOn a running VM, the tunnel to the gateway is down from the moment the host installs the new key until the gateway applies it, a few seconds, so connections through it may stall or drop. The job finishes once the gateway reports a handshake with the new key. On a stopped VM, the host keeps the new key for the VM’s next start, and the job finishes without waiting for a handshake.
Reinstalling destroys the current root filesystem while retaining the same VM capacity and network assignment:
ghost instance reinstall <INSTANCE_UUID> \ --image debian-13 \ --ssh-key-file "$HOME/.ssh/id_ed25519.pub" \ --yes \ --waitYou may also set a new hostname, startup command, or cloud-init payload;
without --hostname the VM keeps its hostname. The reinstalled VM starts
running even if it was stopped before, and ghost says so for a stopped VM,
and for one whose stop is still under way (is stopping; the reinstall starts it again).
Reinstalling is free, so to start over on the same size, reinstall the VM
rather than delete it and create another, which costs the creation fee
again. A failed bounded attempt leaves the VM in failed state with its
allocation fenced; repeat reinstall explicitly to delete any partial
replacement and try again. An image that starts no operating system within
five minutes fails the reinstall with guest_boot_timeout, which is not
retried, and leaves the VM powered off: reinstall another image or delete the
VM.
A VM can be upgraded to a larger size of its host in place: more vCPUs, memory or disk, and no less of anything. From a size of N vCPUs with a core each, the mid-step of 2N vCPUs on the same N cores keeps the memory and disk and adds vCPUs, and the next size doubles the cores, memory and disk. List the sizes it can take, then choose one by its offering:
ghost instance upgrades <INSTANCE_UUID>ghost instance upgrade <INSTANCE_UUID> --offering <OFFERING_ID> --yes --waitEach listed size shows its CPU (4 vCPU, a mid-step’s too), its
prices, what the upgrade adds to the balance the VM holds (the new size’s
hold less the current size’s, at the days of its base price the VM was
created with) and whether the host has room for it
at the moment beside what the VM holds. The list is empty while the host
takes no new rentals, or while its traffic price is above what the platform
accepts now. The VM is
shut down, given the size’s CPUs, memory and disk, and started again if it
was running; it keeps its disk, its address and its hostname. From the
moment the host reports the new shape the VM pays the size’s prices as the
catalog offers them now, and a price change the provider had given notice
of before no longer applies to it. Should the upgrade fail on the host, the
VM is left stopped with its old size and terms, and what the upgrade took is
given back; start it again or retry. A root filesystem grows into a larger
disk on the next boot where cloud-init runs, which every catalog image does;
on another system grow it yourself.
An upgrade to an offering of another host is refused with
offering_not_on_host, since an upgrade does not move a VM, and one to the
VM’s own size or a smaller one with not_an_upgrade, which names in what the
offering is smaller. When the host has no room for the size, the refusal is
capacity_unavailable, naming what the host lacks beside what the VM holds,
and so it is while the host takes no new rentals where the VM runs. Each
points to ghost instance upgrades.
Deletion is irreversible and requires an explicit confirmation flag:
ghost instance delete <INSTANCE_UUID> --yes --waitA VM whose creation failed can be deleted once its host has cleaned it up,
and that deletion completes at once. Deleting a deleted VM again returns the
same deletion job. Deleting a VM keeps its backups, which stay billed for
storage until you delete them, so ghost instance delete names those it
keeps in a note on stderr.
A VM created from a hosted backup waits up to 15 minutes for you to
authorize its restore, holding its capacity and balance meanwhile. Deleting
it then ends its creation: the creation counts as a failure you caused
(restore_authorization_abandoned), so its creation fee and restore charge
are not refunded, and the deletion gives back the rest once the host has
removed the VM.
A cloud VM’s public IPv4 address rests for an hour after the VM is deleted,
so that what is still meant for the VM, such as the traffic your DNS records
send there, reaches no other customer meanwhile; after that another VM may
get it. Update your DNS records within the hour, and remove the address from
your SSH known_hosts before you reach a new VM at an address you used
before. The address of a VM whose creation failed was never the VM’s and is
free at once. A shared_bandwidth home VM’s address rests for an hour too,
and a high_bandwidth home VM’s address goes with its gateway.
Backups
Section titled “Backups”Create a backup on the same host with local, or use hosted for independent
off-host storage:
ghost backup create <INSTANCE_UUID> --destination local --waitghost backup create <INSTANCE_UUID> --destination hosted --waitghost backup listghost backup list <INSTANCE_UUID>ghost backup list --allghost backup get <BACKUP_UUID>ghost backup cancel <BACKUP_UUID>ghost backup delete <BACKUP_UUID> --yes --waitbackup list leaves deleted backups out unless you pass --all
(include_deleted=true in the API). For reading it prints one line per
backup: its ID, its instance’s name, status,
destination (hosted or local), image, size, and creation time, and its
purpose when it is not a regular backup. backup get, a deleted backup
included, and --json show
all of it: its disk size, the smallest root it restores to, the firmware and
image its instance had when it was taken, the hostname the instance had then
(hostname) and its name, hostname and state now, its prices, the fingerprint of
the key a hosted backup is encrypted for, and for a local backup the host and
location that store it. In JSON a hosted backup’s destination reads
gigahost_s3.
A hosted backup is kept in the platform’s storage nearest to its VM’s host, currently in Frankfurt, Los Angeles, or Singapore, and stays there; see Charges and resource limits. It uploads at up to its host’s backup upload limit, which all hosted backups of the host share: 32 Mbit/s, about 4 MB/s, unless the provider set another.
Restoring replaces the VM’s current root disk, so the command also requires explicit confirmation:
ghost backup restore <BACKUP_UUID> --yes --waitA backup knows its instance, so backup cancel, backup restore and
backup delete take the backup’s UUID alone; for the latter two the older
form with the instance’s UUID first still works. A restore also gives the
instance the backup’s image in ghost instance get. Only an available
backup can be restored or give a new VM: ghost refuses any other before it
signs anything, with backup_not_available, and says to retry once a backup
still being made, or restored, is done. A local backup whose host is missing
the backup pool that holds it lists as unavailable, with the reason in an
unavailable column (in JSON the backup’s unavailable object): it is
refused with backup_pool_unavailable and costs nothing until the host has
the pool back. One whose artifact was gone when the pool came back is
lost: it can never be restored, costs nothing more, and is deleted with
ghost backup delete to leave the list. While a restore writes the VM’s
disk, the VM reads provisioning, as during a reinstall. A restore writes
only the data the backup holds, so it takes about as long as that data, not
as the disk is large.
backup create and backup restore print what they cost before they sign
the charge: a backup’s price per GiB and the most it can cost for the VM’s
disk, with the storage and restore prices it will keep, or the restore
charge. A backup deletion runs beside the VM’s other jobs, and several
deletions run at once.
A backup keeps the firmware, BIOS or UEFI, that its instance booted with, and it restores in place only while the instance still boots with the same firmware. After a reinstall with an image that boots with the other firmware, restore the backup into a new instance instead, as shown below.
The source hypervisor compresses and encrypts each local or hosted backup while
streaming it from the VM, and stores all-zero regions of the disk without
data. For hosted restore, the client unwraps and rewraps only the small backup
data key locally. The account key and private recovery key are never sent to
the backend or hypervisor. backup restore and instance create --backup
of a hosted backup wait at most --authorization-timeout-seconds (300) for
the destination host’s key offer and authorize no offer that comes later;
the job they started goes on, and their --json error names it.
Creation and restore also sign a separate paid-operation authorization with the billing key derived from the active account key. The prices are the platform’s, the same on every host, and come from the public backup-pricing catalog: a hosted backup costs $0.005 per GB to create and to restore and $0.03 per GB per month for storage, a local one $0.001 per GB and $0.01 per GB per month. Each backup records its restore and storage prices when it is created. Charging rounds artifact bytes upward to MiB; displayed GB/TB units mean GiB/TiB. The traffic of a backup is not charged.
Nothing is held for a backup. It is charged once, when it is published, for
the compressed and encrypted artifact’s size and for no more than the size of
the volume; a backup that fails or is cancelled before is charged nothing.
ghost backup create is refused with insufficient_balance unless your
balance covers a backup as large as the volume and $1 beside. Restore knows
the immutable artifact size at admission and posts its non-refundable charge
with the job. Storage is billed in 15-minute intervals on a fixed 30-day
month, a local backup’s until its asynchronous delete completes and a hosted
one’s within the same boundaries.
Backups and restores are bounded streams rather than full temporary disk
copies. Running VMs use a point-in-time pull backup; stopped VMs use a
read-only disk export. Restore replaces the current root volume only after the
size checks pass. A backup may restore to an equal or larger root; the restored
disk keeps its partitions and filesystem at their backed-up size, and the
platform never changes them. Every catalog image runs cloud-init’s growpart
and resizefs on every boot, so a system restored from one grows into the
larger disk on its next boot while cloud-init is still installed and enabled.
Other systems must grow the partition and filesystem themselves, for example
with growpart /dev/vda 1 and then resize2fs or xfs_growfs.
A running VM can always be backed up, and keeps running meanwhile. Its host
keeps 16 GiB for the blocks the VM overwrites during the backup. A VM that
overwrites more than that before the backup has read its disk is paused
until it has, and resumed then: nothing it wrote is lost, but it does not
answer meanwhile, for as long as the rest of the backup takes. The job’s
result says whether that happened (upload_parts.guest_paused). Back up a VM
that writes a lot while it is stopped, or when it writes least.
A host makes two backups or restores at a time, of running VMs or stopped
ones; a further one is accepted and waits for its turn, and its job says so
and how many are ahead of it, for example waiting for a backup slot on its host, which works on 2 backups or restores at a time; 1 ahead. The backups
of running VMs also take turns at the host’s two 16 GiB scratches, so a third
such backup can wait for one. A backup reads queued while it waits,
staging once the host has begun it, uploading while a hosted backup
uploads and finishes, and available when it is done. A stopped VM’s backup
needs no room for writes, so its hosted backup keeps nothing on the host; the
VM cannot be started until its backup has finished.
A VM takes no other job while its backup waits or runs. ghost backup cancel
withdraws a backup that still waits: it is cancelled at once and costs
nothing, and the VM takes other jobs again. The backup then counts as deleted, and its job, which the command
names, as cancelled. A backup the host has begun is refused with
backup_started; it runs to its end, and you can delete it then. Only the
platform’s operator can cancel a backup the host has begun: if one holds
your VM too long, open a support ticket. Such a backup reads failed, its
job is cancelled with cancelled_by_operator, and nothing is charged for
it.
A local backup reserves room for its artifact, about the root disk, in the
host’s backup storage. Each offering’s backup_limits says which backups fit
on every one of its hosts while nothing else holds that storage:
local_running, local_stopped, and hosted_running. A local backup the
host cannot take is refused with a message that names the sizes and what
would fit:
local_backups_unavailable: the host has no backup storage and keeps no local backup of any size. Use--destination hosted.backup_too_large_for_host: no backup storage of the host could hold a local backup’s artifact even when empty. Use--destination hosted.backup_storage_busy: other local backups fill that storage. When some are still running, retry once they finish. Stored local backups keep their room until they are deleted, so otherwise delete a local backup of yours on that host, or use--destination hosted.
To create a separate VM from a backup, find an offering that can take it,
then create the VM with --backup in place of --image; --for-backup
reads your backup, so unlike the rest of the catalog it needs your account key:
ghost catalog offerings --for-backup <BACKUP_UUID>ghost instance create \ --offering '<OFFERING_ID>' \ --backup <BACKUP_UUID> \ --waitThe selected root disk must be at least the backup’s disk size. Hosted
backups can restore onto any architecture-compatible offering. A local backup
can only use capacity on the physical host that stores it. --for-backup
keeps the offerings with a large enough root and, for a local backup, with
that host among their host_ids; the backend still checks the architecture
when you create. --host <HOST_UUID> alone keeps the offerings that can place
a VM on one host. The server applies both, as its minimum_root_disk_bytes
and host_id filters.
An offering whose hosts do not include a local backup’s host is refused with
backup_host_mismatch, which names that host and its location. While that
host is full or takes no new rentals, creation from the backup is refused with
capacity_unavailable, or with offering_unavailable if it was the
offering’s only host.
The new VM keeps the restored guest’s users and SSH keys, so the SSH-key and
startup-command options are unavailable with --backup. Put anything else
the new VM needs in a --cloud-init-file, which runs once at its first boot.
Gigahost supplies the new network assignment and hostname and boots only after
restore finishes. At its first boot the new VM also gets new SSH host keys
and, on guests with systemd, a new /etc/machine-id; a restore in place keeps
both.
Completed backups remain in their selected storage until you request deletion.
An automatic backup made immediately before an insufficient-funds VM deletion
has purpose: final_recovery in ghost backup list output. Treat this as the
clearly identified restoration source for a replacement instance; its marker
does not change if the source VM no longer exists. Use it with ghost instance create --backup as shown above.
Deletion is a background job and keeps an audit tombstone after storage
confirms removal. The website creates hosted backups itself, encrypted to the
account’s current recovery public key; restoring a hosted backup needs the
account key’s recovery private key, so the website asks the CLI to approve it
(ghost account approve).
After migrating an account to a new account key, authenticate with the new account key and
select the older account key only when restoring a backup encrypted to its recovery
key. The active --seed-file still authorizes the new restore charge. Here
the replacement is account.next.seed, as in the
account key migration walkthrough, and the older
account key is still the default account.seed:
ghost \ --seed-file "$HOME/.config/ghost/account.next.seed" \ --recovery-seed-file "$HOME/.config/ghost/account.seed" \ backup restore <BACKUP_UUID> --yes --waitA hosted backup whose key does not match the account key is refused before
anything is sent, with recovery_key_mismatch and the fingerprint of the
key the backup was encrypted for: without --recovery-seed-file, the
message says that a backup made before an account key migration needs the account key it
was made with; with it, that the given account key does not match. ghost key inspect shows an account key’s recovery_key_fingerprint.
Jobs and automation
Section titled “Jobs and automation”Commands that change state create an asynchronous job. Pass --wait to follow
its step events on stderr and receive the final result on stdout, or
inspect it later. --wait prints the job’s ID first, so Ctrl-C stops only
the waiting and ghost job watch picks it up again. Each event line names its
step, and a running step’s line is printed again as its progress grows.
ghost job listghost job list --instance <INSTANCE_UUID> --state activeghost job list --kind create_backup --state failedghost job get <JOB_UUID>ghost job watch <JOB_UUID>ghost job list lists your jobs newest first, including those a provider’s
retirement or an empty balance started on your VMs and backups. --instance
keeps one VM’s jobs and its backups’ jobs; --state takes pending,
running, succeeded, failed, cancelled, or active for pending and
running jobs; --kind takes a job kind such as create_instance,
create_backup, or rotate_gateway_keys. A page holds 50 jobs, or 1 to 200
with --limit; pass its next_cursor as --cursor for the next page. For
reading, the list shows each job’s ID, kind, state, progress, and creation
time, and the error code of a job that failed.
ghost job get shows a job’s steps, its newest 1,000 events with the step
each belongs to, and its progress, and the current step’s own. A job’s
progress is the mean of its steps’, but a step that moves a whole disk, a
backup’s upload or a restore’s writing, makes nine tenths of it. The upload
counts the data it has read and, far lighter, the zeros, so it moves
steadily to its end, and a hosted restore’s wait for your authorization
counts as part of its transfer, so its progress does not drop when you
authorize it. Steps are named
by their key; their IDs, which no command takes, are only in --json. The
job’s result holds, by step, only the fields meant for you, such as a new
backup’s size and SHA-256, or whether a restored VM is running and must grow
its filesystem to use a larger disk; the host’s own paths and names are left
out. ghost job get and ghost job watch with an ID that names no job of
yours say so, and that ghost job list lists your jobs.
Creation remains in provisioning until the host sees the new VM’s operating
system start and, for a home VM, its gateway reports a fresh WireGuard
handshake; the VM’s billing starts then. A home VM’s gateway base charge
starts earlier, once the gateway has its place for the VM: with
shared_bandwidth once the VM’s own address has been reserved, with
high_bandwidth once the VM’s own gateway has been created, which can be
minutes before the VM runs. The job says what the host is doing, such as how
much of the image has arrived, and the creation step’s progress follows the
download up to 80% and is 90% once the disk holds the image. A home host
keeps the catalog’s images downloaded ahead of time, so a creation or
reinstall there rarely waits for its image. An image that
starts no operating system within five minutes fails the creation with
guest_boot_timeout, which is not retried. A new VM is not checked for
reachability itself: a cloud VM only
ever gets an address that passed its one-time check, and a home VM’s public
address is its gateway’s.
A home VM uses one gateway, and its creation waits up to 15 minutes for the
gateway to be created and up to 15 more for it to boot, since creating one
can take the gateways’ cloud provider several minutes, and longer when its
service is slow; --wait prints each wait once. If the gateway is not
created or does not become ready in that time, or does not report the
handshake, the creation fails, and Gigahost orders no second one. The job’s
error then says in plain words what went wrong, that the creation charge is
refunded, and that you can try again; gateway_quota_exhausted means that
no gateway capacity is available right now, so try again later. While a
gateway step waits for room among the gateways, the job says so and keeps
trying.
A failed creation keeps its balance reserve, capacity, and address until its host has removed what the creation left there, which takes moments while the host is online; one that never reached its host holds nothing after the failure. A home VM’s gateway is given up at the failure. These steps survive backend or provider restarts. Unless you caused the failure, the creation charge and a home VM’s gateway base charges are refunded when it fails, as described under Charges and resource limits.
For safely retried automation, supply the same --idempotency-key each time
you retry one requested change. When a request gets no answer, times out, is
rate limited, or fails on the server, ghost prints the --idempotency-key
that repeats exactly that change. For a VM you named by its name, it also
prints the VM’s ID to repeat the change with, since by then the name may
stand for another VM. A rejection prints none, since the same
request would be rejected again. A conflict with a job still running on the
resource ends with the ghost job watch <JOB_UUID> command that follows it;
retry once that job has finished. A read that gets no answer at all, because
the connection failed, timed out or closed, is sent twice more, after 1 and
2 seconds, with a notice on stderr; ghost never repeats a change by
itself.
An idempotency key belongs to one kind of change on one resource: a creation
to your account, and other changes to their instance, backup, or ticket. For
30 days, the same key with the same request returns the first answer again,
even for a VM deleted since, and with a different request it is refused with
idempotency_key_reused. ghost makes a new key for every command unless you
pass --idempotency-key.
A refused request answers with a stable code and a message that says what
to do; a conflict with a job still running on the resource also names it as
job_id. Common codes:
| Code | Meaning |
|---|---|
instance_provisioning |
The VM is still being created or reinstalled; wait for job_id. |
operation_in_progress, backup_in_progress |
Another job is running on the VM; wait for job_id. Without a job_id, the VM changed state during the request: retry it. |
instance_stopped |
A stopped VM cannot be rebooted or reset; start it instead. |
instance_failed |
The VM’s creation or last reinstall failed; reinstall or delete it, as the message says. |
instance_deleting, instance_deleted |
The VM is being or has been deleted. |
not_home_instance |
Gateway commands apply only to home VMs. |
idempotency_key_reused |
The key was already used for a different request. |
invalid_offering_token |
The offering ID is not of2_ and 22 base64url characters, such as a longer of1_ ID from before; the message says whether the prefix, a character, the length, or the last character is wrong. Copy one from ghost catalog offerings. |
offering_unavailable |
The offering’s terms changed, or none of its hosts takes new rentals; list the offerings again. |
capacity_unavailable |
No host of the offering has room now, or a local backup’s host is full or takes no new rentals. The message says what the hosts lack: a free public IPv4 address (and until when a resting one rests), cores, memory, or root storage, or that a host keeps its last address for the largest size that fits it. For a home VM it names what the gateways lack: a free public address at the location, with when one is free again, or a gateway that can be set up or has room. |
offering_not_on_host |
The upgrade names a size of another host; ghost instance upgrades lists the sizes the VM can take. |
not_an_upgrade |
The offering is the VM’s own size, or smaller in what the message names. |
insufficient_balance |
Your available balance does not cover the request; the message names what it needs and what is available. |
backup_host_mismatch |
The offering cannot place a VM on the host that stores the local backup; find one with --for-backup. |
backup_started |
The host has begun the backup, so you cannot cancel it any more; wait for job_id and delete the backup then, or ask support, since only the operator can cancel it. |
backup_not_available |
Only an available backup can be restored or give a new VM, and only an available or lost one deleted; the message says what the backup is doing. |
backup_pool_unavailable |
The local backup’s host is missing the backup pool that holds it, or checks it since it came back; try again later. |
local_backups_unavailable, backup_too_large_for_host, backup_storage_busy |
The VM’s host keeps no local backups, or has no room for this one now; the message says what would fit, as under Backups. |
account_not_activated |
No account is registered for this account key yet; activate it first. |
activation_unavailable |
This deployment takes no MMX deposits, so its operator registers accounts; see Create and activate your account. |
auth_key_retired |
An account key migration retired the account key that signed the request; select the new account key. |
ticket_closed |
Reopen the ticket before replying. |
review_revision_conflict |
Pass the review’s current revision. |
Ask for JSON with --json, or with --compact for JSON on one line:
ghost --json instance listghost --compact instance listWith either, a command that fails also prints {"error": {...}} on stdout,
whose fields are always there, null where they do not apply: code, the
backend’s code, also for a refusal ghost makes itself before it sends
anything, where the backend would refuse the same (with status null),
recovery_key_mismatch for an account key that does not match the key a hosted
backup was encrypted for, which only ghost can tell, no_response when
no answer came, or null for a failure of ghost itself, such as a file it
cannot read; message; status, the HTTP status;
job_id, the job a conflict names, or the job the backend accepted when the
command failed after that, such as a restore whose key offer came too late;
request_id, the request’s ID from the error’s body or its x-request-id
header, for support; and transient, whether repeating the request with its
idempotency key may succeed. The error text still goes to stderr, ending with
(request ID) where the answer named one, and the exit status is 1. A job
followed with --wait that fails prints its final state instead.
Without either, results are printed for reading: fields are aligned, and lists
are one line per item, as tables where they fit the terminal and as short
blocks otherwise. Values are shown in their units under labels without the
unit the API sends them in, such as available $500.00 for
available_microusd, memory use in memory-hours, CPU use and uptime as
percentages, and network rates in bit/s; timestamps are in UTC without
fractions. Colors appear only on a terminal and never when NO_COLOR is set.
Never parse this form or error text in scripts. Use the command’s exit status
and the JSON response instead.
Lifecycle warnings such as provider retirement and unrecoverable-host notices are durable and can be listed independently of jobs, and marked read:
ghost account notificationsghost account notifications mark-read <NOTIFICATION_UUID>...ghost account notifications mark-read --allghost account notifications mark-unread <NOTIFICATION_UUID>A low-balance warning that ends, because a top-up covers more than seven
days again or nothing was billed for a day, is marked read, and a
funding_warning_resolved notice says why.
Contact support
Section titled “Contact support”Create a ticket from any activated renter or provider account:
ghost support create \ --category networking \ --priority normal \ --subject 'Public address is unreachable' \ --message-file ./details.txt \ --instance <INSTANCE_UUID>A ticket may link to one owned instance, backup, ledger transaction, provider
host, or provider incident. Replace --instance with --backup,
--ledger-transaction, --host, or --provider-incident as appropriate;
--ledger-transaction takes an entry’s transaction_id from ghost --json account history. The backend validates ownership and does not accept
arbitrary cross-account links. A message of several lines is shown on
several lines.
List or read the ordered conversation, reply, close it, or reopen it:
ghost support listghost support get <TICKET_UUID>ghost support reply <TICKET_UUID> --message 'The issue still occurs.'ghost support state <TICKET_UUID> closedghost support state <TICKET_UUID> openYou can set your own ticket only to open or closed; waiting and
resolved are set by support, who use ghost support list --all for the
global queue. Reopen a closed ticket before replying to it: a reply to a
closed ticket is refused with ticket_closed. Ticket creation, simultaneous
open tickets, message count, message bytes, and retention are bounded. File
attachments are not accepted yet; --message-file reads message text rather
than uploading that file.
Global configuration options include --api-url, --seed-file,
--recovery-seed-file, --json, and --compact. Their environment-variable equivalents
are GHOST_API_URL, GHOST_SEED_FILE, and GHOST_RECOVERY_SEED_FILE.