Chinese Version: 中文
mkBlog is a minimalist personal blog system built with Go, Gin, GORM, Vue 3, and Vite. It serves both frontend and backend from one deployment target, uses SQLite by default, and also supports MySQL and PostgreSQL. VS Code and Obsidian uploader plugins are included for a Markdown-first workflow.
- Create, update, and delete Markdown articles
- Category filtering and pagination
- Article search
- Switchable comments
- Friend links and friend link applications
- Image upload with automatic WebP conversion
- Bearer Token protection for write APIs
- Rate limiting, blacklist mode, and Bloom filter
- TLS / HTTP3 / automatic certificate control
- VS Code / Obsidian uploader workflow
- Go 1.24
- Gin
- GORM
- SQLite / MySQL / PostgreSQL
- Vue 3
- Vite
- Element Plus
- Axios
- markdown-it
- highlight.js
.
├── main.go
├── service/
├── pkg/
├── frontend/
├── plugin/vscode/
├── plugin/obsidian/
├── static/
├── docker/
└── data/
- The server reads runtime config from
./data/config.yaml - If the file does not exist, a default config is generated automatically
- Frontend build assets are served by the Go backend
- Images are stored under
./data/static/images - An empty database is initialized with a default
Hello Worldarticle
- Go 1.24+
- Node.js 20.19+ or 22.12+ for frontend or plugin builds
- SQLite for the simplest setup
- MySQL with ngram parser for better full-text search
- PostgreSQL with zhparser for Chinese full-text search
go build -o mkBlog .
./mkBlogOn first start, mkBlog creates:
./data/config.yaml
./data/app.db
Update ./data/config.yaml and review these fields:
database.kind:sqlite3/mysql/postgresdatabase.host: file name for SQLite, host address for MySQL / PostgreSQLserver.portserver.imageSavePathserver.devmodeserver.http3_enabledtls.enabledauth.enabledauth.secretsite.signaturesite.aboutsite.avatarPathsite.serversite.comment_enabledsite.icp
cd frontend
npm install
npm run buildAfter building, copy the frontend output into the root static/ directory so it can be served by the backend.
Default address:
http://127.0.0.1:4801
If site.server is configured correctly, the frontend uses that value as the production API root.
- Default option
- No extra database service required
- Search falls back to LIKE queries
- Better suited for production deployments
- Search uses FULLTEXT + ngram parser
- Supported
- Chinese search requires zhparser
GET /api/siteGET /api/articlesGET /api/allarticlesGET /api/article/:titleGET /api/searchGET /api/categoriesGET /api/friendsPOST /api/friendsGET /api/commentsPOST /api/comments
PUT /api/article/:titlePUT /api/imageDELETE /api/article/:titlePOST /api/blockip
When auth.enabled: true, admin APIs require:
Authorization: Bearer <your-token>- Images are grouped by article title
- Uploaded non-WebP images are converted to
.webp - In article content, image paths can omit the extension
- If an extension is written manually, use
.webp - The plugins upload Markdown files together with images in same-name folders
docker build -f docker/Dockerfile -t mkblog:latest .
docker run -d --name mkblog -p 4801:4801 -v /etc/mkblog:/app/data mkblog:latestRuntime data inside the container is stored in /app/data.
- Deployments from
mainonly run when code-related directories, Docker files, or GitHub Actions workflows change - The deploy workflow runs
make releaseon the remote server - Publishing a GitHub Release automatically builds and pushes multi-architecture Docker images for
linux/amd64andlinux/arm64 - Changes under
docker/**or.github/workflows/**onmainalso trigger Docker image build and push
- Frontend and backend are served from the same origin
- Enable
tls.enabledif you want HTTPS - Configure
cert_controlif you want automated certificate management - Both VS Code and Obsidian plugins can connect to a remote mkBlog instance through Base URL settings


