想找一个「整站就是一堆 Markdown 文件夹、没有数据库」的 CMS,Grav 是这类里活得最久的那个。第一个版本 2014 年就有了,现在还在更新。
我把它完整装了一遍,前台四个页面、后台十个插件、品牌改成自己的,全部跑通。过程中被三件事绊住:PHP 版本、后台换框架、还有一套图标字体。
下面按我被绊的顺序写。

Grav 能干什么
一句话:一个不用数据库的 CMS——整站就是一堆 Markdown 文件加 Twig 模板,内容存在文件夹里。
按用途对号入座——
- 个人博客、随笔站:写文件就是写文章,没有后台也能干活
- 产品文档、内部知识库:按目录组织,改一篇就是改一个文件
- 公司官网、落地页:主题模板能随手改,不用等插件
- 经常要搬家的站:换服务器就是复制文件夹,不用导库、不用改连接串
- 内容想进 Git 的站:文章就是文件,谁能改、改了什么,跟着 Git 走
- 小机器上跑:没有数据库查询,缓存开着很轻
它不适合重协作的场景——多用户、评论、会员、电商,这些都得靠插件,而它的插件生态撑不起这么重的需求。
核心功能亮点
- 无数据库:内容全在
user/pages/下的 Markdown 文件里,备份就是拷文件夹 - Twig 模板:主题是 Twig 写的,改版式就是改模板,逻辑能写进去
- 后台 admin 插件:可视化管理内容、插件、主题、配置
- 蓝图(Blueprints)自定义字段:给页面类型加自定义字段,不用改代码
- 插件体系:内置十个左右常用插件,SEO、表单、分页、备份都有
- 缓存机制:开了缓存之后访问速度接近静态站
- 多语言:一个站挂几种语言,目录分开
- 媒体管理:图片上传、拖拽、自动生成缩略图尺寸
一、它是什么
- 21.1MB,解压 5025 个文件,MIT 许可,15.7k Star
- release 里有
grav-admin包,后台是打包在一起的,不用另外装插件 - 没有数据库。一个页面 =
user/pages/下一个文件夹 + 里面一个.md - 备份就是把整个目录压缩一下,搬家就是复制粘贴
写文章的体验和 Hexo 差不多,但它不需要「生成」这一步:改完 md 刷新浏览器就是新的,跟 WordPress 一样即时。
二、第一个坑:PHP 8.3 是硬拦,不是建议
我本机宝塔面板里只有 PHP 8.0 和 8.2,直接起服务,首页一片白。翻日志只有一句:
Composer detected issues in your platform:
Your Composer dependencies require a PHP version ">= 8.3.0".看着像源码下坏了,其实是 vendor/composer/platform_check.php 里的版本判断在 index.php 最前面就 exit(1) 了,连 Grav 自己的报错页都进不去。
网上不少教程还写着「Grav 要求 PHP 7.3 以上」,那是 1.x 的事了。2.x 换了新组件,8.3 起步。
处理办法是下个 Windows 便携版 PHP:
php-8.3.35-nts-Win32-vs16-x64.zip解压到 _php83/,拿 php.ini-development 生成 php.ini,打开十二个扩展(curl、fileinfo、gd、intl、mbstring、openssl、pdo_sqlite、sqlite3、zip、xml、dom、exif),然后:
../_php83/php.exe -S 127.0.0.1:8905 system/router.php关键词是必须带 system/router.php,不带的话所有路由 404。
三、装完之后长这样
首页 302 跳到 /admin —— 因为还没有管理员账号,Grav 会先把人引到后台去初始化。
内容结构很直白,一个页面是这样:
user/pages/
└── 02.blog/
├── blog.md # 列表页,指定 template: blog
└── 01.first-post/
└── item.md # 一篇文章item.md 开头是 YAML:
---
title: '文章标题'
date: '2026-10-17'
taxonomy:
tag: [Grav, 建站]
---正文就是普通 Markdown。它还认 > [!NOTE]、> [!WARNING] 这种 GitHub Alerts 语法,自带的插件会渲染成带图标的提示块,不用装额外的扩展。

文章页的排版是这样,标题、日期、标签、正文层级都由主题管,不用自己写 CSS:

四、第二个坑:后台换成了 Svelte 单页应用
这一版后台(admin2)不再是 PHP 拼 HTML,而是一个独立的 Svelte 应用,接口走 /api/v1,登录态是 JWT 存在 localStorage。
影响很直接:/admin 返回的 HTML 里没有登录表单,表单是 JavaScript 水合完才出现的。想脚本化登录,抓页面拿不到字段;想找老教程里那个 /install.php 安装向导,根本没有这个文件。
正确入口是接口:
GET /api/v1/auth/setup → {"setup_required":true, "password_policy":{...}}
POST /api/v1/auth/setup → {username, password, email} → 返回 JWT
POST /api/v1/auth/token → 后续登录密码策略是 (?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,},至少 8 位、有数字、有大写、有小写,四条缺一条建不了号。我第一次图省事用纯小写加数字,被拦了。

进去之后是这套界面,左边菜单、右边内容,主题色跟着你配的走:

编辑器是 Markdown 的,左边写右边看,工具栏有标题、加粗、表格、代码块,够用:

五、第三个坑:图标从 cdnjs 拉,国内拉不到
Quark2 主题默认引的是:
https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.1/css/all.min.css国内打开,图标全变成豆腐块或者奇怪的符号——我第一次截图,主题切换按钮渲染成两个箭头,日期前面的日历图标变成一个方块。
主题其实留了开关,blueprints.yaml 里写得很清楚:开了就找主题目录下的 css/fontawesome/all.min.css。所以把 FA 7 的 CSS 和 woff2 放进去:
themes/quark2/css/fontawesome/all.min.css
themes/quark2/css/webfonts/*.woff2配置改成:
fontawesome:
enabled: true
local: true整套 312KB,换掉一个境外请求。这个改动在包里我也做了。
六、品牌化:三层,只改一层会露馅
Grav 的品牌信息分散在三个地方,这也是它容易改出「半成品」的原因。
第一层,主题。 user/config/themes/quark2.yaml:
accent-color: '#01316F'
custom_logo:
- name: ymw-logo.pngcustom_logo 必须是数组,写裸字符串不生效,而且不报错——模板读的是 logo|first.name,取不到 .name 就静默回落成 Grav 内置的 SVG。我第一次就是在这儿浪费了十分钟,后来发现是文件都没拷进去。
第二层,站点。 user/config/site.yaml 改站名、作者、描述。顺手把日期格式也改了,system.yaml 里默认的 jS M Y 会输出 17th Oct 2026 这种英式序数,中文站看着别扭:
pages:
dateformat:
short: 'Y-m-d'第三层,后台。 这层在前台配置里找不到,它在 user/config/admin-next.yaml 的 ui.branding,只能走接口写:
PATCH /api/v1/admin-next/branding → 标题、副标题、logo 高度
POST /api/v1/admin-next/branding/logo?variant=light|dark|favicon
PATCH /api/v1/admin-next/preferences/site → accentHue / accentSaturation主色那个尤其绕:键名是扁平的驼峰 accentHue,不是 {appearance:{accentHue}} 那种嵌套。嵌套传进去接口照样返回 200,返回体是空的 {},值一个都没写进去。
还有一个小的:文章标题在 HTML 里是 <h1><a>标题</a></h1>,主题给链接加了 2px 下划线。标题一换行,下划线只挂在第一行下面,像画歪了。custom.css 补一条:
.p-name > a.u-url { text-decoration: none; color: var(--q2-accent); }七、实测结果
暗色模式整站反色,没有残留白块:

手机版 390 宽,汉堡菜单,正文单栏:

后台十个插件全在,配置分六个页签:

配置页是按「系统 / 站点 / 备份 / 媒体 / 安全 / 信息」分的,改完点保存就行,不用碰文件:

八、缺点
PHP 8.3 这个门槛会挡掉一批人。 虚拟主机、老面板、群晖自带的 PHP,大部分还在 8.0/8.1。装不上不是配置问题,是版本硬拦,报错还看不懂。
没有数据库,不是没有代价。 页面多了全靠 cache/ 顶着。我的测试站就 6 个页面,首屏 200 毫秒以内,很轻。但这个数字跟页面数量不是线性关系——Twig 编译、YAML 解析、taxonomy 索引都在请求里做。上千页的站我没试,不敢说。
后台是 SPA,老教程基本作废。 你能搜到的 Grav 教程一大半是 1.x 时代的:找 install.php、改 admin/ 目录里的模板、在主题里改 blueprints。换成 admin2 之后这些全部对不上。官方文档更新也不快,很多东西得自己读接口。
插件生态不大。 自带十个,社区插件数量跟 WordPress 没法比。要个表单、要个评论,基本都能找到,但再细分一点就没有了。
中文资料少。 官方论坛英文为主,中文教程零零散散,而且不少是 1.x 的。
备份靠压缩文件夹,没有版本概念。 这既是优点也是缺点——你可以把 user/pages 丢进 Git,但 Grav 自己不管这事。
九、自己动手的成本
装 Grav 本身不费事,解压、起服务,十分钟。真正花时间的是三件:
- 搞定 PHP 8.3。有服务器权限的下个版本就行;用虚拟主机的,先问客服支不支持 8.3,不支持就换方案
- 改三层品牌。主题、站点、后台各一处,后台那层还得走接口。这一步不熟的话,一小时起步
- 把 Font Awesome 本地化。不改也能用,就是国内打开一片方块
我这次的记录:从下载到前台四个页面出图,两个多小时;后台品牌化又花了差不多一小时,主要卡在 accentHue 那个键名上。
十、我打的这个包
为了不让下一个人再走一遍 PHP 版本那道坎,包里直接塞了一份 Windows 便携 PHP 8.3:
| 内容 | 说明 |
|---|---|
grav-admin/ | 官方原版 v2.2.10,一行没改 |
php83/ | Windows 便携 PHP 8.3.35,不用装环境 |
start.bat | 双击起站 |
README-先看我.txt | 起站、改站、上服务器、排错 |
两个小提醒:
- 建议先「转存到自己网盘」再下载——直接下载的链接容易失效,转存后就是你自己的了,随时能下;
- 手机上操作:点开链接 → 右下角「保存到网盘」→ 回夸克 App 的「我的网盘」里下载。
装之前先确认两件事:PHP ≥ 8.3(这是硬拦截,platform_check.php 会直接 exit)、user/、cache/、logs/ 几个目录可写。数据库不用准备——它根本不用数据库。
用法:解压到纯英文路径,双击 start.bat,浏览器打开 http://127.0.0.1:8905。
第一次进 /admin 会让你建管理员账号,密码要 8 位以上、有大写、有小写、有数字。
这个包我是真解压跑过的:解压 → 双击 → 服务起来 → 建号 → 前台出「Say Hello to Grav 2.0!」。中间还揪出一个 bug:router.php 里那句 require 'index.php' 是相对当前工作目录解析的,启动脚本从包根目录跑就是 500。现在 start.bat 会先 cd 进 grav-admin 再启动。
包里的内容是官方原版,不是我这个演示站。上面截图里的配色、Logo、栏目是我自己改的,改法就是第六节那三层,照做能复刻。
十一、谁适合用
Grav 的定位很清楚:你不想为一个内容站养一套数据库。
个人博客、产品文档、内部知识库、公司官网,这类内容量可控、更新不频繁、需要能随手改模板的站点,它很合适。备份复制文件夹,迁移复制文件夹,升级就是把 system/ 和 vendor/ 换掉,user/ 不动。
反过来,如果你要的是多用户协作、评论、会员、电商,那它不合适——这些都得靠插件,而它的插件生态撑不起这么重的需求。
还有一点:它不适合「完全不想碰命令行」的人。虽然日常写文章全在后台,但第一次部署绕不开 PHP 版本和权限这两件事。
包里源码保持原样,只额外加了启动脚本、说明文件和免责声明。MIT 许可,LICENSE 文件在 grav-admin/ 下面。