本地部署一个静态网站生成工具,这两年被问得越来越频繁,问的最多的就是 VuePress。我自己的个人博客和团队文档站都是用它搭的,本地开发、构建出静态文件、再决定要不要开放给外部访问,这一整套流程闭着眼都能走完。今天把完整过程写清楚:从安装 Node、初始化项目、写第一个页面,到构建产物,再到三种把站点暴露到外网的方式,每一步都有命令、有配置、有踩坑记录。你照着做,基本不会卡壳。
先说下这篇适合谁:想搭个人博客但不想折腾数据库的人,团队里要维护一套低成本文档库的人,以及前端刚入门想搞清楚“静态网站生成工具到底怎么运作”的人。VuePress 的上手门槛不高,只要会 Markdown,半小时内就能看到一个能跑起来的站点。
1. VuePress 本地部署前的方案选型与整体思路
1.1 静态网站生成工具是什么,为什么我选了 VuePress
静态网站生成工具,也就是常说的 SSG,做的事情很简单:把 Markdown 文档或数据文件作为原料,通过模板和组件渲染,在本地生成一堆纯 HTML、CSS、JavaScript 文件。这堆文件不需要数据库,不需要 PHP、Node 之类的服务端运行时,任何能托管静态文件的服务器都能直接跑。
VuePress 在同类工具里的优势很明显,它是 Vue.js 生态下的产物,核心技术栈跟做前端的人日常写的东西完全一致。默认主题直接给你配好了导航栏、侧边栏、搜索框、目录层级,这些做技术文档最常用的功能,开箱即用。而且 Markdown 里可以直接写 Vue 组件,遇到需要展示动态示例的页面会很舒服。
我拿它和身边几个工具对比过,选型时可以看这张表:
| 工具 | 技术栈 | 适合场景 | 特点 |
|---|---|---|---|
| VuePress | Vue | 技术文档、组件库文档、个人笔记 | 默认主题完善,Markdown 内嵌组件方便 |
| Hexo | Node | 纯博客站点 | 主题多、生态老,但自定义文档站比较费力 |
| Docusaurus | React | 团队文档、多版本文档 | 国际化、版本管理强,React 使用者友好 |
| Astro | 多框架 | 内容站、复杂首页 | 灵活度高,但要自己搭的东西也多 |
如果你跟我一样主要写技术文档和博客,VuePress 是性价比最高的选择。它的学习成本低到可以忽略,文档本身是中文的,遇到问题社区资料也多。
1.2 本地部署与线上托管的边界,怎么划分
很多人对“本地部署”有个误解,以为就是把服务跑在自己电脑上自己玩。实际上我日常的开发路径是分阶段的:
- 开发阶段:本地跑
vuepress dev,改一个文件浏览器立刻热更新,效率远高于在服务器上直接改。 - 内部分享阶段:构建出静态产物后,往局域网一扔,同事通过 IP 地址就能访问。
- 公网开放阶段:再做一次产物同步或端口映射,让外部访客访问。
本地部署的最大价值是可控、免费、离线也能用,数据在自己手里。但代价也明显,没有云厂商帮你扛流量和 CDN,机器断电服务就没了,公网访问还需要自己搞定入口、安全和 HTTPS。所以不用迷信某一种模式,哪个阶段用哪种方式,心里有数就行。
1.3 我最终采用的部署架构
我的思路可以概括成“本地开发、产物分发、网关接入”:个人电脑上做所有写作和 theme 调试,构建后的静态文件有两种出口。常规情况下,用rsync把产物推到云服务器,由 Nginx 托管;临时要给合作方看效果时,才用端口映射工具开一条临时公网地址,用完就关。这样既稳当又省钱。
2. 从零开始搭建 VuePress:依赖、初始化与配置
2.1 先看版本,别让 Node.js 变成第一个坑
跑 VuePress 需要 Node.js,这是绕不开的一步。如果你只装一个环境,建议直接上 Node.js 18.16 或更高的版本,因为这是 VuePress v2 的硬性要求。
先确认当前版本:
node -v npm -v如果版本偏旧,可以考虑用 nvm 来管理多版本,它能在项目之间灵活切换 Node 版本。我踩过一个典型坑:VuePress v1 在 Node 17 以上运行时会报一个跟 OpenSSL 有关的错误,这个后面常见问题里细说。简单讲,2025 年的今天新项目直接上 v2 就好。
另外提一句 npm 下载速度的问题,如果你发现官方源安装依赖很慢,可以临时换用镜像源加参数,例如:
npm install -D vuepress@next --registry=https://registry.npmmirror.com这纯粹是下载层面的加速,不影响任何其他环节。
2.2 初始化项目,搞清楚每个文件干什么
我比较推荐手工初始化,哪怕多敲两行命令,它会让知道每个文件在哪里、是干什么的。先建目录再初始化:
mkdir docs-site cd docs-site npm init -y然后安装 VuePress。v2 正式版发布后直接装 latest 就行,如果你习惯用 next 标记,也可以:
npm install -D vuepress@next等依赖装完,创建这样的目录结构:
docs-site/ ├─ docs/ │ ├─ .vuepress/ │ │ ├─ config.js │ │ └─ public/ │ └─ README.md ├─ package.json └─ .gitignoredocs是 VuePress 默认的源目录,你在里面写的所有 Markdown 文件就是站点的页面。.vuepress放配置和静态资源,README.md就是首页。.gitignore记得把node_modules和dist排除掉。
如果你想省事,官方也提供了脚手架命令npm create vuepress@latest,但新手我不建议直接用,因为脚手架帮你隐藏了太多细节,出了问题不好排查。
2.3 package.json 脚本与 config.js 关键参数
在package.json里配置两条最常用的命令:
"scripts": { "dev": "vuepress dev docs", "build": "vuepress build docs" }然后在docs/.vuepress/config.js里写入基础配置:
const { defaultTheme } = require('vuepress'); module.exports = { base: '/', lang: 'zh-CN', title: '我的文档站', description: '用 VuePress 本地部署的静态网站', host: '0.0.0.0', port: 8080, theme: defaultTheme({ navbar: [ { text: '首页', link: '/' }, { text: '指南', link: '/guide/' }, ], }), };这里几个参数值得先说清楚:
base决定资源引用的根路径。如果你部署在域名根路径,那就用/;如果要部署到https://example.com/docs/,这里必须改成/docs/,否则页面能打开但样式和脚本全部 404。host默认是localhost,这意味着只有本机能访问。想局域网访问,必须改成0.0.0.0。port是开发服务器端口,默认 8080,被占用时可以换。
3. 本地预览、构建生成静态产物与局域网访问配置
3.1 dev 模式的正确启动姿势
在你已经完成上面配置的前提下,启动命令非常简单:
npm run dev正常情况下终端会打印两条地址:
- Local:
http://localhost:8080/ - Network:
http://192.168.x.x:8080/
前者是本机访问,后者是局域网内其他设备使用的地址。如果你发现 Network 那行地址不对或者显示不出来,优先检查config.js里的host到底改成0.0.0.0没有。这一步是很多新手首次局域网访问失败的原因。
在电脑上查局域网 IP,Windows 用ipconfig,macOS 或 Linux 用ip addr或ifconfig。找到类似192.168.x.x的地址,让同一 Wi-Fi 下的手机浏览器直接访问这个地址加端口号即可。
VuePress 的 dev 模式带热更新,改 Markdown 内容浏览器会自动刷新,不需要手动重启。写长文档时这个体验非常关键,实时看到排版效果,比写完再构建高效得多。
3.2 build 构建产物,验证纯静态文件
开发完成以后,需要构建出可上线的静态产物:
npm run build默认输出目录是docs/.vuepress/dist。打开这个目录,你会看到里面全是index.html、assets之类的静态文件。这就是静态网站生成工具的效果:所有页面已经渲染成纯 HTML,不再依赖 Node 运行时。
构建完成后,你可以在本地用任意静态服务器模拟线上环境:
npx serve docs/.vuepress/dist这一步强烈建议做,因为 dev 模式下 VuePress 会帮你处理路由和各种资源路径,很多问题在 dev 下看不出来,只有以纯静态方式访问时才会暴露。
3.3 局域网访问最容易踩的防火墙坑
当你兴致勃勃把192.168.x.x:8080发给同事,结果对方打不开,十有八九是防火墙拦住了入站端口。
Windows 上的处理方式:打开“Windows 安全中心”,进入“防火墙和网络保护”里的“高级设置”,在“入站规则”中新建规则,选择“端口”,填上 8080,允许连接,应用到所有网络类型。整个过程一点不复杂,但很多人第一次操作时会卡在找不到入口。
如果用的是 Linux 服务器或开发机,常见命令是:
# ufw sudo ufw allow 8080 # firewalld sudo firewall-cmd --add-port=8080/tcp --permanent sudo firewall-cmd --reload另外提醒一句:不要为了省事直接把防火墙关了。放行指定端口就够了,关掉防火墙会带来完全没必要的安全风险。这也是我在本机折腾时最常看到的错误操作。
4. 实现外部访问:三种方案对比与完整实操
4.1 方案一:构建产物部署到云服务器,正式环境首选
这是个人站和团队文档站最常见、也最稳定的一种外部访问方式。思路是把本地构建好的静态文件用同步工具传到远程服务器,再用 Nginx 或其他静态服务器托管。
先在本机构建:
npm run build然后通过 rsync 同步到服务器,一条命令就能搞定增量同步:
rsync -av --delete docs/.vuepress/dist/ user@your-server:/var/www/my-site/注意路径末尾的斜杠,它表示把dist目录下的内容同步到目标目录,而不是把dist本身嵌套进去。--delete会让远端删除那些源端已经移除的旧文件,避免发布后残留垃圾文件。
服务器上的 Nginx 配置可以参考:
server { listen 80; server_name docs.example.com; root /var/www/my-site; index index.html; location / { try_files $uri $uri/ /index.html; } }这里核心是try_files那行,它会让请求在找不到实际文件时回退到index.html,避免刷新子页面出现 404。改完配置后执行sudo nginx -t检查语法,然后sudo systemctl reload nginx让配置生效。
这个方案的好处是所有文件都落在服务器上,访问质量和速度都受你自己控制。代价是你需要一台云服务器和一个域名。如果你暂时没有服务器,可以看下面两个方案。
4.2 方案二:路由器端口映射,把公网请求引到本地
如果你的网络环境有公网 IP,可以在路由器上做端口映射,把外部访问引导到本地运行 VuePress 的电脑。
操作步骤:进入路由器后台,找到“端口映射”或“端口转发”功能,新增一条规则。外部端口填8080,内部 IP 填你电脑的局域网地址,例如192.168.1.100,内部端口也填8080,协议选 TCP 即可。
这个方案有个前提:你的宽带给到路由器 WAN 口的 IP 必须是真正的公网 IP。很多家庭宽带其实是运营商二次分配的内网 IP,这种情况下路由器端口映射做得再对也没用。判断方法很简单,路由器 WAN 口 IP 跟你在百度上搜到的出口 IP 是否一致,一致就是公网 IP。
实际用这个方案时有两点提醒:
- 暴露给外网的一定是构建后的静态产物,而不是 dev server。开发模式有热更新调试接口等额外能力,不适合作为对外服务。
- 如果可以,优先在路由器上更换一个不常见的端口,比如
18080,这样能减少一些自动化扫描的骚扰。
4.3 方案三:用内网映射工具临时生成公网地址,适合快速演示
这是我最常用来给临时访客展示效果的方式。它可以在没有公网 IP、没有云服务器的前提下,把本地端口映射成一个公网临时地址。常见的工具有 ngrok、frp、cpolar 等,它们的使用场景都是开发者自己的项目演示和测试,操作上够简单、用完随时可以关闭。
以 ngrok 这类托管型工具为例,安装并注册后,一行命令就能把本地服务公开出去:
ngrok http 8080执行后会生成一个临时的公网域名,任何人在浏览器里打开都能访问到你本机的 VuePress 页面。这个临时域名在免费模式下每次启动会变化,适合演示完就关闭的场景。
如果你追求稳定可控,可以用 frp 这类自建映射工具。原理是:一台有公网 IP 的服务器做中转,你本地安装客户端连接到它,之后所有访问都会转发到你的电脑。服务端配置frps.ini:
[common] bind_port = 7000客户端配置frpc.ini:
[common] server_addr = your-server-ip server_port = 7000 [web] type = tcp local_ip = 127.0.0.1 local_port = 8080 remote_port = 8080再分别启动服务端和客户端,外部访问your-server-ip:8080就会落到你本地的 8080 端口。手法很简单,但要注意:这类工具要把本机服务短暂暴露给公网,必须严格限定在自己项目的演示、测试这类合规场景中使用,不要用来做任何绕过访问控制的事情,用完立刻关闭映射进程。
4.4 外部访问上线前的检查清单
不管选哪种方案,正式开放外部访问之前,我都建议过一遍自己定下的检查清单:
- 域名有没有做解析,解析是否已经生效,
ping一下确认。 - 对应端口是否放行,云服务器安全组、系统防火墙、路由器端口映射这三层都要查。
base路径和最终访问路径是否一致,子目录部署最容易翻车。- 你暴露出去的是不是静态产物,而不是开发服务器。
- 如果对外长期提供服务,建议在网关层配置 HTTPS,这个虽然不会影响访问成功率,但影响访客信任度。
- 确认有日志或者有办法在异常时立刻关掉入口,避免站点裸奔。
5. 常见问题与排查技巧实录
5.1 npm run build 报错 ERR_OSSL_EVP_UNSUPPORTED
这个报错信息很有特点,完整提示通常是:
Error: error:0308010C:digital envelope routines::unsupported原因是 Node.js 17 之后默认启用了 OpenSSL 3.0,而 VuePress v1 使用的 webpack 4 跟它不兼容。如果你还在维护 v1 老项目,临时解决办法是在命令前加一个环境变量:
NODE_OPTIONS=--openssl-legacy-provider npm run devWindows 的 PowerShell 用:
$env:NODE_OPTIONS="--openssl-legacy-provider"; npm run dev但这不是长久之计,最一劳永逸的办法是把项目升级到 VuePress v2,它是基于 Vite 的,没有这个历史包袱。
5.2 页面能打开但 CSS 和 JS 全部 404
这个坑十个人里有八个会踩。现象是首页 HTML 加载出来了,但样式全丢、排版乱成一片,点开控制台全是.css和.js资源 404。原因几乎都是base配置不对。你如果把站点部署到https://example.com/docs/,但config.js里还写着base: '/',所有资源都会从域名根路径去找,自然 404。
修复方式非常简单,打开docs/.vuepress/config.js,把base改成你实际的子路径:
module.exports = { base: '/docs/', };改完以后重新npm run build,再上传产物。一定要构建后再传,因为base是构建期写进产物里的,不是运行时配置。
5.3 端口被占用,dev 模式“悄悄”换端口
VuePress dev 模式有个行为:如果配置的端口已经被占用,它会自动往上寻找下一个可用端口。很多人没注意终端日志,以为自己访问的是 8080,结果实际服务跑在 8081,然后一顿排查发现没毛病,就是端口对不上。
检查端口占用:
# macOS / Linux lsof -i:8080 # Windows netstat -ano | findstr 8080找到占用进程后,如果是旧开发服务残留,直接结束进程再重启。不想处理旧进程的话,也可以干脆在config.js改一个不常用的端口,比如9090。
5.4 外部访问始终打不开的排查清单
当你在本地一切正常,但外部访问死活不通时,不要慌,按顺序逐层排查。我一般按照这张表来定位:
| 现象 | 可能原因 | 排查方式 |
|---|---|---|
| 外部请求无响应 | 端口未放行 | 依次检查系统防火墙、路由器端口映射、云服务器安全组 |
| 局域网能访问,公网不行 | 宽带没有公网 IP | 对比路由器 WAN 口 IP 与出口 IP 是否一致 |
| 有响应但打不开页面 | 暴露的是 dev server 而非产物 | dev 模式只建议本机用,外部访问必须用构建产物 |
| 页面乱码、样式丢失 | base配置错误 | 确认实际访问路径和构建配置中的base是否一致 |
| 刷新子页面 404 | 缺少路由回退规则 | Nginx 配置里必须写try_files $uri $uri/ /index.html; |
5.5 rsync 同步后权限导致 Nginx 403
同步完静态文件到服务器后,如果 Nginx 返回 403,多半是目录权限问题。rsync 默认会保留源文件的权限,而你本机文件的所有者跟服务器上 Nginx 运行用户不一致。
检查并修复:
sudo chown -R www-data:www-data /var/www/my-site sudo chmod -R 755 /var/www/my-site修改完记得刷新浏览器,Nginx 这类静态服务不需要重启也能生效,但权限问题要先确认文件确实能被启动 Nginx 的用户读取。
最后再分享一个我自己的使用习惯:平时所有开发和写作都在本地 dev 模式完成,构建产物用一条脚本自动 rsync 到服务器,临时给合作方演示时才用映射工具开一个公网地址,用完立即关闭。这个流程跟了我快两年,基本没有出过大问题。你只要把上面这些细节都过一遍,VuePress 本地部署加外部访问这件事,真的不算复杂。