docsify 是一个用 JavaScript 写的「运行时文档站渲染器」。它和 Hugo 这类静态网站生成器最根本的区别是:它不构建。仓库里只有一个 index.html 和一堆 Markdown 文件,访问页面时由浏览器里的 docsify 按路由去请求对应的 .md,在前端转成 HTML 显示出来。
换句话说,Hugo 是「把 Markdown 编译成 HTML 再部署」,docsify 是「把 Markdown 原样部署,打开网页时再编译」。
核心特点与优势:
零构建:没有 hugo、没有 Actions 构建步骤、没有 public/ 产物。改完 .md 推上去就是最终状态,构建这一步彻底消失。
一条 index.html 撑起全站:主题、导航、封面、插件全靠 window.$docsify 配置和几个 _ 开头的约定文件(_sidebar.md、_navbar.md、_coverpage.md)。
文件即内容:新增一篇文章就是新增一个 .md,然后在侧边栏加一行链接,不需要生成页面、不需要重新编译。
对多端写作极其友好:手机浏览器打开 GitHub 网页,编辑一个 .md 文件点 Commit,几十秒后线上就是新内容,全程不碰命令行。
插件体系:官方内置搜索、代码复制、图片缩放、Disqus / Gitalk 评论、GA4 统计,另有社区插件补翻页、标签等能力。
部署门槛最低:任何能托管静态文件的地方都能放,GitHub Pages 连 CI 都不需要。
主题可改:v5 主题基于 CSS 变量,改颜色、字体只需要覆盖几个 --xxx 变量。
但从「个人博客」角度看,必须先把它的局限说清楚,否则写到一半会想换框架:
| 维度 | docsify | Hugo |
|---|---|---|
| 构建 | 无,浏览器运行时渲染 | 有,产出完整静态 HTML |
| 博客能力 | 无原生分页 / 标签 / 归档 / RSS,都要自己维护或找插件 | 内置 taxonomy、分页、RSS、sitemap |
| 导航 | 手写 _sidebar.md,加文章要手动加一行 | 自动按目录和日期生成 |
| SEO | 弱:单页应用 + 哈希路由,搜索引擎只认一个 index.html | 强:每篇文章都是独立 HTML |
| 每页 meta | 全站共用一份 index.html 的 meta | 每页独立 title / description / OG |
| 写作体验 | 改完即生效,手机也能直接改 | 需要本地或 CI 构建 |
| 适合场景 | 文档、笔记、知识库、少量文章的个人站 | 有内容流、要被搜到的正式博客 |
结论:docsify 能当个人博客用,但它本质是文档站。文章数量少、不指望搜索引擎带流量、主要在电脑和手机上记录时,它比 Hugo 省事得多;要长期按时间流更新、要被搜到,就该回到 Hugo / Astro 那条线。
因为产物就是源码,docsify 的部署只有一件事:把 docs/ 目录原样放到一个静态托管上。没有构建、没有上传 public/,两条路线都比 Hugo 短一截。
| 维度 | 服务器 + 域名 | GitHub Pages |
|---|---|---|
| 费用 | 轻量云服务器 + 域名 | 公开仓库完全免费 |
| 国内访问 | 备案后稳定 | *.github.io 不稳定,挂自定义域名会好一些 |
| 发布方式 | rsync 整个目录(无构建) | git push 即发布,连 Actions 都不用 |
| 运维成本 | 证书、系统、Nginx | 几乎为零 |
| 适合场景 | 国内读者为主的正式站 | 随手记录、文档型站点 |
node -v 能输出版本即可。装 CLI 并生成脚手架:
bashnpm i -g docsify-cli docsify init ./docs
它会生成三个文件:index.html、README.md、.nojekyll。就这三个,没有别的。
也可以完全手动:新建目录 docs/,自己写 index.html 和 README.md,再放一个空的 .nojekyll。脚手架只是省事。
推荐的目录结构(把「博客」的部分提前规划好):
blog/ ├── docs/ │ ├── index.html # 唯一入口,全站配置都在这里 │ ├── .nojekyll # 必须,见 GitHub Pages 一节 │ ├── CNAME # 自定义域名(可选) │ ├── README.md # 首页 = 文章列表 │ ├── _coverpage.md # 首页封面 │ ├── _navbar.md # 顶部导航 │ ├── _sidebar.md # 侧边栏(必须位于根目录才能被全局复用) │ ├── _media/ # 头像、封面图、图标 │ └── posts/ # 文章,一篇一个 .md │ ├── hugo-deploy.md │ └── docsify-blog.md └── README.md # 仓库说明,不会出现在站点上
这是 v5 的完整模板,直接改内容就能用:
html<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<title>我的博客</title>
<meta name="description" content="记录与分享" />
<!-- 主题:core 必须,addons 是叠加层 -->
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify@5/dist/themes/core.min.css" />
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify@5/dist/themes/addons/core-dark.min.css" media="(prefers-color-scheme: dark)" />
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify@5/dist/themes/addons/vue.min.css" />
</head>
<body class="loading">
<div id="app"></div>
<script>
window.$docsify = {
name: '我的博客',
nameLink: 'README.md', // 项目站别写 '/',否则会跳出子路径
repo: 'https://github.com/your-name/blog',
loadSidebar: true, // 读取 _sidebar.md
subMaxLevel: 3, // 侧边栏里自动带上 h2/h3
loadNavbar: true, // 读取 _navbar.md
coverpage: true, // 读取 _coverpage.md
onlyCover: false, // true 则首页只显示封面
auto2top: true, // 切页回到顶部
homepage: 'README.md',
routerMode: 'hash', // 保持 hash,Pages 上最省事
relativePath: true, // 链接按当前目录解析,图片路径更直观
search: {
placeholder: '搜索文章',
noData: '没有找到结果',
depth: 3
},
copyCode: {
buttonText: '复制'
}
};
</script>
<script src="//cdn.jsdelivr.net/npm/docsify@5"></script>
<script src="//cdn.jsdelivr.net/npm/docsify@5/dist/plugins/search.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/docsify@5/dist/plugins/zoom-image.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/docsify-copy-code/dist/docsify-copy-code.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/docsify-pagination/dist/docsify-pagination.min.js"></script>
</body>
</html>
几个容易踩的点:
window.$docsify 必须在 docsify 主脚本之前,顺序反了配置不生效。dist/ 下:主题是 dist/themes/core.min.css,官方插件是 dist/plugins/*.min.js。v4 时代的 /dist/vue.css、/lib/plugins/ 路径已经不对了。docsify@5 会自动跟小版本;想绝对稳定就写成 docsify@5.0.0。docs/vendor/ 用本地路径。_sidebar.md(决定文章入口,博客的「导航骨」):
markdown- [首页](README.md)
- 部署
- [服务器 + 域名](posts/server.md)
- [GitHub Pages](posts/github-pages.md)
- 写作
- [多端写作](posts/multi-device.md)
- 关于
- [关于我](about.md)
缩进二级就是折叠分组;行尾可以用 :target=_blank 之类不需要,外链正常写即可。子目录里放同名 _sidebar.md 会覆盖上级,适合某一类文章有独立目录。
_navbar.md(顶部横条,适合放外链和关于页):
markdown- [首页](README.md)
- [归档](archive.md)
- [GitHub](https://github.com/your-name)
_coverpage.md(首页封面):
markdown
# 我的博客
> 记录折腾与踩坑
- 纯 Markdown 写作
- 改完即发布
- 多端同步
[开始阅读](README.md)
[GitHub](https://github.com/your-name)
背景图两种写法:在 markdown 里直接插一张图,或者用 CSS 变量 --cover-bg: url('_media/bg.jpg')。想首页直接展开正文就保持 onlyCover: false。
关于 front matter:docsify 不解析它。 照搬 Hugo 的文章头写成 ---\ntitle: xxx\n---,页面上会把这几行当正文显示出来。docsify 的做法是正文第一行写 # 标题,日期写成一行斜体即可:
markdown# docsify 部署与博客配置
*2026-10-25*
正文从这里开始。
侧边栏里链接的文字会决定浏览器标签页标题,所以标题要写清楚。
bashcd blog
docsify serve docs
# 默认 http://localhost:3000
必须用 HTTP 访问,不能双击 index.html。 docsify 通过 XHR 去取 .md,file:// 协议下会被浏览器拦截,页面只会剩个框架。没有 Node 时用 python -m http.server 3000 -d docs 也能代替。
bashssh ubuntu@1.2.3.4
sudo apt update && sudo apt install -y nginx
sudo mkdir -p /var/www/blog
sudo chown -R $USER:$USER /var/www/blog
sudo ufw allow 'Nginx Full' # 云厂商安全组同步放行 80/443
/etc/nginx/sites-available/blog.conf:
nginxserver { listen 80; listen [::]:80; server_name blog.example.com; root /var/www/blog; index index.html; location / { try_files $uri $uri/ /index.html; } # Markdown 缓存别设太长,否则改完要等缓存过期 location ~* \.(md|css|js|png|jpe?g|webp|svg|ico|woff2?)$ { expires 10m; add_header Cache-Control "public, max-age=600"; } add_header X-Content-Type-Options "nosniff" always; gzip on; gzip_types text/markdown text/css application/javascript application/json image/svg+xml; gzip_min_length 1024; }
启用:
bashsudo ln -s /etc/nginx/sites-available/blog.conf /etc/nginx/sites-enabled/
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t && sudo systemctl reload nginx
try_files ... /index.html 是给 history 路由兜底的;用默认的 hash 路由时它也不会误伤,可以放心留着。
bashsudo apt install -y certbot python3-certbot-nginx sudo certbot --nginx -d blog.example.com sudo certbot renew --dry-run
和 Hugo 一样,certbot 自动改 Nginx、自动续期。
服务器 IP 假设 1.2.3.4,blog.example.com 只需要一条记录;根域名也指向本站时才需要 @ 和 www。
| DNS 服务商 | 配置入口 | 记录 | 注意点 |
|---|---|---|---|
| Cloudflare | NS 改到 Cloudflare → DNS → Records | A blog → 1.2.3.4 | 橙云走代理时 SSL/TLS 模式必须 Full (strict),源站要有有效证书;用 Flexible 且源站强跳 HTTPS 会重定向循环。签证书期间先灰云 |
| 阿里云 / 腾讯云 | 控制台 → 云解析 DNS → 解析设置 → 添加记录 | A blog → 1.2.3.4,TTL 600 | 国内服务器必须先备案;解析生效后 80/443 才通 |
| DNSPod | 域名解析 → 添加记录,主机记录 blog,线路「默认」 | A blog → 1.2.3.4,TTL 600 | 免费版够用;改完等 TTL 过期再验 |
验证:
bashdig +short blog.example.com curl -I https://blog.example.com
bashrsync -avz --delete docs/ deploy@1.2.3.4:/var/www/blog/
就这一条。没有 hugo,没有 public/,--delete 保证删掉的文章不会残留。
Windows 上的两个坑和 Hugo 一样:Git Bash 默认没 rsync,用 scoop install rsync;或者用 tar 管道替代:
bashtar -czf - -C docs . | ssh deploy@1.2.3.4 'find /var/www/blog -mindepth 1 -delete && tar -xzf - -C /var/www/blog'
index.html 里 $docsify 在 docsify 主脚本之前docsify serve docs 能正常打开,侧边栏有内容_sidebar.md、_navbar.md、_coverpage.md 都在 docs/ 根目录,文件名带下划线没被过滤/var/www/blog 属主正确,Nginx 可读certbot renew --dry-run 通过--delete,删文章不残留docsify 是最适合 GitHub Pages 的一类站点:不需要构建,仓库里是什么,线上就是什么。
docs/ 目录:仓库名随意(如 blog),站点文件放 docs/,Pages 选 main 分支的 /docs。仓库根目录还能放脚本、草稿、备份。<用户名>.github.io,站点文件直接放根目录,Pages 选 root。访问地址是 https://<用户名>.github.io/。文章多、还想放构建脚本的,选前者;只放站点、想要最短域名的,选后者。
.nojekyll(必做)在站点根目录(docs/ 或仓库根)放一个空文件 .nojekyll。
原因:GitHub Pages 默认跑 Jekyll 处理,而 Jekyll 会忽略所有以下划线开头的文件——正好是 _sidebar.md、_navbar.md、_coverpage.md。没有它,线上表现就是「首页能开、侧边栏和封面全没了」,这是 docsify 部署最容易浪费半小时的一个坑。
bashtouch docs/.nojekyll
空文件就行,内容不重要,别有 BOM 或多余扩展名(Windows 上别存成 .nojekyll.txt)。
推送代码后:仓库 Settings → Pages:
main,目录选 /docs(或 / (root))之后每次 git push,Pages 大约几十秒到几分钟自动更新,不需要写任何 workflow。
Settings → Pages → Custom domain 填 blog.example.com,保存。GitHub 会在站点目录写入 CNAME 文件(内容只有域名,不带 https://)。
DNS 加记录:
CNAME blog → <用户名>.github.ioA @ → 185.199.108.153、.109.153、.110.153、.111.153(四条都要)解析生效后回到 Pages 勾选 Enforce HTTPS,证书由 GitHub 签发。
Cloudflare 托管 DNS 时,验证阶段建议先设灰云(DNS only);开橙云后把 SSL/TLS 模式设成 Full (strict),否则会出现「证书错误」或「重定向次数过多」。
docsify 不需要构建,所以默认不用 Actions。只有这几种情况值得加:站点文件不在 /docs、仓库是私有仓库但要发布 Pages(需要付费计划)、或者想统一走 Actions 做校验。最小 workflow:
yamlname: Deploy docsify to Pages
on:
push:
branches: ["main"]
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: "pages"
cancel-in-progress: false
jobs:
deploy:
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- uses: actions/checkout@v4
- uses: actions/configure-pages@v5
- uses: actions/upload-pages-artifact@v3
with:
path: ./docs
- id: deployment
uses: actions/deploy-pages@v4
注意:用了 Actions 发布后,Pages 的 Source 要改成 GitHub Actions;.nojekyll 依然需要放进 docs/,因为上传的是原始目录。
https://name.github.io/:_sidebar.md 里写 [首页](/README.md) 或 [首页](README.md) 都行。https://name.github.io/blog/:不要用 / 开头的绝对链接,[首页](/) 会跳到 name.github.io 根上。统一写相对路径;确实需要绝对路径时,在 $docsify 里设 basePath: '/blog/'。| 现象 | 原因 | 处理 |
|---|---|---|
| 线上首页能开,侧边栏/封面 404 | 缺 .nojekyll,下划线文件被 Jekyll 过滤 | 加空 .nojekyll,重新提交 |
本地双击 index.html 白屏 | file:// 禁止 XHR 取 .md | 用 docsify serve docs 或本地 HTTP 服务 |
| 文章点了 404 | 链接大小写、扩展名、目录层级不一致 | Linux 区分大小写,按真实文件名写 |
| 改了内容线上没变 | Pages 发布延迟或浏览器缓存 | 等 1~2 分钟强刷(Ctrl + F5) |
| 项目站里链接跳到根域 | 用了 / 开头的绝对链接 | 改相对路径或设 basePath |
| 自定义域名被清空 | 仓库里 CNAME 与 Pages 设置不一致 | 以 Settings → Pages 为准重填一次 |
| Actions 部署报环境不存在 | Pages Source 还是分支模式 | 改成 GitHub Actions 后重跑 |
| 手机上排版挤 | 缺 viewport meta | 确认 index.html 里有 width=device-width |
| 现象 | 优先检查 |
|---|---|
| 浏览器标签页标题都一样 | 侧边栏链接文字;name 配置 |
| 搜索没结果 / 只有标题命中 | search 插件按空格分词,中文长句效果差;缩短关键词,depth 调大 |
| 图片不显示 | 用相对路径 + relativePath: true;图片和文章放同一目录 |
| 侧边栏层级乱 | subMaxLevel 与 markdown 标题级别;行尾空格缩进 |
| 代码块没有复制按钮 | 漏了 docsify-copy-code 脚本,或顺序在 docsify 之后 |
| 样式发灰 / 主题没加载 | CDN 路径写成 v4 的 /dist/vue.css;v5 是 dist/themes/core.min.css |
| 中文乱码 | index.html 的 charset=utf-8,文件本身保存为 UTF-8 |
上面解决「能访问」,这一节解决「像个博客」。全部改完仍然只有那一个 index.html 加几个 md。
docsify 没有文章列表功能,首页 README.md 就是列表页。约定按「日期 + 链接」一行一篇,新文章往最上面加:
markdown# 我的博客
> 记录折腾与踩坑
## 2026
- 2026-10-25 [个人博客:docsify 部署与配置](posts/docsify-blog.md)
- 2026-07-17 [个人博客:Hugo 部署教程](posts/hugo-deploy.md)
## 2025
- 2025-12-01 [Nginx 反向代理笔记](posts/nginx-proxy.md)
文章多了之后,用一个十几行的 Node 脚本扫 posts/ 目录生成这段列表即可(读每个文件首行 # 标题 和日期行);在没有构建的体系里,这种「手动或半自动」就是代价。
markdown# 文章标题
*2026-10-25 · 标签:部署*
正文……

.md,图片放同目录,用相对文件名引用,写的时候不用记路径。docsify-blog.md),URL 会变成 /#/posts/docsify-blog,不要用中文文件名,避免转义和分享链接问题。加 docsify-pagination 插件(本文 index.html 已包含),会在每篇文章底部按侧边栏顺序给出「上一页 / 下一页」,相当于文档式的翻页。它不是「文章列表分页」,侧边栏还是全量列表。
官方 search 插件,索引的是 Markdown 原文:
jssearch: {
placeholder: '搜索文章',
noData: '没有找到结果',
depth: 3 // 索引到 h3,文章长的话调到 3~4
}
中文分词能力有限:搜「部署」准,搜「docsify 怎么部署到服务器」这种长句基本没结果。关键词短一点即可。
v5 直接用主题 addons,跟随系统:
html<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify@5/dist/themes/addons/core-dark.min.css" media="(prefers-color-scheme: dark)" />
想手动切换而不是跟随系统,就把 media 换成 JS 控制 disabled,或者自己覆盖 CSS 变量。
只改颜色和字体,用 CSS 变量,别去覆盖具体选择器:
html<style>
:root {
--theme-color: #2f6feb;
--font-family: "LXGW WenKai", "PingFang SC", sans-serif;
--content-max-width: 46em;
}
</style>
放在主题 <link> 之后、</head> 之前。侧边栏宽度、行高、代码底色都有对应变量,改之前先在浏览器里查一下实际生效的背景色。
官方内置两个插件:
docsify@5/dist/plugins/disqus.min.js,配置 disqus: 'shortname'。国内加载慢,且部分网络不可达。docsify@5/dist/plugins/gitalk.min.js + gitalk 库,基于 GitHub Issues,需要建 OAuth App,读者必须登录 GitHub 才能评论。Giscus 没有官方插件,需要自己写一个 docsify 插件,在 doneEach 钩子里把评论容器挂到 .markdown-section 末尾,并在路由切换时重建 iframe;嫌麻烦就先不放评论。
GA4 用官方插件,两行:
html<script src="//cdn.jsdelivr.net/npm/docsify@5/dist/plugins/gtag.min.js"></script>
jsgtag: 'G-XXXXXXXXXX'
需要注意 hash 路由下 /#/posts/xxx 的路径变化能正常上报,但「页面」维度会按 hash 区分,报表里看「页面路径」时要留意。
这一步要对齐预期:docsify 是单页应用,所有文章共用 index.html 的一份 meta,hash 路由的 #/... 也不会被搜索引擎当作独立页面收录。所以:
title 会被 docsify 更新(取自侧边栏链接文字),这个有效。description、OG 图、分享卡片全站同一份,写在 index.html 的 <head> 里即可。sitemap.xml 手写也只能列一个首页,收益很低;真要 SEO,换 Hugo / Astro 或把 docsify 预渲染。/#/posts/xxx 链接,微信/Telegram 会显示全站统一的标题和封面。把站点的社交分享图做好,是这份方案里性价比最高的一步(见下一节仓库配置)。
除了 Pages 那几项,仓库本身还有几个地方建议补齐:
https://blog.example.com(会显示在仓库首页,也是 GitHub 个人主页的入口);Topics 加 blog、docsify、markdown、github-pages。CNAME 文件:内容只写域名(blog.example.com),不要带协议、不要带路径、不要带换行多余字符。.nojekyll:提交进仓库,别只放在本地,也别被 .gitignore 排除。main;Pages 的分支选择和本地推送对齐,避免推了 master 而 Pages 在看 main。docs/,直接改 md 即发布」,手机端临时编辑时不用回忆结构。docsify 在这件事上比 Hugo 更顺:没有构建,就没有「这台机器没装 Hugo」的问题。
内容在 Git 仓库,写作 = 改 md,发布 = push。
任何设备改 docs/posts/xxx.md(或 _sidebar.md 加一行) → commit / push → GitHub Pages 自动更新(服务器路线则 rsync 一次) → 几十秒后线上可见
没有编译产物、没有缓存目录、没有版本对不上的可能。
| 方案 | 平台 | 优点 | 代价 |
|---|---|---|---|
| GitHub 网页 / GitHub Mobile | 全平台 | 零安装;改错字、发短文最快;可上传相册图片 | 长文编辑体验弱,Markdown 预览有限 |
| Obsidian + Git 插件 | iOS / Android / 桌面 | 本地库、双链、离线写,插件可 commit & push | 手机端冲突要手动合并 |
| Working Copy | iOS | 完整 Git 客户端,diff / push 齐全 | 推送功能付费,Android 无 |
| Termux + git | Android | 可本地跑 python -m http.server 预览 | 门槛高 |
| IntelliJ / VS Code | 桌面 | 编辑体验最好,内置 Git | 只在电脑前可用 |
实际组合和 Hugo 那篇一致:桌面主力编辑,手机用 GitHub 网页改字发短文,长文用 Obsidian 写。
两个 docsify 特有的注意点:
_sidebar.md 加一行,否则文章存在但没人能找到入口;README.md 的文章列表同理。git pull,写完立刻 push;两台设备挂着未提交改动是冲突的唯一来源。post: 文章标题;同时改了 _sidebar.md 就在同一次提交里带上。_sidebar.md 和 README.md 列表,这三处一致才算发布完成。index.html 和主题,配置类改动放桌面做。桌面端 deploy.sh(GitHub Pages 路线删掉最后一行):
bash#!/usr/bin/env bash
set -euo pipefail
msg="${1:-post: 更新}"
git pull --rebase
git add -A
git commit -m "$msg" || echo "没有需要提交的改动"
git push
# 服务器路线才需要;docsify 无需构建,直接同步 docs/
rsync -avz --delete docs/ deploy@1.2.3.4:/var/www/blog/
echo "已发布 $(date '+%F %T')"
日常流程:写完 md → ./deploy.sh "post: 标题" → 手机打开域名确认侧边栏和文章都在。手机端改完直接在 GitHub 点 Commit,Pages 那边自己会更新。
本文作者:Weee
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!