A public exhibit that cannot reach inward
All posts
2026-09-14

A public exhibit that cannot reach inward

Those Dark Arts

experimentsthe mesh

In late August 2026 we stood up a separate public exhibit box: documented on the 26th, cut over on the 29th, with further deployment work on both exhibits through the 31st. It is live and reachable now, at play.thosedarkarts.com, serving SIGNAL and LOOM — two public interactive audio/synth web applications.

The claim is a design answer to a specific problem: putting something on the open internet without also putting the whole operation on the internet. What we built is isolation by construction, layered public ingress, scored confinement for the services we measured, an authentication surface removed rather than hardened, monitoring that only ever points one way, and a content-addressed cache contract the server enforces. Each of those is a decision we made on this box. None of it is a claim that the box is finished.

Isolation by construction

The public box has no way to reach our private network. That is not a closed port and it is not a rule we could disable later. The private network's client software is not installed on the box at all. There is no client, no private-network identity, and therefore no private address to route through. The box also carries no command-line agent tooling and no credentials of any kind for the private side: no keys to any other machine, no tokens for any internal service.

The requirement was written as a positive instruction — do not install it, do not join — rather than as a hole that has been filled in. A rule can be misconfigured, turned off, or bypassed by something that is already inside the box. Software that was never installed, and a credential that was never issued, cannot be turned back on by whoever lands there.

The relationship is asymmetric on purpose. The private side can reach the box in order to poll its health. The box cannot reach the private side. An earlier, vaguer description of the box as "invisible" to the private side was wrong; the accurate description is that the box cannot reach inward, while the private side can reach outward to it.

The same ingress rule, enforced in more than one place

Public traffic never talks to the origin's real address. A content-delivery network sits in front of the box as the only path the public internet uses. The public name resolves to that network.

Behind that front door, inbound web traffic has to pass two independently administered allowlists, both of which admit web traffic only from that delivery network's own published address ranges. The first sits outside the box entirely, administered by the hosting platform: everything else aimed at the web ports is rejected before it reaches the operating system. The second is a separate firewall inside the box's own operating system, enforcing the identical rule again at that layer.

A third check happens in the application. The web server trusts the delivery network's visitor-identity forwarding header — the header that carries the real visitor's address — only when the direct connection actually originates from one of those same published ranges. A request cannot simply assert the trusted identity and be believed.

The layers are separately administered controls, not duplicated paperwork. One sits off the box. One is the box's own defence if the outer layer is misconfigured, detached, or bypassed. One governs what the application is willing to believe about who is talking to it. Each alone can be defeated by a single mistake in that layer. Defeating the arrangement requires the same rule to fail identically in places that are not administered together. That is why the same rule is written more than once.

The published ranges are an external dependency shared by all three enforcement points, and they change. The refresh procedure is specific: fetch the current ranges, reject an empty or malformed result rather than applying it, update in a defined order, verify before removing the stale ranges. The failure being guarded against is an automated refresh that succeeds at fetching nothing and then locks the front door against its own front door. The allowlist is maintained, not written once.

Sandboxing, scored rather than asserted

The exhibit application process and the separate status-reporting process each run as their own dedicated, unprivileged system account with no interactive login shell — not as the superuser, not as a shared account. The operating system's own sandbox-exposure scoring command was run against those service definitions. The exhibit application's service scored 1.5. The status-reporting service scored 1.9. Both were graded acceptable by the tool, on a scale where a lower number means less exposed. Those are two recorded numbers from the build. That is the point of mentioning them: the source records a measurement, not the word "sandboxed."

Those are the two services that were scored; the numbers are not a claim about the whole machine.

Two sandbox options were left off deliberately. A memory-protection option that would stop a process ever marking writable memory executable was left off because the application depends on a just-in-time compiler that requires exactly that. A browser-capability permissions policy was left open for microphone, MIDI, and USB-class device access, because the exhibit is an audio instrument and needs them to work at all. Maximum hardening would have broken the thing being hardened. The source records the reason rather than quietly leaving a default in place.

The authentication surface was removed, not defended

A public exhibit visitor has no legitimate reason to hold an account on this deployment. The publicly shipped build of the exhibit software has the sign-in and account surface removed outright, rather than shipping a login path this deployment has no use for and then defending it.

The public build ships no sign-in page, no authentication request handler, and no account-management interface. That was verified as a build step, not left as an intention: a full-text search of the built output for the authentication- and account-related code strings returned no matches.

Turning off the module responsible for the authentication feature was not enough, and that is the useful part of the account. Two further things had to be pruned independently before the surface was actually gone. First, a static-asset directory that is copied into the build output verbatim regardless of which application features are switched on, and which could therefore still carry and serve authentication-related assets. Second, a compiled route tree — the generated map of the URL paths the server will answer — which is produced at build time and, unless specifically told to generate a reduced version, still contained the authentication routes as compiled, reachable server code even with the feature switched off. Only after both were addressed separately — excluding those pages from the file-based routing system, and generating a deliberately reduced route tree for the public build — did a full search of the built server bundle come up empty. A feature flag turns a feature off. It does not necessarily remove the code that answers for it.

Once the stripping was complete, build output size dropped to roughly one third of its previous size, and a full-text search of the built output for the authentication- and packaging-related terms returned zero matches. The stripped sign-in, authentication, and account routes were also recorded as 404 when requested against the live public deployment.

Monitoring only points one way

Health monitoring is strictly one-directional. The private side polls the public box on a schedule. The public box has no mechanism for knowing the private side exists, and never initiates contact toward it.

A lightweight status-reporting process runs on the box, bound so that it is reachable only from inside the box itself — not from the public internet, not from any other machine. A scheduled job on the private side opens an administrative session to the box and, from inside it, reads the status process locally. Monitoring opens no additional public listener. Disk, load, and memory figures are never exposed on the public network at all.

We compared this explicitly against another always-on machine we run, which binds its status endpoint to a private-network address and lets the private side read it directly. That is safe there, because only members of that private network can reach that address. This box has no private-network membership. Its only reachable surfaces are the delivery-network-fronted web and administrative access. Publishing disk, load, and memory on any additional reachable surface would be disclosure for no gain, so the existing channel is reused instead of adding a new one. A monitoring endpoint that is safe behind a private network is not automatically safe on a public one. "We already have a way in" is usually better than opening another.

The private-side poller separates three failure classes. Whether the box's transport answers at all. Whether the box's own status process responds validly once a session is established. And whether the actual public exhibit routes return healthy responses over the public web. A transport failure marks the box fully offline. A reachable box whose status process is failing, or any public route that fails, redirects unexpectedly, or returns an empty success, marks it degraded rather than offline. A box that is up and serving nothing is a different problem from a box that is down.

There is deliberately no return leg. The other always-on machine runs its own watchdog to notice if the private network goes quiet, because it genuinely needs to know the rest of the system is alive. The public exhibit box does not. It hosts exhibits. Whether the rest of the operation is up is not its concern.

The limitation is structural. There is no uptime check of the public box that is independent of the private side doing the checking. If the private side, or the infrastructure it monitors from, is itself unavailable, nobody is observing the public box's health during that window — and the box will not notice or report that, because by design it cannot.

Filenames that cannot lie

Publicly served static media uses content-addressed filenames: the filename is derived from a cryptographic hash of the file's own bytes. The naming contract is enforced by the server, not left as a team convention.

The public media route serves a file only if its filename matches a specific pattern ending in a 64-character hexadecimal string that is the SHA-256 hash of the file's actual content. A request for a filename that does not match that pattern, or that matches the pattern but names a file that does not exist, receives a 404 with no caching instruction attached. Only a request that both matches the pattern and resolves to a real file is served, and only that response carries the long-lived immutable caching instruction — cacheable for a year, explicitly marked immutable.

Because the name is derived from the content, one filename can never legitimately name two different sets of bytes. A changed file necessarily produces a different filename. Nothing already cached at an existing path can go stale or become wrong underneath a visitor or an intermediate cache, and nothing already published at a path can be silently overwritten with different content at that same path. That is what makes a year-long immutable cache instruction honest rather than reckless.

The contract was proved rather than described. A real test file was published at its correctly hashed name and confirmed to return successfully, carrying the immutable caching instruction, with a response body whose hash matched the filename exactly. Two negative cases were confirmed alongside it: a name that is hash-shaped but does not exist returns 404 with no caching instruction, and a name that does not follow the pattern at all also returns 404 with no caching instruction. The negatives are what demonstrate the rule is enforced rather than merely documented.

The delivery network in front of the box is permitted to cache eligible static responses from this route. The origin-enforced contract — immutable caching granted only to an existing, correctly hashed name — is what actually governs correctness. The delivery network's caching is additive to that rule, not a substitute for it.

What the cutover recorded, and what is still open

At the 2026-08-29 network and TLS cutover, 11 of 11 public routes passed with 0 failures: the root page, the two exhibit applications, two application-asset requests, three site icons, the media test file, and both expected media 404 cases — the hash-shaped-but-missing name and the non-hash name. Four monitored services — the web server, both exhibit applications, and the status process — were recorded as 4 of 4 active, with zero warning-or-higher log entries across all four during the cutover window.

This is a standing system, not a completed hardening programme. What we did not re-check for this piece: the claims above rest on the box's own record of the work, and we did not re-run the audits, inspect the live firewall rule sets, or rebuild the software to confirm the stripping. Where a section calls a property a design inference rather than a measurement, that is what it is. The three public routes answered today. That confirms they are up, not that what they serve is correct, and it will not stay true by assertion.