Build a Personal Blog: Complete Roadmap

Welcome to the Build a Personal Blog series! This 8-post roadmap walks you through creating a fully-featured, self-hosted blog from an empty folder to a live website with a custom domain — without relying on Vercel, Netlify, or any managed platform.
You own the server. You own the domain. You own the data.
Why Build Your Own Blog?
Platforms like Hashnode, Dev.to, and Medium are great for getting started. But at some point, owning your content and infrastructure matters:
✅ Full control — your content, your design, your rules. No platform can change the layout, limit your storage, or shut you down
✅ Custom domain — chanh.blog instead of chanh.hashnode.dev. Looks professional, builds brand equity
✅ No vendor lock-in — your posts are plain MDX files you can migrate anywhere
✅ Real-world skills — Docker, Nginx, SSL, VPS management, DNS — things you'd configure for production apps
✅ Cost-effective — a Hostinger KVM VPS starts at ~$5-7/month. No per-seat pricing, no traffic limits
✅ Portfolio piece — the blog itself demonstrates full-stack, DevOps, and infrastructure skills
✅ PostgreSQL integration — track post views, manage subscribers, store comments — real database features platforms don't offer
What You'll Build
By the end of this series, you'll have a production blog with:
- Next.js 16 App Router — file-based routing, Server Components, metadata API
- ShadCN/UI — beautiful, accessible components built on Radix UI and Tailwind CSS
- MDX on-demand rendering — write posts in Markdown + JSX, render at request time
- PostgreSQL + Drizzle ORM — track views, manage subscribers, schema migrations
- Tag system, search, and pagination — help readers discover content
- Docker Compose — consistent dev and production environments
- Ubuntu VPS on Hostinger — full control, ~$5-7/month
- Nginx reverse proxy + SSL — HTTPS via Let's Encrypt (free)
- Custom domain —
chanh.blogregistered and configured on Hostinger
Complete Roadmap Structure
Post #1: Build a Personal Blog — Roadmap (Overview) ✅ You are here
- Why self-host instead of using a platform
- Full stack overview and architecture
- Series structure with all 8 posts
- Prerequisites and local dev setup
Phase 1: Foundation
Post #2: Phase 1 — Project Setup: Next.js 16 + ShadCN/UI
Topics:
- Scaffold with
create-next-app— TypeScript, Tailwind, App Router - Project folder structure (
app/,components/,lib/,content/) - Install and configure ShadCN/UI
- Build Header, Footer, and responsive mobile nav with Sheet
- Dark/light theme with
next-themes+ ShadCNThemeProvider - Configure
next/fontfor zero-layout-shift font loading - Site metadata with
generateMetadata()
Learning Outcomes:
✅ Scaffold a Next.js 16 App Router project with TypeScript and Tailwind
✅ Install and use ShadCN/UI components
✅ Build a responsive layout with dark mode support
✅ Configure SEO metadata for your site
Estimated Time: 2-3 days
Post #3: Phase 2 — MDX On-Demand Rendering
Topics:
- What MDX is and why it's great for blogs
- On-demand rendering vs static generation trade-offs
next-mdx-remotewith React Server Componentsgray-matterfor frontmatter (title, date, tags, description)- Syntax highlighting with
rehype-pretty-code+ Shiki - GitHub Flavored Markdown with
remark-gfm - Building the
/bloglisting page — read all MDX files - Building
/blog/[slug]— on-demand MDX compilation - Custom MDX components and frontmatter TypeScript types
Learning Outcomes:
✅ Set up MDX with on-demand server-side rendering
✅ Parse frontmatter and render post metadata
✅ Add syntax highlighting that respects dark/light mode
✅ Build a blog listing and post detail page
Estimated Time: 2-3 days
Post #4: Phase 3 — PostgreSQL + Drizzle ORM Integration (Coming Soon)
Topics:
- Why add a database alongside MDX (hybrid approach)
- PostgreSQL in Docker for local development
- Drizzle ORM vs Prisma vs TypeORM — why Drizzle wins
drizzle-orm+drizzle-kitsetup anddrizzle.config.ts- Schema design:
post_views,subscribers, optionalcomments - Running migrations with
drizzle-kit generateandmigrate - Post view counter via Server Action or API Route
- Newsletter subscriber management
- Environment variables and
DATABASE_URL
Learning Outcomes:
✅ Connect Next.js to PostgreSQL with Drizzle ORM
✅ Design and migrate a database schema
✅ Build a post view counter
✅ Manage newsletter subscribers in the database
Estimated Time: 2-3 days
Phase 2: Features
Post #5: Phase 4 — Tags, Search & Pagination (Coming Soon)
Topics:
- Tag extraction from MDX frontmatter
- Tag index page at
/blog/tags/[tag] - ShadCN/UI Badge for tag display
- Client-side search with
useStatevs server-side with?q=param - Pagination — splitting post arrays, prev/next controls
- ShadCN/UI Pagination component
- Reading time calculation
- Post sorting by date and by view count
- SEO: metadata for tag pages
Learning Outcomes:
✅ Build a tag system with dedicated tag pages
✅ Implement search with URL-based state
✅ Add pagination to the blog listing
✅ Display reading time and sort posts
Estimated Time: 2-3 days
Phase 3: Infrastructure
Post #6: Phase 5 — Docker Compose for Local Dev & Production (Coming Soon)
Topics:
- Why Docker matters even for a personal blog
- Multi-stage
Dockerfilefor Next.js standalone build docker-compose.yml—app+dbservices for local devdocker-compose.prod.yml— production overrides (restart, logging)- Running Drizzle migrations inside Docker on startup
.dockerignorebest practices- Health checks for Postgres and Next.js
- Environment variable management across environments
Learning Outcomes:
✅ Dockerize a Next.js app with multi-stage builds
✅ Run Next.js + PostgreSQL locally with Docker Compose
✅ Write production Docker Compose overrides
✅ Run database migrations automatically in Docker
Estimated Time: 2-3 days
Post #7: Phase 6 — Deploy to Ubuntu VPS on Hostinger (Coming Soon)
Topics:
- Choosing the right Hostinger VPS plan (KVM 1 vs KVM 2)
- Initial Ubuntu 24.04 server setup: SSH keys,
ufwfirewall,fail2ban - Installing Docker and Docker Compose on Ubuntu
- Cloning the repo, setting
.env.production - Docker Compose production deployment
- Nginx reverse proxy: routing traffic from port 80/443 to Next.js
- SSL certificates with Certbot (Let's Encrypt) — free HTTPS
- Zero-downtime re-deploy workflow
- Reading logs with
docker compose logs -f
Learning Outcomes:
✅ Provision and secure an Ubuntu VPS on Hostinger
✅ Install Docker and deploy with Docker Compose
✅ Configure Nginx as a reverse proxy
✅ Set up free HTTPS with Let's Encrypt
Estimated Time: 3-4 days
Post #8: Phase 7 — Custom Domain Setup on Hostinger (Coming Soon)
Topics:
- Registering a
.blogdomain on Hostinger - Hostinger DNS management panel walkthrough
- Adding
Arecords for apex andwww - DNS propagation — what to expect and how to verify
- SSL certificate covering both
chanh.blogandwww.chanh.blog - Nginx redirect from
wwwto apex domain - End-to-end testing — HTTPS, post pages, search
- Optional: Cloudflare DNS proxy for DDoS protection
- Post-launch checklist: Google Search Console, sitemap, OG previews
Learning Outcomes:
✅ Register and configure a custom domain
✅ Set up DNS records and verify propagation
✅ Redirect www to the apex domain
✅ Submit to Google Search Console
Estimated Time: 1-2 days
The Full Stack Architecture
Here's how all the pieces connect in the final blog:
Tech Stack Overview
| Layer | Technology | Purpose |
|---|---|---|
| Framework | Next.js 16 (App Router) | Routing, SSR, metadata, API routes |
| UI | ShadCN/UI + Tailwind CSS | Components and styling |
| Content | MDX + next-mdx-remote | Blog post format and rendering |
| Frontmatter | gray-matter | Parse post metadata (title, date, tags) |
| Syntax highlighting | rehype-pretty-code + Shiki | Code blocks with theme support |
| Database | PostgreSQL 17 | Views, subscribers, comments |
| ORM | Drizzle ORM + drizzle-kit | Type-safe SQL, migrations |
| Containerization | Docker + Docker Compose | Local dev and production |
| Reverse proxy | Nginx | Route HTTPS traffic to Next.js |
| SSL | Certbot (Let's Encrypt) | Free HTTPS certificates |
| Hosting | Hostinger KVM VPS | Ubuntu 24.04 server |
| Domain | Hostinger Domains | chanh.blog registration and DNS |
| Theme | next-themes | Dark/light mode toggle |
Learning Paths
Path A: Frontend-First (2-3 weeks)
For developers comfortable with React but new to infrastructure.
| Week | Posts | Focus |
|---|---|---|
| 1 | BLOG-1, BLOG-2 | Project setup and design system |
| 2 | BLOG-3, BLOG-4 | MDX content + database |
| 3 | BLOG-5, BLOG-6, BLOG-7, BLOG-8 | Features + deployment |
Path B: DevOps-First (2-3 weeks)
For developers who want to understand the infrastructure before the app.
| Week | Posts | Focus |
|---|---|---|
| 1 | BLOG-1, BLOG-6 | Overview + Docker fundamentals |
| 2 | BLOG-7, BLOG-8 | VPS deploy + domain setup |
| 3 | BLOG-2, BLOG-3, BLOG-4, BLOG-5 | App features |
Path C: Linear (8-10 days)
Follow the posts in order — one per day.
| Day | Post | Focus |
|---|---|---|
| 1 | BLOG-1 | Understand the full picture |
| 2-3 | BLOG-2 | Next.js + ShadCN/UI setup |
| 4-5 | BLOG-3 | MDX rendering |
| 6-7 | BLOG-4 | PostgreSQL + Drizzle |
| 8 | BLOG-5 | Tags, search, pagination |
| 9 | BLOG-6 | Docker Compose |
| 10 | BLOG-7 | VPS deploy + Nginx + SSL |
| 11 | BLOG-8 | Domain setup + launch |
Prerequisites
This series assumes:
- JavaScript / TypeScript basics — variables, functions, async/await, types
- Basic React knowledge — components, props, useState (even shallow is fine)
- Command line comfort —
npm install,git, navigating directories - A code editor — VS Code recommended
- No prior Docker or VPS experience required — we cover it from scratch
You do NOT need experience with Next.js, PostgreSQL, or any infrastructure tools. Each post starts from zero.
Development Setup
Before starting Post #2, install these tools:
# Node.js 20+ (use nvm for easy version management)
nvm install 20
nvm use 20
# Verify versions
node --version # v20.x.x
npm --version # 10.x.x
# Docker Desktop (includes Docker Compose)
# Download from: https://www.docker.com/products/docker-desktop/
# Verify Docker
docker --version # Docker 27.x.x
docker compose version # Docker Compose v2.x.xRecommended VS Code Extensions:
- Tailwind CSS IntelliSense — autocomplete for Tailwind classes
- Prettier — consistent code formatting
- ESLint — catch errors as you type
- MDX — syntax highlighting for
.mdxfiles - Docker — manage containers from VS Code
Why These Technology Choices?
Next.js 16 over plain React
React is a UI library. Next.js adds everything a blog needs: routing, server rendering, image optimization, metadata management, and a clear deployment path. The App Router (introduced in Next.js 13) makes server-side rendering the default — pages are fast without extra configuration.
ShadCN/UI over other component libraries
ShadCN/UI is not a traditional component library — you copy components into your project and own them. No version conflicts, no node_modules bloat, no opinionated theming you can't override. Built on Radix UI (accessible) and Tailwind CSS (utility-first). Looks great out of the box.
MDX over a CMS
MDX lets you write blog posts as Markdown files with embedded JSX components. Posts live in your git repository — versioned, portable, and searchable. No API calls to a CMS, no vendor lock-in, no monthly CMS bill. On-demand rendering means you don't need to rebuild after every post.
Drizzle ORM over Prisma
Drizzle is lightweight, TypeScript-first, and generates SQL you can read. Schema is defined in TypeScript — no separate .prisma schema file. Migrations are plain SQL you can inspect. Drizzle is also faster and has a smaller footprint, which matters on a small VPS.
Docker Compose over bare-metal install
Docker ensures the same environment in development and production. If it works in Docker locally, it works on the VPS. No "works on my machine" issues. Easy to move the blog to a different VPS or cloud provider — just clone and docker compose up.
Hostinger VPS over Vercel
Vercel is excellent for Next.js — but it charges per team member, has bandwidth limits on the free plan, and doesn't give you a real server. A Hostinger KVM VPS gives you a full Ubuntu machine for ~$5-7/month. PostgreSQL, Nginx, Docker — whatever you need. The blog series itself demonstrates skills that matter more than using a managed platform.
Common Questions
Can I use a different hosting provider? Yes. Posts #7 and #8 use Hostinger, but the Docker + Nginx + Certbot setup works on any Ubuntu VPS — DigitalOcean, Hetzner, Linode, Vultr, etc.
Can I use Vercel instead of a VPS? Yes for the Next.js app, but you'd need a separate PostgreSQL host (Neon, Supabase) and you'd skip the Docker and Nginx sections. The series is designed around self-hosting, but the app code works on Vercel too.
Do I need to buy a .blog domain?
No. You can use any domain (.com, .dev, .io) from any registrar. Posts #7 and #8 use Hostinger because the VPS and domain are in one place, but the DNS setup is the same everywhere.
What if I already know Docker?
You can move faster through Post #6. Focus on the Next.js-specific patterns (standalone build, output: 'standalone') and the Drizzle migration setup.
Can I deploy to a subdomain instead of apex domain?
Yes — blog.chanh.dev instead of chanh.blog. The Nginx config and DNS records change slightly, but the process is identical.
Related Posts & Series
This series builds on and connects to:
- React.js & Next.js Roadmap — deeper dive into React and Next.js concepts
- Docker & Kubernetes Roadmap — comprehensive Docker and container orchestration
- SQL & NoSQL Database Roadmap — database fundamentals and design
- TypeScript Full-Stack Roadmap — TypeScript patterns used throughout this series
- Relational Database Fundamentals — PostgreSQL and schema design concepts
- Bun + Hono + Neon + Upstash: Full Stack API on Vercel — alternative serverless approach
Summary
Building your own blog is one of the most complete full-stack projects you can do. It touches every layer of the stack:
- Frontend: React components, ShadCN/UI, dark mode, responsive design
- Content: MDX rendering, frontmatter, syntax highlighting
- Backend: PostgreSQL schema, Drizzle ORM, API routes, Server Actions
- Infrastructure: Docker Compose, Nginx, SSL, Ubuntu VPS
- Domain: DNS records, HTTPS,
wwwredirects
By the end of this series, you'll have a real production blog running on your own server with your own domain — and you'll understand every line of infrastructure that keeps it running.
Start with Post #2: Phase 1 — Project Setup: Next.js 16 + ShadCN/UI
Series Index
| Post | Title | Status |
|---|---|---|
| BLOG-1 | Build a Personal Blog — Roadmap | ✅ You are here |
| BLOG-2 | Phase 1: Project Setup — Next.js 16 + ShadCN/UI | ✅ Complete |
| BLOG-3 | Phase 2: MDX On-Demand Rendering | ✅ Complete |
| BLOG-4 | Phase 3: PostgreSQL + Drizzle ORM | Coming Soon |
| BLOG-5 | Phase 4: Tags, Search & Pagination | Coming Soon |
| BLOG-6 | Phase 5: Docker Compose | Coming Soon |
| BLOG-7 | Phase 6: Deploy to Ubuntu VPS on Hostinger | Coming Soon |
| BLOG-8 | Phase 7: Custom Domain Setup on Hostinger | Coming Soon |
📬 Subscribe to Newsletter
Get the latest blog posts delivered to your inbox every week. No spam, unsubscribe anytime.
We respect your privacy. Unsubscribe at any time.
💬 Comments
Sign in to leave a comment
We'll never post without your permission.