I built a powershell script that sets up whonix on windows. two vms in virtualbox, a gateway and a workstation, both downloaded, imported, and configured without me clicking through the import wizard and eight adapter dropdowns by hand.
the part i figured would be trivial turned out to be the one that actually bit me. launching them.
quick background on how whonix works, because the bug only makes sense with it. the gateway is the only vm that touches the internet, and everything it sends goes out through tor. the workstation has no direct internet at all. its single network adapter sits on an internal virtualbox network, and the gateway is the only other thing on that network. so every packet the workstation sends is forced through the gateway, through tor. that's the whole point. if the workstation could reach the internet on its own, it wouldn't be whonix, it'd just be linux in a box.
here's the shape of that config:
Gateway:
Adapter 1 = NAT (real internet)
Adapter 2 = Internal Network "Whonix"
Workstation:
Adapter 1 = Internal Network "Whonix" (nothing else)
my first launch script just started both vms. startvm gateway, startvm workstation, done. worked on my machine, so i moved on.
then i ran it cold on a slower box and the workstation came up with no network. apt couldn't reach anything, the tor connection check just spun.
the reason is timing. the workstation only has a working route out if the gateway is already up AND tor inside the gateway has finished bootstrapping. start the workstation first, or even a few seconds too early, and it boots into a network that's dead on arrival. some services cache that failure and don't quietly recover, so you're left poking at it wondering why a fresh vm has no internet.
so you can't start both. you start the gateway, then you wait. and it can't be a fixed sleep, because tor bootstrap takes anywhere from about 15 seconds to over a minute depending on the connection and which guard nodes it picks. you wait for an actual signal that tor is up, then start the workstation.
that's what the launcher does now. start the gateway, poll for tor bootstrap using guest control plus a tcp probe, and only once that comes back do you start the workstation. there's a -TorTimeoutSeconds flag because on a bad connection the default wait wasn't always long enough.
simplified, it's this shape:
Start-Vm -Name $gateway
$deadline = (Get-Date).AddSeconds($TorTimeoutSeconds)
while ((Get-Date) -lt $deadline) {
if (Test-TorBootstrapped -Vm $gateway) { break }
Start-Sleep -Seconds 3
}
if (-not (Test-TorBootstrapped -Vm $gateway)) {
throw "Gateway never reported Tor bootstrap. Check the Gateway console."
}
Start-Vm -Name $workstation
start gateway, poll until tor says ready or you hit the timeout, then and only then bring up the workstation.
a couple other things i had to get right, because this is a privacy tool and the small stuff is the whole thing:
the ova gets a sha-512 check before import. you're downloading an entire anonymity operating system. if that file got tampered with between their mirror and your disk, every bit of privacy it's supposed to give you is gone and you'd never know. so the download isn't trusted until the hash matches. mismatch aborts the run.
the vms get hardened during config. clipboard sharing off, drag and drop off, shared folders removed, usb off, audio off, 3d off, remote desktop off. every one of those is a bridge between your real machine and the isolated vm, and a bridge is exactly what you don't want when the entire idea is isolation.
what's still rough:
the guest vm password defaults to "changeme". you can pass -GuestPassword, but a default password sitting in a privacy tool bugs me. i want to force it to be set rather than ship a default at all.
bigger one is reproducibility. if you don't pin a virtualbox version, the script installs whatever LATEST.TXT currently points at. run it today and again next month and you might get two different virtualbox builds. you can pass -VirtualBoxVersion and -VirtualBoxHash to pin and verify, and a mismatch aborts, but if you skip the hash it installs unverified. i left it that way so the quick start stays one line, but honestly the verified path should be the default and the convenient one should be the opt-in.
the tests were the nice surprise. i mock VBoxManage and the filesystem in pester, so the unit tests run anywhere, no virtualbox and no vms needed. ci runs psscriptanalyzer and pester on every push. so i can change the ram allocation math and know in ten seconds if i broke it, without spinning up a real vm to find out.
it works. the order problem is solved, the download is verified, the vms come up isolated. not perfect. the password default and the unverified virtualbox path are both still on the list.
repo's here if you want to read it or break it: https://github.com/TiltedLunar123/WhonixAutoSetup
Top comments (0)