Production Checker · Production audit tool built on Replit by Martin StojanovskiProduction Checker · Production audit tool built on Replit by Martin Stojanovski

Production Checker · Production audit tool built on Replit

Martin Stojanovski

Martin Stojanovski

Production Checker · 10-point production audit tool built on Replit

A free, no-signup tool that audits a deployed web app against 10 production-readiness signals and returns a 0–10 score. Built and deployed end-to-end on Replit.

About

Production Checker audits any deployed web app against 10 production-readiness signals and gives it a 0–10 score. Free, no signup, takes about 30 seconds.
You paste a URL (bare domain or with https://, both work) and it runs ten parallel checks: SSL certificate validity, custom domain configuration, cold-start latency (two HEAD requests 25 seconds apart to catch sleeping deployments), WebSocket upgrade support, security headers (Helmet stack, CSP, HSTS, X-Frame-Options, Content-Type-Options), Cache-Control hygiene (immutable for hashed assets, no-cache for HTML), Open Graph metadata, robots.txt + sitemap.xml presence, real 404 handling, and SEO basics (meta description, lang attribute, structured headings).
Each check returns pass / warn / fail with a specific explanation of what was found and why it matters. The score is the weighted average across all ten.

What's built

10 production checks running in parallel — SSL, custom domain, cold-start latency, WebSocket support, security headers, Cache-Control, OG metadata, robots + sitemap, real 404 handling, SEO basics
Shareable result pages with a 16-character nanoid token in the URL — no accounts, no email harvesting, just a link to send a client or teammate
Auto-expiring reports at 30 days, with noindex,nofollow and /check/ in robots.txt Disallow so audits stay private to whoever has the link
Real /ws endpoint on the server so the tool can audit itself honestly without skipping the WebSocket check
IP-level SSRF protection — private and reserved IPv4 + IPv6 ranges are blocked at DNS resolution time, before any outbound request fires
Sliding-window rate limit of 10 audits per IP per hour
Custom Express static server in front of the Vite build, enforcing a unified header policy (CSP, X-Frame-Options, Cache-Control, Referrer-Policy) on every response — assets, SPA fallback, and 404s
Animated loading state with rotating context tips on a 4.5-second cycle, count-up animation on the score number when result pages mount

Replit-specific development and debugging

1. Custom-domain detection via DNS TXT verification
First implementation matched .replit.app / .replit.dev hostnames and walked the CNAME chain. Worked for most cases. Then I audited a custom-domain Replit app I host, and the tool flagged it as "not a Replit deployment."
Dropped into Replit's shell. dig CNAME returned nothing. dig A returned a Google Cloud Load Balancer IP. curl -I showed a GCP-fronted server signature. Every external signal pointed at GCP, not Replit. Then dig TXT returned a replit-verify= record on the domain — the missing piece. Replit's custom-domain flow doesn't always issue a CNAME; for some configurations it issues a TXT verification record at the domain or apex, with the A record pointing at Replit's GCP-fronted edge.
Rebuilt the detector with a four-layer pipeline: hostname match → CNAME chain → replit-verify= TXT on the subdomain → same TXT on the apex → HTTP header fallback. All DNS lookups run in parallel under a 6-second shared timeout. The previously misdetected app now hits the TXT layer and is correctly identified.
The bug only surfaced because I was using my own Replit-hosted production app as a real-world test case, and the fix required Replit-platform-specific knowledge of how custom domains are verified.
2. WebSocket endpoint so the tool audits itself honestly
One of the 10 checks tests WebSocket upgrade support — a Replit-specific production signal, where Reserved VM supports persistent WS connections and Autoscale doesn't. Without a real WS endpoint on the server, the tool would have scored itself a warn on its own check.
Added a real /ws endpoint to the Express server that accepts WebSocket upgrades and echoes a greeting. Chose Reserved VM specifically because of this requirement — that decision is platform-aware architecture, not a generic deployment-type pick.
The tool now passes its own WebSocket check with 101 Switching Protocols.
3. HSTS deliberately omitted to compose with Replit's edge
Most security-hardening guides say add Strict-Transport-Security at the application layer. On Replit, doing this naively can produce duplicate HSTS headers, because Replit's edge layer adds its own. If the application's max-age is lower than the edge's, the headers create a confusing downgrade signal.
Explicitly did not set HSTS in the application server, with a comment in the code explaining why. Replit's infrastructure owns TLS termination and HSTS injection at the edge, so the application should not duplicate it. The production response has a single clean HSTS header (preload-eligible, max-age 2 years), and the tool's own security-headers check passes.
The kind of decision a developer only gets right if they understand where the responsibility boundary sits between their app and Replit's edge.
4. Custom Express static server in front of the Vite build
By default, static assets from a Vite build can be served directly through Replit's edge CDN, bypassing Express middleware. CSP, X-Frame-Options, Cache-Control, and Referrer-Policy would only apply to the initial HTML route — not to JS, CSS, or image responses.
Wrote a custom Express static server (src-server/index.ts) that intercepts every response (assets, SPA fallback, 404s) and applies a unified header policy. Hashed Vite assets get Cache-Control: public, max-age=31536000, immutable; HTML gets no-cache, must-revalidate. CSP is strict (script-src 'self', no unsafe-inline), with the production HTML containing zero inline scripts to make that possible.
All security headers confirmed present on every response type.
5. Cold-start check calibrated for Replit's sleeping deployments
The cold-start audit fires two HEAD requests 25 seconds apart and compares response times. The 25-second gap is deliberately calibrated to trigger Replit's sleep behavior on Autoscale and free-tier deployments, which can cold-start anywhere from 5 to 30 seconds.
Required understanding which Replit plans sleep, how long the sleep window is, and the typical cold-start spread. Runs in parallel with the other nine checks via Promise.all — sequential blocking would have made the tool unusable.
Observed in production: warm Reserved VM round-trip of 48ms → 36ms (passes). On Autoscale or free-tier, the delta exposes cold-start latency as a scored signal.
6. DATABASE_URL via Replit Secrets, not a .env file
The Postgres connection string lives in Replit's Secrets UI. Replit injects it as an environment variable available in both the development container and the production Reserved VM, with no additional configuration. Same secret across environments automatically, never appears in checkpoint commits, never needs manual rotation.
Workflow-level Replit knowledge — understanding which platform features replace which traditional tools (.env files, secret managers, environment-specific configs) — that informs how the project is structured from the start.
7. Startup watchdog for audits interrupted by deployment restarts
Replit's Reserved VM deployments restart on redeploy. Any audit running at the moment of restart would have been left with status: 'running' in the database forever, and users polling would see a spinner that never resolves.
Added a startup watchdog: on boot, the API server runs UPDATE checks SET status = 'error', error = 'Audit interrupted by server restart' WHERE status = 'running' AND created_at < NOW() - INTERVAL '2 minutes' and logs the row count. Any check interrupted by a deployment surfaces as an error within two seconds of the next boot.
Specifically a fix for Replit's deployment-restart pattern. A long-running daemon on a traditional VPS wouldn't hit this case as often — redeploys are less frequent and typically use blue-green or rolling strategies that finish in-flight work. Recognizing that Replit Reserved VM deployments are full process restarts shaped the watchdog design.
8. Human-in-the-loop AI agent build workflow
The entire tool — architecture, all 10 check modules, security hardening, UI, deployment config, custom-domain detection — was built through structured prompting with Replit's AI agent. I acted as PM, architect, and QA rather than writing code directly.
Prompts were structured with three components: explicit "Don'ts" sections to prevent the agent from making plausible-but-wrong choices, "Verify" checklists so the agent could self-test before reporting back, and evidence-based corrections when work needed adjustment. Example: when the CNAME-only Replit detection failed on one of my custom-domain deployments, the fix prompt included the raw dig TXT output showing the replit-verify= record, not a vague "it's not detecting custom domains".
The Replit-platform-specific knowledge demonstrated throughout — deployment types, edge behavior, custom-domain DNS patterns, WebSocket support per plan, Secrets management, deployment-restart semantics — is genuine platform depth, not generic web-dev knowledge that happened to be implemented inside Replit.

Tech stack

Vite, React, TypeScript, Express, Drizzle ORM, PostgreSQL, Replit (Reserved VM Deployment, Secrets, custom domain), framer-motion, Lenis, Geist + Geist Mono, oklch color, nanoid, Helmet.

Outcome

Free public production-readiness audit tool, hosted end-to-end on Replit (Reserved VM + Postgres + custom domain), composing correctly with Replit's edge layer across security headers, custom domains, WebSocket support, and cold-start behavior. Currently scores itself 10/10. Live at productionchecker.martinstojanovski.com.
Like this project

Posted May 14, 2026

A free, no-signup tool that audits a deployed web app against 10 production-readiness signals and returns a 0–10 score. Built and deployed end-to-end on Replit.