home about projects blog contact
building-a-self-hosted-blog.md

Building a Self-Hosted Blog with Vite

January 5, 2025
vitejavascriptself-hosting

I recently added a blog to my portfolio site. Here's how it works.

The Goal

I wanted a blog that:

  • Uses markdown for writing posts
  • Has syntax highlighting for code
  • Generates static HTML (no client-side rendering)
  • Fits the existing terminal aesthetic

The Stack

The implementation uses three key libraries:

  • marked - Markdown to HTML conversion
  • highlight.js - Syntax highlighting for code blocks
  • gray-matter - Parsing YAML frontmatter

How It Works

Posts are written as markdown files in src/posts/:

---
title: "Post Title"
date: "2025-01-05"
description: "A short description"
tags: ["tag1", "tag2"]
---

Your content here...

At build time, a Node script processes each post:

import { marked } from 'marked';
import hljs from 'highlight.js';
import matter from 'gray-matter';

// Configure syntax highlighting
marked.setOptions({
  highlight: function(code, lang) {
    if (lang && hljs.getLanguage(lang)) {
      return hljs.highlight(code, { language: lang }).value;
    }
    return hljs.highlightAuto(code).value;
  }
});

// Parse frontmatter and content
const { data, content } = matter(fileContent);
const html = marked(content);

The Result

Each post becomes a static HTML page at /blog/post-slug/. The listing page at /blog/ is also pre-rendered with all post cards.

No JavaScript required to read posts. No API calls. Just static HTML served by Nginx.

Why Static?

For a personal blog, static generation makes sense:

  • Fast - No server-side rendering, just files
  • Simple - No database, no backend to maintain
  • Reliable - If Nginx is up, the blog is up
  • Cheap - Minimal resources needed

The only downside is needing to rebuild when adding posts. But with a CI/CD pipeline, that's just a git push away.

Built with Vite + Tailwind CSS

Self-hosted on personal infrastructure