Asset CDN
Operationalcritical@atrium/cdncdn.atriumad.com — client photos and reels on Hostinger shared hosting.
checked 3m ago· owner AtriumHost ↗
Checks
Host reachable
The whole CDN is down; every case study loses its media at once.
100%
24h
100%
30d
GET https://cdn.atriumad.com/robots.txtexpects 200last 200 · 130ms · 3m ago
Client asset delivery
The host answers but real client media does not — usually encoding or permissions.
100%
24h
100%
30d
GET https://cdn.atriumad.com/clients/AAHA/photos/AAHA_%20APR13%20Slide%201.jpgexpects 200last 200 · 162ms · 3m ago
What it is
Not a server we run: a document root on Hostinger that we publish to over SSH. The workspace is three Node scripts and a hardened .htaccess. Every case study that renders real media pulls it from here, which makes this the single most load-bearing piece of infrastructure in the estate — the website is static and can survive most things, but not this.
The three scripts
scripts/build.mjs— walkspublic/, warns on filenames with spaces, parens or percent signs, hard-fails on.php/.cgi/.pl/.sh/.py, then wipes and re-stagesdist/, dropping hidden files except.htaccessandrobots.txt.scripts/deploy.mjs— refuses to push ifdist/.htaccessis missing, thenrsync -az --delete --exclude clients/. The exclusion is the safety rail: client media on the server is never wiped by a deploy.scripts/manifest.ts— read-only. Enumeratespublic/clients/<CODE>/{photos,reels}and prints delivery URLs;--snippetemits a paste-readycdnAssetsrecord for the website's overrides file.
Why filenames are a recurring failure
Client media arrives with spaces, non-breaking spaces and parentheses in the filenames. Those survive rsync but need exactly one round of percent-encoding in the URL. Encoding twice produces a 404 that looks like a missing file; not encoding at all produces a 403. The build script warns about these names precisely because the failure appears later, in the browser, far from the upload.
Server hardening
public/.htaccess removes PHP handlers, disables directory indexes, 404s every dotfile, sets X-Robots-Tag: noindex, sends HSTS, caches media immutably for a year, restricts CORS to (www.)atriumad.com, and blocks hotlinking while deliberately allowing an empty Referer so next/image server-side fetches keep working.
A 403 on a directory URL is therefore correct behaviour, not an outage — indexes are off. Only asset URLs are meaningful to monitor.
Credentials
None in the repo, by design. Auth is the atrium-cdn entry in ~/.ssh/config (HostName / User / Port / IdentityFile) with the public key registered in hPanel → SSH Access. That means deploys only work from a machine that has been set up; CI cannot publish today.
When it breaks
Symptom
A specific asset 404s but the host is up
Check
Compare the URL against `bun run manifest` output for that client code.
Fix
Almost always double-encoding, or a non-breaking space in the filename. Re-run the manifest and paste the fresh URLs into lib/case-assets.overrides.ts.
Symptom
Everything on the host is unreachable
Check
Hostinger status and the hPanel file manager for the domain.
Fix
Nothing to redeploy — the files are already there. This is a hosting incident; the website will show placeholders until it clears.
Symptom
A deploy wiped something
Check
Whether the path was under clients/ — that folder is excluded from --delete.
Fix
Anything outside clients/ is reproducible from the repo: re-run bun run deploy.
Breaks when this does
- Atrium websiteThe public marketing site: home, services, work, pricing, about, resources, contact.
- Chick-in-WaffleClient case study with 44 assets on the CDN; site URL not yet registered here.
Configuration
| variable | status | purpose |
|---|---|---|
CDN_SSH_HOSTapps/atrium.cdn/scripts/deploy.mjs:27 | missing | SSH alias to publish to.Defaults to atrium-cdn, which is the real alias, so the deploy works unset. |
CDN_REMOTE_PATHapps/atrium.cdn/scripts/deploy.mjs:28 | missing | Remote document root.Defaults to domains/atriumad.com/public_html/cdn. |
CDN_PROTECTEDapps/atrium.cdn/scripts/deploy.mjs:29 | missing | Path spared by rsync --delete.Defaults to clients/. Changing this can delete client media — treat it as load-bearing. |
Where to start reading
Stage build
apps/atrium.cdn/scripts/build.mjsDeploy over SSH
apps/atrium.cdn/scripts/deploy.mjsClient asset manifest
apps/atrium.cdn/scripts/manifest.tsServer hardening
apps/atrium.cdn/public/.htaccess
In the repo
path
apps/atrium.cdnversion
files
lines
depends on
Incident history
No incidents recorded for this system.