LIVE 2 A.M.

Are you STILL retiring servers like this?

Don’t forget to wipe!

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. slag.sh retires a server 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.

slag /slæɡ/

  1. n the scum formed by oxidation at the surface of molten metals [syn: slag, scoria, dross]
  2. v convert into slag
  3. acronym SLAG: Sanitize, Log, Attest, Go. What’s left after the burn.
Sanitize
keys struck first, every non-zero block zeroed, every byte read back
Log
every step recorded as ok, unsupported, frozen, failed or skipped, with a reason
Attest
a receipt with its SHA-256, checked against the copy on the console
Go
the instance deleted only after a second boot proves the disks are zero

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.

slag.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!
QA qcow2 overlaythin-provisioned, recovering
I'll just write myself back after the verify. Nobody will... HEY! Who set my partition read-only?!
SAn ext4 superblockcaught in the lab, fenced since
I don't want "it ran." I want "bytes read: 3,221,225,472 of 3,221,225,472." Then we can talk.
AYour auditorhas never once smiled
So the verify used to pass when the disk wouldn't even answer? ...I need to sit down.
GGary from Opshas wiped a lot of disks

*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!

  1. Inventory: what lived here?

    slag.sh inventory walks 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.

  2. Checklist: what do you rotate?

    slag.sh checklist turns the inventory into ROTATION-CHECKLIST.md: host keys, TLS certs, API tokens, database passwords, directory entries, DNS, backup keys and the provider-side snapshots only you can delete.

  3. Wipe: make every byte zero, then prove it

    slag.sh wipe --target /dev/sda ... checks the targets, copies itself into RAM, detaches from your SSH session, quiets the disks, strikes the keys first, runs the hardware erase, zeroizes every block to zero, and reads every byte back. The full sequence is in the manual.

Introducing: Zeroize™

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.

slag.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: zeroized: 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?
GGary from Opsnow a believer

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.

Running root disk, wiped in place
905,611,732 → 0
non-zero bytes on a 3 GiB disk, checked from the host
Marker string hits
200,000 → 0
SLAG-MARKER written before the wipe, searched after
Second disk, rescue-style
519,707,681 → 0
512 MiB target with a real ext4 filesystem on it
Thin volume allocation, after zeroize
536,875,008 → 536,875,008
bytes allocated before and after: overwritten in place, nothing new allocated
With --reclaim
11,083,776 → 598,016
bytes of qcow2 overlay after the discard, second verify passed
Read errors injected on purpose
VERDICT: FAIL
exit 1, as it should, and the rest of the disk still zeroed. The old version said VERIFIED.

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!

Keys first. Then everything.

Before the wipe starts, the strike reads the whole raw disk and zeroes every block holding a private key, a password hash or a WireGuard key, deleted copies and swap included. On a real Linode the keys were gone in two and a half minutes. Then the wipe does the rest. How it works.

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.

Your receipt, even after SSH gives up

Wiped the disk you're running on? New SSH logins usually die with it. Add --serve and the receipt waits for you at a random URL, served straight from RAM, with its SHA-256 on the console so you can check your copy. Add --send-receipt and it POSTs itself to your server the moment it's done. How it works.

Order now and get slag!

Type an IP. Type its name once. Walk away. slag runs the inventory, the checklist and the wipe for you, brings the receipt home and checks its hash. Give it a provider token and it boots the rescue system, checks every disk from the console, and only then deletes the instance. Fleet hosts and your own machine? Refused before it even dials. Got a whole fleet? slagctl builds the list from the machines themselves and slags them two at a time. How it works.

No OS? No problem!

Plug in the slag stick, or network-boot it, and the machine boots straight into slag: pick the disks, type DESTROY. Every file from the boot script to the kernel is signature-checked against one pinned root before it runs. No console on your VPS? retire-vps.sh kexecs it into the same appliance, root disk and all. How it works, or download the stick.

Your policy says DoD 5220.22-M?

Fine. --pattern dod3, or Gutmann, VSITR and a dozen more, run after the zero pass has verified, and the receipt records the SHA-256 the disk must hash to. Nobody needs them anymore. We have them anyway. The list.

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:

# slag.sh inventory --out /root/slag.out
# slag.sh checklist --out /root/slag.out
# scp -r /root/slag.out you@elsewhere:   # before anything else
# slag.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. Step-by-step in the manual.

You have to TYPE THE DEVICE NAMES? Not just "yes"? Finally, a product that respects my anxiety!
AYour auditorsmiled, briefly

The fine print, which is the actual fine print