Back to blog

Build a Personal Blog: Complete Roadmap

nextjsreactpostgresqldockervps
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 domainchanh.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 domainchanh.blog registered 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 + ShadCN ThemeProvider
  • Configure next/font for 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-remote with React Server Components
  • gray-matter for frontmatter (title, date, tags, description)
  • Syntax highlighting with rehype-pretty-code + Shiki
  • GitHub Flavored Markdown with remark-gfm
  • Building the /blog listing 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-kit setup and drizzle.config.ts
  • Schema design: post_views, subscribers, optional comments
  • Running migrations with drizzle-kit generate and migrate
  • 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 useState vs 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 Dockerfile for Next.js standalone build
  • docker-compose.ymlapp + db services for local dev
  • docker-compose.prod.yml — production overrides (restart, logging)
  • Running Drizzle migrations inside Docker on startup
  • .dockerignore best 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, ufw firewall, 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 .blog domain on Hostinger
  • Hostinger DNS management panel walkthrough
  • Adding A records for apex and www
  • DNS propagation — what to expect and how to verify
  • SSL certificate covering both chanh.blog and www.chanh.blog
  • Nginx redirect from www to 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

LayerTechnologyPurpose
FrameworkNext.js 16 (App Router)Routing, SSR, metadata, API routes
UIShadCN/UI + Tailwind CSSComponents and styling
ContentMDX + next-mdx-remoteBlog post format and rendering
Frontmattergray-matterParse post metadata (title, date, tags)
Syntax highlightingrehype-pretty-code + ShikiCode blocks with theme support
DatabasePostgreSQL 17Views, subscribers, comments
ORMDrizzle ORM + drizzle-kitType-safe SQL, migrations
ContainerizationDocker + Docker ComposeLocal dev and production
Reverse proxyNginxRoute HTTPS traffic to Next.js
SSLCertbot (Let's Encrypt)Free HTTPS certificates
HostingHostinger KVM VPSUbuntu 24.04 server
DomainHostinger Domainschanh.blog registration and DNS
Themenext-themesDark/light mode toggle

Learning Paths

Path A: Frontend-First (2-3 weeks)

For developers comfortable with React but new to infrastructure.

WeekPostsFocus
1BLOG-1, BLOG-2Project setup and design system
2BLOG-3, BLOG-4MDX content + database
3BLOG-5, BLOG-6, BLOG-7, BLOG-8Features + deployment

Path B: DevOps-First (2-3 weeks)

For developers who want to understand the infrastructure before the app.

WeekPostsFocus
1BLOG-1, BLOG-6Overview + Docker fundamentals
2BLOG-7, BLOG-8VPS deploy + domain setup
3BLOG-2, BLOG-3, BLOG-4, BLOG-5App features

Path C: Linear (8-10 days)

Follow the posts in order — one per day.

DayPostFocus
1BLOG-1Understand the full picture
2-3BLOG-2Next.js + ShadCN/UI setup
4-5BLOG-3MDX rendering
6-7BLOG-4PostgreSQL + Drizzle
8BLOG-5Tags, search, pagination
9BLOG-6Docker Compose
10BLOG-7VPS deploy + Nginx + SSL
11BLOG-8Domain 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 comfortnpm 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.x

Recommended VS Code Extensions:

  • Tailwind CSS IntelliSense — autocomplete for Tailwind classes
  • Prettier — consistent code formatting
  • ESLint — catch errors as you type
  • MDX — syntax highlighting for .mdx files
  • 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.


This series builds on and connects to:


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, www redirects

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

PostTitleStatus
BLOG-1Build a Personal Blog — Roadmap✅ You are here
BLOG-2Phase 1: Project Setup — Next.js 16 + ShadCN/UI✅ Complete
BLOG-3Phase 2: MDX On-Demand Rendering✅ Complete
BLOG-4Phase 3: PostgreSQL + Drizzle ORMComing Soon
BLOG-5Phase 4: Tags, Search & PaginationComing Soon
BLOG-6Phase 5: Docker ComposeComing Soon
BLOG-7Phase 6: Deploy to Ubuntu VPS on HostingerComing Soon
BLOG-8Phase 7: Custom Domain Setup on HostingerComing 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.