02 · Blog · 2026-08-02
How I Built This Portfolio Site
Building a static trilingual portfolio from scratch: Markdown as content, a web admin for updates, one-command atomic deploys, and why "static" is still the right call.
Posted on · 2026-08-02 Reading time · 1 min read Tags · Portfolio · Static Site
Why static
A portfolio should be fast and reliable. No backend, no database — the page is complete the moment it loads, and there is almost nothing to maintain.
Structure
Content lives in /zh, /en and /ja directories, with the same pages in all three languages and a one-click switcher in the header. build.py renders the Markdown and templates into static HTML, giving every page its own URL for sharing and search engines.
Markdown-first writing
Adding a post means creating one .md file:
---
title: Post title
date: 2026-08-07
tags: tag
---
Body here...
Later I added a lightweight admin backend (server/admin_server.py) that reads and writes those same Markdown files and triggers a rebuild from the browser. So day-to-day updates don't require SSH — and the source stays plain Markdown. Static and maintainable aren't mutually exclusive.
One-command deploys
bash scripts/publish.sh builds the site, then atomically swaps dist/ into /var/www/portfolio, rolling back automatically on failure. Because the deploy path is fixed and repeatable, I can change content any time without worrying about breaking the live site.
Automation: the daily briefing
Part of the blog is automated: ai-design-daily archives feed into scripts/daily_to_blog.py, which turns them into trilingual posts. The machine drafts, I polish, then it goes through the same build-and-publish pipeline. The tools do the repetitive work; I do the judgment.
Deployment
The server only needs Nginx serving static files. The ICP filing has been approved and the domain huxuancheng.top is now bound to the server; HTTPS is live as well, so the whole site is served over https.