$ uname -a · uptime
Colophon
Everything on djkimlab.com and the 8 subdomain apps runs on one laptop in my apartment, fronted by a Cloudflare Tunnel. No Vercel, no AWS, no Render. This page documents the stack so the homelab work isn't invisible.
The path of one HTTP request
The hardware
Subdomain → port table
| Subdomain | Port | App |
|---|---|---|
| djkimlab.com | 3000 | portfolio + wiki (this site) |
| ops.djkimlab.com | 3001 | Investment Operations Suite |
| radiology.djkimlab.com | 3002 | Radiology AI |
| rl.djkimlab.com | 3003 | Reinforcement Learning Lab |
| agent.djkimlab.com | 3004 | Autonomous AI Agent |
| audio.djkimlab.com | 3005 | Audio Intelligence |
| lamp.djkimlab.com | 3006 | Responsive Lamp (gaze + memory) |
| quant.djkimlab.com | 3007 | Quant Trading Platform |
| chatbot.djkimlab.com | 3008 | Consulate Chatbot |
Each row is a long-running next start (or FastAPI + Uvicorn for non-Next apps) inside its own keep-alive.sh loop.
How deploys happen
No CI/CD, no webhook, no auto-pull. The deploy is four shell lines I type after merging a PR:
git pull origin main cd app && npm install && npm run build kill $(ss -tlnp | grep ":3000 " | grep -oP 'pid=\K\d+') # keep-alive.sh sees `next start` exit and restarts it # within ~2 s, now serving the new .next/ build.
Downtime per deploy: about 2 seconds. Cloudflare's long edge cache (s-maxage=31536000 on SSG routes) means most visitors never notice.
The cloudflared service
The tunnel daemon runs as a systemd service. The auth token used to live in the unit file's ExecStart=, which made it visible to any user via /proc/$PID/cmdline. Now it sits in /etc/cloudflared/tunnel.env (mode 600, root), loaded with EnvironmentFile=, so cmdline shows only cloudflared --no-autoupdate tunnel run.
Why self-host instead of Vercel
- ›Cost — 9 separate Next apps on Vercel Hobby is over the free tier. On a laptop I already own, the marginal cost is one power outlet.
- ›Backend control — most of these apps need a long-lived FastAPI process for ML inference, WebSocket streaming, or scheduled trading cycles. Vercel functions are not the right shape.
- ›Practice — running the whole stack myself keeps the infra muscle that the CKA cert was supposed to prove.
This page's own stack
/opengraph-image/wiki/, loaded at build via gray-matterreact-markdown + remark-gfm + rehype-slug + rehype-highlightgenerateMetadata, sitemap.ts, robots.ts, dynamic OG image via next/og