A zero-config project hosting system. Drop a folder, deploy, get a subdomain. Here's what happens under the hood.
One repo, many projects, automatic subdomains.
Every folder inside projects/ becomes its own site at
<name>.info.tomas.im. No configuration needed — the
system discovers projects at build time and routes traffic at the edge.
Static HTML? Just drop the files in. React or Vite app? It detects package.json,
runs the build, and deploys the output. Want a redirect? A single redirect.json is
all it takes.
Plain HTML/CSS/JS. Copied as-is to the CDN.
Has package.json. Auto-built, output deployed.
Has redirect.json. 301 redirect at the edge.
Auto-generated at info.tomas.im from project metadata.
What happens when you visit a project subdomain.
A wildcard CNAME record (*.info.tomas.im) points all subdomains to the CloudFront distribution. DNS is managed automatically via SST + Cloudflare.
A CloudFront Function runs on every request. It reads the Host header, extracts the subdomain, and decides what to do — all in under 1ms.
The function checks three cases: if it's the root domain, serve the landing page. If the subdomain is in the redirect map, return a 301. Otherwise, rewrite the path to /projects/<subdomain>/.
The rewritten request hits S3, which serves the project files through CloudFront's global CDN. Cache headers ensure fast repeat visits.
The core routing logic, running at 400+ edge locations worldwide.
CloudFront Functions use the cloudfront-js-1.0 runtime — a stripped-down
JavaScript environment. No const or let, no arrow functions,
no async. Just var and ES5. This is what makes them sub-millisecond.
// Extract subdomain from Host header var host = event.request.headers.host.value; var parts = host.split("."); // Root domain → serve landing page if (host === "info.tomas.im") { return event.request; } var subdomain = parts[0]; // Check redirect map (built at deploy time) if (redirects[subdomain]) { return { statusCode: 301, headers: { location: { value: redirects[subdomain] } }}; } // Rewrite path → /projects/<subdomain>/... event.request.uri = "/projects/" + subdomain + uri; return event.request;
What bun run build does before deployment.
Read the projects/ directory. Classify each folder as static, buildable, or redirect based on which files it contains.
Check every folder name: lowercase, alphanumeric, hyphens only. Catch duplicates. Fail fast on errors.
Static projects are copied as-is. Buildable projects get npm install && bun run build, then the output (dist/, build/, or out/) is copied. Redirects just go into the redirect map.
Read project.json from each project, generate the landing page HTML with cards, create placeholder thumbnails, and write the redirect map JSON.
Everything that powers this system.
/projects/<name>/ structure
scripts/build.ts) and SST config, run via tsx
It takes about 30 seconds.
# 1. Create a folder mkdir projects/my-cool-site # 2. Add your files cp index.html styles.css projects/my-cool-site/ # 3. (Optional) Add metadata for the landing page cat > projects/my-cool-site/project.json << 'EOF' { "description": "A cool thing I made", "tags": ["html", "demo"] } EOF # 4. Deploy bun run deploy # → my-cool-site.info.tomas.im ✓