Are you STILL decommissioning servers like this?
Wipe it like you mean it.
You stopped the server. You deleted the instance. You told everyone it was gone. But the old disk blocks are still out there, and so are the keys that lived on them. decom.sh takes a server out of service in three steps: it lists everything that lived there, tells you what to rotate, and wipes the disks with a receipt that proves every byte reads zero.
VERIFIED!
Sound familiar?
dd if=/dev/zero and a prayer
You zero the disk, the command exits, and you call it done. But dd exits with an error at the end of every block device, so you stopped reading its exit code years ago. The old script's "verify" counted an empty read as all zeros, so a disk it could not read at all came back VERIFIED.
On thin storage you discarded first, which freed the blocks that held your data. The zeros landed somewhere new, and a 10 MiB image grew to 3 GiB doing it.
decom.sh
Every target is checked to be a whole disk. Every disk on the machine is accounted for. Hardware erase runs first and is waited for. Each block that holds data is overwritten where it sits. Then every byte is read back with direct I/O, and a read that comes up short is a FAIL, never a pass.
At the end you get a receipt with every step and its outcome, written to the console, the log, and a file that outlives the disk.
Real reactions from real* people
I used to be ten megabytes! Then somebody zeroed me the old way and now I'm THREE GIGABYTES of nothing!
I'll just write myself back after the verify. Nobody will... HEY! Who set my partition read-only?!
I don't want "it ran." I want "bytes read: 3,221,225,472 of 3,221,225,472." Then we can talk.
So the verify used to pass when the disk wouldn't even answer? ...I need to sit down.
*Dramatization. Disks, superblocks and Gary portrayed by actors. The superblock incident is real: see the lab results below.
It's as easy as one, two, zero!
Inventory: what lived here?
decom.sh inventorywalks every running process and systemd service to its config files, state, logs and environment, and catalogs every user's keys and dotfiles. You get a tarball to pull off the box before anything is destroyed.Checklist: what do you rotate?
decom.sh checklistturns the inventory intoROTATION-CHECKLIST.md: host keys, TLS certs, API tokens, database passwords, directory entries, DNS, backup keys and the provider-side snapshots only you can delete.Wipe: make every byte zero, then prove it
decom.sh wipe --target /dev/sda ...checks the targets, copies itself into RAM, detaches from your SSH session, quiets the disks, runs the hardware erase, normalizes every block to zero, and reads every byte back. The full sequence is in the manual.
Introducing: Normalize to Zero™
Other methods write zeros over every block, whether it held anything or not. On thin storage that balloons the volume, and if you discard first, the zeros never touch your old data at all.
decom.sh reads every block and writes zeros only where a block is not already zero. A block that held data is already allocated, so the zeros go over it in place. A block that reads zero has nothing in it to destroy, so it is left alone and never allocated.
The receipt says exactly what happened. From the lab, verbatim: normalized to zero: 3,221,225,472 bytes read, 1,258,225,664 bytes written where a block was not already zero; every block verified zero.
On a thin raw volume the allocation did not move: 536,875,008 bytes before, 536,875,008 after. (A copy-on-write overlay is another story: it has to store zeros over its base image's data, and the base image still holds the original. That is a snapshot, and snapshots are a provider-side job. Details.)
(The ™ is a joke. It is a shell loop. It is free.)
Wait, so it only zeroes the parts that aren't zero? That's... that's just correct?
Don't take our word for it. Take the disk's.
Every scenario runs live in a throwaway KVM guest. After each wipe the VM is stopped and the host reads the disk image itself, without trusting the script: converted to raw, compared against zeros, and searched for a marker string written before the wipe.
Lab: Debian 12 guests, kernel 6.1, QEMU 8.2.2. Partition, LVM, loop and duplicate targets were all refused with the disk's hash unchanged. Hardware erase paths for ATA and SAS drives, and a real NVMe sanitize, need real hardware and are not covered by the lab. What the lab tests.
But wait! There's more!
Per-file proof
Before the wipe it records where your keys, /etc/shadow and the inventory's sensitive files sit on disk. After, it re-reads exactly those spots and names each one in the receipt.
Survives the hang-up
The wipe runs as its own systemd unit from a RAM copy of every tool it needs. Your SSH session can drop. The wipe keeps going.
Counts every disk
Whole disks only, and every disk on the machine must be a target unless you say otherwise. No forgotten second drive.
Waits for the hardware
NVMe sanitize is polled until it finishes, once per controller, before any target is written. A frozen ATA drive is recorded as frozen, not quietly skipped.
Reclaim, if you ask
--reclaim discards the targets after they verify, so thin storage gets its space back, then verifies again.
A receipt that tells the truth
Every step is ok, unsupported, frozen, failed or skipped. Nothing is hidden behind || true. See one.
Operators are standing by
From the provider's rescue system, where the disks are not the running machine:
# decom.sh inventory --out /root/decom.out # decom.sh checklist --out /root/decom.out # scp -r /root/decom.out you@elsewhere: # before anything else # decom.sh wipe --target /dev/sda --target /dev/sdb TARGETS (every byte on these is destroyed): /dev/sda model=... serial=... size=480G /dev/sdb model=... serial=... size=480G Type the device names to wipe, separated by spaces ("sda sdb"): sda sdb
Then rotate everything on the checklist and delete the provider's snapshots. Get it, then follow the step-by-step in the manual.
You have to TYPE THE DEVICE NAMES? Not just "yes"? Finally, a product that respects my anxiety!
The fine print, which is the actual fine print
- No tool inside a machine can prove that provider snapshots or backups are gone, that the storage layer kept no copy of old blocks, or that SSD cells the controller no longer exposes are clean. That is what the hardware erase, the provider's console and the rotation checklist are for.
- On an SSD, the controller sends each write to a fresh cell, so writing zeros does not reach worn or retired cells. The hardware erase step covers those.
- Wiping the running root disk works and is tested, but the kernel still holds that disk. The receipt covers it up to a re-check made 10 seconds after the verify. Use rescue mode when there is one.
- Kernels 5.10 and older may not honor a read-only block device for a filesystem's own error writes.
- A sampled verify (
--sample) proves only the blocks it read, and the receipt says so. - This destroys data. That is the whole point. It asks you to type the device names first, and it means it.
- Not affiliated with any actual late-night television. No disks were harmed that weren't supposed to be.