Build a professional-grade blog system from scratch. Go + Gin + Gorm backend, Next.js public blog, React admin dashboard. Implementing AI-assisted content creation, bilingual support, and CI/CD automated deployment.
Foreword
For a developer, having one's own technical blog is almost standard practice. Evolving from initially using the Hexo static blog generator to building a complete full-stack blogging system has been a journey of not just improving technical skills, but also gaining a deeper understanding of system architecture and engineering practices. This article shares the evolution of my blog system from simple to complex, along with the technical selection considerations for the final architecture.
I. Evolution: From Static to Dynamic
1.1 Pain Points of the Hexo Era
Initially, I chose Hexo, a popular static blog generator. Its advantages were clear: Markdown writing, rich themes, and simple deployment. However, as I used it more, pain points gradually emerged:
Tedious Publishing Process: Every time an article was finished, I had to run hexo generate locally, commit to GitHub, and wait for GitHub Pages deployment.
High Modification Cost: Discovering a typo required repeating the entire process.
No Online Editing: If I wanted to make changes while away from my main setup, I needed a complete development environment.
Limited Feature Expansion: Adding dynamic features like comments or statistics required relying on third-party services.
These limitations sparked the idea of building my own blogging system.
1.2 First Attempt with Express.js
Since I wanted a dynamic blog, the Node.js ecosystem was the natural first choice. I built the first version of the backend system using Express.js:
Implemented user authentication (JWT)
Completed Article CRUD APIs
Connected to MongoDB for data storage
While the features were implemented, new problems arose:
Bloated Docker Image Size: The package, including only user and article CRUD, exceeded 100MB (because the Node.js runtime had to be included), resulting in slow pulling and deployment.
Suboptimal Performance: Single request response times often exceeded 100ms.
High Resource Consumption: It strained my small-memory VPS.
1.3 Transformative Leap with Go Refactoring
After research, I decided to rewrite the backend in Go. This decision brought immediate and significant improvements:
Drastic Image Size Reduction: Dropped from 100MB+ to 40MB.
Contents
Substantial Performance Boost: Response times dropped to single-digit milliseconds.
Extremely Simple Deployment: Compiled into a single binary file, requiring no environmental dependencies.
Very Low Resource Usage: Memory consumption was less than one-third of the Node.js version.
Go's high concurrency and low resource usage allowed the blog system to run smoothly even on a cheap VPS. This refactoring profoundly highlighted that the choice of technology has a fundamental impact on system performance.
1.4 Current Architecture: A Feature-Rich Full-Stack System
Building upon the stable Go backend, I gradually added features expected of a modern blog:
AI-Assisted Creation: Integration with AI for translation, cover image generation, and optimization of titles and abstracts.
Bilingual Support (Chinese/English): A complete internationalization solution, supporting dual languages in both URL paths and the database.
Automated Deployment: A CI/CD pipeline based on GitHub Actions.
II. System Architecture Details
2.1 Overall Architecture Diagram
My blog system employs a typical front-end/back-end separation architecture, but with a unique feature: a dual front-end design.
User Request
↓
DNS Resolution
↓
┌──────────────────────┐
│ Nginx Reverse Proxy │
│ - SSL/TLS Termination │
│ - Route Distribution │
└──────────────────────┘
↓
┌─────────────┴─────────────┐
↓ ↓
┌─────────────┐ ┌─────────────┐
│ Next.js │ │ React SPA │
│ Public Blog │ │ Admin Panel │
│ (SSR/ISR) │ │ (CSR) │
└─────────────┘ └─────────────┘
↓ ↓
└─────────────┬─────────────┘
↓
┌──────────────────────┐
│ Go API Backend │
│ - Business Logic │
│ - Authentication │
│ - AI Gateway │
└──────────────────────┘
↓
┌─────────────┴─────────────┐
↓ ↓
┌─────────────┐ ┌─────────────┐
│ PostgreSQL │ │ External AI │
│ Database │ │ Vendors │
│ - Article Content │ │ - Translation │
│ - User Data │ │ - Image Gen. │
└─────────────┘ └─────────────┘
2.2 Considerations for the Dual Front-End Design
Public Blog (Next.js)
The reasons for choosing Next.js are clear:
SEO is Crucial: Technical blogs need to be indexed by search engines.
First-Contentful-Paint (FCP): Server-Side Rendering (SSR) ensures visitors see content quickly.
AI integration is now a mandatory feature for modern blogging systems. I have implemented the following capabilities:
Bilingual Translation
Automatically generate English versions after writing in Chinese, or vice-versa.
Maintain accuracy for technical terminology.
Automatic Cover Image Generation
Generates accompanying images based on the article title and content.
Ensures a unified style and good visual effect.
Title and Abstract Optimization
AI provides multiple title options.
Automatically extracts or generates article abstracts.
Prompt Generation
Creates suitable prompts for cover image generation.
These features significantly boost content creation efficiency, allowing me to focus more on the technical writing itself.
V. DevOps Practices
5.1 Containerization
All my services run in Docker containers:
Multi-Stage Builds
The Go backend's Dockerfile uses multi-stage builds:
dockerfile
# Stage 1: Build
FROM golang:alpine AS builder
# ... Compile code
# Stage 2: Run
FROM alpine:latest
COPY --from=builder /app/main .
The final image is only about 10MB and contains no compilation tools or source code.
Docker Compose Orchestration
docker-compose.yml unifies orchestration for both local development and production environments:
Go Backend Service
PostgreSQL Database
Next.js Frontend
React Admin Panel
Nginx Reverse Proxy
5.2 CI/CD Automation
Pushing a commit with a tag triggers a full deployment process:
git push origin v1.0.0
↓
GitHub Actions Triggered
↓
Build Docker Image
↓
Push to Docker Hub
↓
SSH Connect to Server
↓
Pull New Image
↓
Rolling Update Container
The entire process is fully automated, taking only a few minutes from commit to going live.
5.3 Security Measures
Nginx as Gateway
All external traffic first reaches Nginx:
SSL/TLS termination, forcing HTTPS.
Request rate limiting to prevent abuse.
Static file caching.
Routing to different backend services.
Automatic Certificate Management
Using Certbot or Acme.sh to automatically apply for and renew Let's Encrypt certificates without manual intervention.
VI. Why Choose Self-Hosting on a VPS
In an age dominated by cloud services, I still choose to self-host my blog on a VPS:
1. Fixed and Controllable Costs
Cloud services are billed based on usage, leading to unpredictable costs with high traffic.
VPS fees are fixed monthly, providing clear budgeting.
2. Complete Control
Root access allows installation of whatever is needed.
Freedom from platform restrictions, allowing flexibility in technology choices.
3. Learning Value
Building a complete system from scratch deepens operational understanding.
Accumulating full-stack knowledge in Linux, networking, and security.
4. Avoiding Vendor Lock-in
Not relying on proprietary services of specific cloud platforms.
Low migration cost; I can switch providers anytime.
5. Sufficient Performance
Personal blog traffic is limited; a small VPS is more than enough.
With proper optimization, response speed is comparable to cloud services.
VII. Technology Stack Overview
Frontend
Next.js (Public Blog)
React (Admin Panel)
Tailwind CSS (Styling Framework)
shadcn/ui, Ant Design (Component Libraries)
Backend
Go (Primary Language)
Gin (Web Framework)
Gorm (ORM)
PostgreSQL (Database)
DevOps
Docker (Containerization)
Nginx (Reverse Proxy)
Certbot (SSL Certificates)
GitHub Actions (CI/CD)
VIII. Conclusion and Outlook
The evolution from a Hexo static blog to the current full-stack system has brought me significant gains:
Technology Selection Capability: Choosing the right technology based on actual needs, rather than blindly chasing trends.
Architectural Design Thinking: Understanding the boundaries of responsibility and collaboration methods between different components.
Engineering Practice: Containerization and automated deployment are no longer just theoretical concepts.
Full-Stack Vision: A complete understanding spanning frontend to backend, and development to operations.
If you are considering building your own blogging system, I hope my experience offers some inspiration. Start simple, evolve incrementally, and enjoy the process.