Portfolio Website
nginx · Docker · Cloudflare Tunnel
The site you are reading is hosted at home in Tokyo on a salvaged school Chromebook, exposed to the internet through a Cloudflare Tunnel with zero open ports.
View on GitHub
Internet
│
▼
┌───────────────────┐
│ Cloudflare edge │ DNS + TLS for clementcolin.com
└─────────┬─────────┘
│ tunnel (outbound-only connection,
│ established from inside the LAN)
────────────┼──────────────────────── home router: zero open ports
▼
┌───────────────────┐ docker network ┌───────────────┐
│ cloudflared │ ──────────────────────► │ nginx:alpine │
│ container │ http://web:80 │ container │
└───────────────────┘ └───────┬───────┘
│ read-only mount
./site (static files)
Acer Chromebook R752T · Linux Mint · docker compose
The machine is an Acer Chromebook Spin 511 (R752T), a fanless Celeron with 4GB of RAM, bought second-hand for ¥5,000 at a Hard Off in Tokyo. It is a locked-down school device, the kind that normally boots nothing but ChromeOS.
Reflashing the firmware
The stock firmware was replaced with MrChromebox full UEFI firmware (coreboot + edk2), which turns the locked school machine into an ordinary x86 computer that boots standard Linux. It now runs Linux Mint, with Docker on top.
Reaching the internet without open ports
A visitor resolves clementcolin.com to Cloudflare's edge, which terminates TLS. Cloudflare forwards the request through a tunnel that the cloudflared container opened from inside the home LAN, so no inbound connection ever reaches the router. cloudflared hands the request to the nginx container over a private Docker network, and nginx serves the static files from a read-only mount of the site directory.
Why this design
- No port forwarding, no dynamic DNS, and the home IP never appears in DNS.
- TLS certificates live at the Cloudflare edge, so there is nothing to renew on the box.
- Deploying an update is a git pull on the server. The site directory is mounted into nginx, so there is nothing to rebuild or restart.
- The only secret is the tunnel token, kept in a gitignored .env file.
- The Chromebook's battery doubles as a small UPS.
The stack
- Hardware: Acer Chromebook Spin 511 (R752T), fanless
- Firmware: MrChromebox UEFI (coreboot + edk2)
- OS: Linux Mint
- Runtime: Docker and docker compose
- Web server: nginx (alpine image)
- Ingress: cloudflared (Cloudflare Tunnel, free plan)
- DNS and TLS: Cloudflare edge
- Site: static HTML and CSS, no JavaScript, no build step