Blog ·
A label that survives a hostname change
A sticker on a server is a public document. What we put on it, why the QR code holds no URL, and how a barcode table gets verified instead of trusted.
By Provibr
A sticker on a server is a public document. It travels in a courier van, it is read by remote hands staff who work for a company you have never contracted with, and eventually the machine is decommissioned and the sticker goes in a skip with the chassis. Anything printed on it is, over the life of the machine, published.
That single observation decides almost everything a datacenter label should contain, and it rules out most of what people put on them.
What is on it, and what is not
Three things: an opaque locator, the revision number of this print, and the same locator again in human readable form, grouped in fours for when the code will not scan.
Not on it: the customer name, the organisation, the serial, the asset tag, the rack it currently lives in, the hostname, a logo, or a token of any kind. A label is an identity, not a record.
The rack is the one people argue about, because writing it on the sticker is convenient right up to the first time a machine moves. Then the sticker confidently states a wrong location, and a wrong location that looks authoritative is worse than none. That is also why a rack position gets no sticker: a U position is not a thing but a coordinate, and it stops meaning what it meant the moment the starting unit of the rack is corrected.
Why the QR code holds no URL
The default for anything with a QR code is to encode a link. We encode the bare locator, for three reasons in order of weight.
A sticker outlives a hostname. An account that later moves onto its own domain would otherwise hold a thousand labels pointing at an address that no longer serves it, and nobody reprints a thousand labels.
A URL says more than a locator does. It names the platform, and on a customer's own domain it names the customer, which is precisely the category of information the label is supposed to be free of. A URL is not a shortcut, it is an extra field with the most bystanders.
And there is exactly one input path. A phone camera, a USB scanner and a human copying by hand all produce the same string in the same box. A URL would add a fourth shape that only the camera ever produces, and a fourth shape is a fourth thing to get wrong.
The locator is not a bearer token
This is the part that makes the rest safe. Holding the locator gets you nothing.
A scan is an ordinary authenticated action. The organisation gate runs, the read permission is checked, the query is scoped to the account, and only then does the server say whether this locator exists here. A locator from a different account gives the same answer as one somebody invented: unknown. A revoked one gets its own refusal, because that is a different fact and the person holding the sticker deserves to know which it is.
There is also no vendor prefix. A scheme in front would let the software tell our sticker apart from the manufacturer's own barcode, and it would tell anyone who finds the sticker which platform it belongs to. The shape does that job silently: a locator is sixteen characters from a known alphabet, and anything else is looked up as an asset tag or a serial, which the scan flow needs anyway for the manufacturer's barcode and for somebody reading a number off the chassis.
Sixteen characters, and why sixteen
The alphabet is Crockford base32: the digits and the letters without I, L, O and U. I and L are confusable with the digit one, O with zero; the U is dropped by the standard to avoid accidental profanity. We follow it because two other codes in this product already do, and two alphabets would be a bug waiting for its moment.
Sixteen characters of a thirty two character alphabet is eighty bits. The length was not chosen for guessability, because guessing buys nothing: the lookup is authorised regardless. It was chosen for collisions. Eighty bits makes a duplicate across millions of labels negligible, so the unique index underneath never forces a retry a user would notice. It is also about the longest string somebody copies in four groups of four without a mistake.
Normalisation runs on everything coming in: trim, upper case, strip spaces and hyphens, then map I and L to one and O to zero. Nobody typing from a sticker should have to know those letters are absent. The U deliberately has no mapping: no digit resembles it, so a U is a real typing mistake and belongs in a refusal rather than a silent substitution.
Code 128, written by hand, and verified rather than trusted
The QR code uses a library already in the lockfile for two factor authentication: no runtime dependencies, and a renderer that produces SVG without touching a canvas or a DOM. Reusing it beats writing a second QR encoder.
For Code 128 no such package existed here. The candidates drag a drawing layer aimed at a canvas or a browser, the one thing a server rendered SVG must not have, and they are two orders of magnitude larger than the thing actually is. Code 128 is small: a table of patterns, a start character, a checksum modulo one hundred and three, and a stop character. That is a couple of hundred lines and no supply chain for a table unchanged since 1981.
The problem with typing a standard table out of a specification is that a mistake fails silently. The SVG looks perfect, the tests pass, and months later a scanner reads a different character. So the table is verified by four independent invariants and a decoder, all in the test file:
- One hundred and six patterns besides the stop character, each of exactly six elements summing to eleven modules.
- Even parity in the bars. Every Code 128 character has an even sum across its three bars; that is the property a scanner uses to work out which way round it is reading, and it holds for all one hundred and six. A single mistyped digit breaks either this or the sum above.
- Element widths between one and four, and all one hundred and six patterns distinct.
- The stop character, the only pattern with seven elements and thirteen modules.
- A decoder in the test that reads the generated bar widths back and has to recover the input string, check character included.
A table that survives four independent invariants and a round trip is not "probably right", and that distinction is the whole reason for writing them.
We stayed in subset B rather than switching automatically. The label carries upper case letters and digits, which subset B covers in one pass. Subset C would halve numeric pairs, but a locator is not a numeric run, so switching would be a branch that never fires.
The sheet layout is a consequence of the barcode
Twenty four labels per A4 page, three across and eight down. That number is not a design preference but arithmetic running in the other direction.
A sixteen character Code 128 is two hundred and eleven modules wide: eleven for the start, eleven per character, eleven for the check character and thirteen for the stop. Add two quiet zones of ten modules and you need two hundred and thirty one modules across. The practical floor for an ordinary scanner is a module of a quarter of a millimetre, below which reading goes from reliable to occasional. That is fifty eight millimetres of barcode.
Four columns on an A4 gives a label around fifty two millimetres wide and a module near two tenths of a millimetre: a sheet that looks tidier and does not read in a cold aisle. Three by eight gives a label of seventy by thirty seven millimetres, a usable width of sixty four, and a module of 0.277 millimetres. The count follows from the code rather than the other way round. The page is deliberately full, with the margin inside each label rather than around the grid, so a printer driver never has to scale anything, and scaling is the one thing a barcode does not tolerate.
That floor is a constant in the source rather than a comment, so a test measures the module width of the rendered SVG against it. A layout change that squeezes the barcode too thin is a red test instead of a complaint from the aisle.
One active label per object
Reprints are the ordinary case, so the database carries the invariant rather than the code. Two partial unique indexes, one for machines and one for racks, which are the only two things that carry a label, allow at most one that has not been revoked. Without them a reprint that fails halfway leaves two valid stickers on one machine, and nobody can say which is real. A second pair keeps the revision unique per object, so a reprint counts up and never repeats. Three digits is the ceiling: the number has to stay legible, and a thousand reprints of one machine is not a labelling problem.
What we would write down
- Treat the sticker as published, and decide what goes on it by asking who reads it in five years.
- Encode the identifier, not a link. It survives a domain change, a rebrand and an acquisition; a URL survives none of them.
- Make the identifier worthless on its own, so a lost sticker is a logistics problem and not a security one.
- Verify a standards table with invariants and a round trip, because that class of mistake never fails loudly.
- Derive the print layout from the smallest readable module, pinned as a constant a test can measure.
For honesty about our own position: this work sits behind a rollout flag that is off by default, with a per organisation setting on top, so it is a description of a design and not an announcement. Two things are explicitly unproven. The QR matrix has not been decoded by an independent implementation, because there is no decoder in this repository. And nothing has been printed and scanned in an aisle, which is the only test that really counts for a barcode. The same reasoning about what a component may know shows up elsewhere here: credentials stay on the host, and the agent only ever connects outbound.
From the datacenter work on Provibr. What stops two people claiming the same rack unit is in the only real limit on rack occupancy.