Some games ship an "official" self-hosting tool that flatly requires Windows plus Hyper-V, nested virtualization and all. Open the box before you believe that. The actual payload is often a portable Linux disk image with a full container orchestration stack already inside it. The Windows and Hyper-V wrapper is there because that is what the publisher's own tooling was built on.
A modern "dedicated server" for a live-service game is rarely a single executable. It is usually a small fleet of coordinated services bundled with something like Kubernetes to manage them. A database, a message queue, matchmaking and gateway logic, the game-world process itself. If the official installer requires Windows, check what it actually ships before you assume you need a Windows box. Publishers have said as much publicly for at least one game using this pattern. Linux-direct hosting works fine. They just do not provide official instructions, because their own packaging tool needs Windows and Hyper-V to unpack it.
Once you confirm the official installer is only unpacking a self-contained disk image, a VHDX in the case this is based on, convert it to your own hypervisor's format and boot it directly:
qemu-img convert -f vhdx -O qcow2 server-disk.vhdx server-disk.qcow2
qemu-img resize server-disk.qcow2 80G
Boot that directly under KVM, or whatever your hypervisor is. No Windows. No Hyper-V. No nested virtualization anywhere in the chain.
modprobe nbd max_part=8
qemu-nbd --connect=/dev/nbd0 server-disk.qcow2
vgchange -ay vg0
mount /dev/mapper/vg0-lv_root /mnt
# edit /mnt/etc/network/interfaces for a static IP
# check /mnt/etc/resolv.conf -- shipped images often point at their original
# host environment's internal DNS, which is dead anywhere else
umount /mnt; vgchange -an vg0; qemu-nbd --disconnect /dev/nbd0
x509: invalid signature: parent certificate cannot sign this kind of certificate right after
first boot looks alarming. It is usually clock skew during early startup, before NTP has synced. Wait a few
minutes and retry the same command rather than troubleshooting further.
This caused a real, confusing bug. It is worth walking through in full, because the debugging process is the useful part, including two wrong turns along the way.
The symptom. A player transferred their character onto a self-hosted world, then got a generic "Claim failed, try again later" error redeeming a returning-player reward package. Even after waiting over an hour, as the game's own message suggested.
First finding, and it matters for anyone running one of these. A self-hosted world is not isolated from the publisher's live infrastructure. The game-world processes make real outbound HTTPS calls to the publisher's cloud backend for entitlements, transfers and reward systems. None of that is simulated locally just because you host the "dedicated server" part yourself. The failure was findable in the game process's own logs, in a category clearly labeled as talking to the publisher's live services. Not anywhere in the hosting or orchestration layer's logs:
LogFuncomLiveServices: Error: https://[publisher-live-service-host]/api/ClaimSystem_GrantPacksForCharactersServer... Failed: Request Timeout or null response
LogDuneCharacter: Error: ...GrantReturnRewards... Failed to grant returning-player award packs for the character...
The actual answer came from the publisher's own patch notes and player community reports, not from guessing. This was a documented bug. Transferring a character to a new world without first logging into the character's origin world to view the reward there resets its eligibility. The publisher had shipped a fix for the common case months earlier. It has a real edge case. If the character's origin world was already shut down by the time of the transfer, there is nothing left to log into first, and the fix cannot apply retroactively. The only resolution other players in that situation reported success with was an official support ticket requesting manual compensation. Nothing fixable through local server configuration.
If the disk image comes through a platform like Steam rather than a bespoke publisher download, you already have a lightweight way to check whether you run the latest build. No full re-download, no real login:
steamcmd +login anonymous +app_info_print <appid> +quit
Look for the branches → public → timeupdated field in the output. It is a Unix timestamp, so
pipe it through date -u -d @<value> to read it. Compare that against when you built your
deployment. If the publisher's build predates your deployment date, you are current and a stale binary is
ruled out. Check that before you assume an obscure bug needs a version bump to fix.
A separate incident, months later. A server that had run fine for days stopped showing up in the in-game server browser at all. Not a connection failure. Not a timeout. Just gone from the list. Every layer under direct control checked out healthy. The world simulation was running. The periodic calls that publish the server to the browser returned clean responses. The tunnel was reachable. DNS resolved correctly. The database showed no blocked state. Two real, unrelated bugs got found and fixed along the way. Fixing them did not bring the server back.
Found by re-checking build freshness directly, with the same anonymous
app_info_print trick from above. Not by trusting an earlier pass that had already "confirmed"
the build was current. That earlier check only confirmed the update job ran without erroring, which is not
the same as confirming it updated anything.
Fix: run the update command by hand, interactively over SSH instead of through cron. It worked immediately and pulled the new build cleanly, which confirmed the automated job's failure mode was specific to running non-interactively. Note that applying an update to this kind of orchestrated server often leaves the world itself stopped. Updating and starting are two separate steps, easy to forget when you are used to the orchestrator handling both.