This website — A bilingual travel blog I built and host myself
I wanted one place to share my travels with friends and family in both English and Japanese, and to show employers something real I’d built. So instead of using a blogging platform, I designed and built this site from scratch, and I run it on a Linux server in a friend’s home in the US while I’m living in Japan. I initially started this project back in March 2024, as I had just started my studies abroad in Japan and wanted to share my experiences in a more open format than limiting it to a ten photo Instagram post. I had just finished taking a sequence of web dev classes at my university, so taking a leap from my final project and what I had learned during that class I set out to build my own website. After being away from developing for so long, I finally found motivation once again to finish my project and implement the functionality I originally wanted. I completely rebuilt my project from the ground up using better technologies to provide for performance and security.

A block-based editor. Posts are built from blocks: hero covers, wide banners, image-and-text splits, rows of three phone photos, rich text, and video. I can reorder blocks, crop every photo to fit its slot before uploading, save drafts and preview before publishing.
Write once, read in two languages. I write in either English or Japanese, then translate with one click through the DeepL API. I review the translation before publishing. The system remembers which source text each translation came from, so later re-translations only touch what I changed and never overwrite my own corrections.

Private space for family. Family members join by invitation only and sign in with a link emailed to them, with no passwords. They can leave threaded comments that only other family members can see. An invite works once, for one email address, and the rule is enforced in two separate places, so there’s no way to sign up uninvited.
Built with: Next.js 16 and React 19 with TypeScript, Tailwind CSS, PostgreSQL with Prisma, Better Auth, Tiptap, sharp and ffmpeg for media, DeepL, and Resend for email. It runs in Docker on a home server behind a Cloudflare Tunnel. GitHub Actions tests and builds every change automatically.
What I learned
Caching without serving stale or private data. Public pages are pre-built and cached, but anything personal is rendered fresh for each visitor, and publishing clears the cache instantly.
Privacy is a feature. Phone photos and videos contain GPS coordinates. Every upload is stripped of metadata, which I confirmed with test files that carried location data.
Running a server I can’t touch. The server is on another continent. I deploy over SSH (key-only, password login disabled), keep nightly backups, and expose the site through an outbound tunnel, so no ports are open and the site keeps working if the home IP changes.
Reproducible builds. My first CI runs failed on things that only worked on my machine. Fixing them taught me to treat the build pipeline as part of the product.