ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

自托管Wiki.js完全指南:从Docker部署到Nginx反向代理外部访问

自托管Wiki.js完全指南:从Docker部署到Nginx反向代理外部访问 1. 项目全貌为什么我要在本地搞一套 Wiki.js先说我自己的处境。团队一直缺一个能沉淀文档的地方市面上的在线文档平台用了一圈要么免费版限制协作人数要么就是数据在别人服务器上想导出还得看平台脸色。后来我接触到了 Wiki.js一个基于 Node.js 的开源 wiki 系统界面清爽、支持 Markdown、权限粒度细、还能接外部数据库最关键的是它完全开源数据掌握在自己手里。折腾完本地部署之后我用它把团队的接口文档、运维手册、新人培训资料全迁了过去顺手配好了外部访问同事在家办公也能正常打开目前稳定跑了小半年。我整理这套「本地部署 Wiki.js 并实现外部访问」的完整过程不是为了给一个照抄的教程而是把我在整个部署链路里遇到过的坑、想明白的原理、验证过的改法都写出来。无论你是刚接触自托管的新手还是已经在用 Docker 跑各种服务的进阶玩家这篇文章都能帮你少走弯路。先说几个核心思路后面全部围绕它们展开Wiki.js 本质上是一个 Node.js 应用官方推荐用 Docker 部署但手搓二进制也不是不行关键看你有没有 Node 环境。外部访问不只是「把端口暴露出去」这么简单域名解析、HTTPS 证书、反向代理、防火墙放行、安全加固一环扣一环。数据安全是底线数据库、上传的图片附件、配置文件这三样东西必须在部署第一天就做好备份方案。2. 部署方案选型Docker Compose 一步到位但原理必须懂2.1 为什么我最终选了 Docker Compose 而不是二进制安装Wiki.js 官方文档提供了两种主流安装方式一种是直接下载安装包跑在已有 Node.js 环境里另一种是 Docker 容器化部署。我一开始试过二进制方案因为手头恰好有一台闲置的 Ubuntu 服务器Node 版本也符合要求。但实际操作下来二进制方案的依赖管理比想象中繁琐——需要单独处理 Node 版本、npm 全局包、系统服务注册升级版本时还要手动停服务、替换文件、迁移数据库整套流程对新手非常不友好。Docker Compose 方案则完全不同。一个docker-compose.yml文件定义了应用容器和数据库容器一条docker compose up -d命令就能启动整套服务。后续升级只需要拉新镜像、重建容器数据库结构由 Wiki.js 启动时自动迁移省心得多。我的建议是如果只是自己用、或者小团队使用无脑选 Docker Compose如果公司有严格的运维规范、必须用 systemd 管理服务那再考虑二进制方案。2.2 数据库选型PostgreSQL 还是 SQLiteWiki.js 同时支持 PostgreSQL、MySQL、MariaDB、SQLite 和 SQL Server。官方推荐生产环境用 PostgreSQL原因很直接PostgreSQL 的并发读性能好、支持 JSON 数据类型、外键约束完整而且 Wiki.js 的全文搜索功能在 PostgreSQL 下的匹配质量更好。SQLite 适合极轻量的个人笔记场景——单文件数据库、零配置但一旦多人同时编辑或者历史版本记录多了SQLite 的写入锁竞争会非常明显。我这次部署用的是 PostgreSQL 16配合 Docker 官方镜像postgres:16-alpine。选 Alpine 版本会小很多但还是建议在docker-compose.yml里固定具体的小版本号比如16.4-alpine避免将来某天latest标签指向一个大版本变更导致数据库不兼容的尴尬。提示如果你还没有 Docker 环境先到 Docker 官网下载 Docker DesktopWindows/macOS或者用包管理器安装 docker-ceLinux装完记得运行docker compose version确认 Compose 插件可用。这是所有后续步骤的前提。3. 实操过程从零部署 Wiki.js 并打通外部访问3.1 目录结构和 docker-compose.yml 的完整写法我习惯把所有自托管服务的目录统一放在/opt下便于维护和备份。本次的目录结构如下/opt/wikijs/ ├── docker-compose.yml ├── .env └── data/ ├── pg-data/ # PostgreSQL 数据目录 └── wiki-data/ # Wiki.js 上传的图片、附件等docker-compose.yml的核心内容如下我直接把注释也写进去了方便你理解每一项的作用version: 3.8 services: db: image: postgres:16-alpine container_name: wikijs-db restart: unless-stopped environment: POSTGRES_DB: wiki POSTGRES_USER: wikijs POSTGRES_PASSWORD: ${DB_PASSWORD} # 从 .env 读取 volumes: - ./data/pg-data:/var/lib/postgresql/data healthcheck: test: [CMD-SHELL, pg_isready -U wikijs -d wiki] interval: 10s timeout: 5s retries: 5 wiki: image: requarks/wiki:2.5 container_name: wikijs restart: unless-stopped depends_on: db: condition: service_healthy ports: - 3000:3000 environment: DB_TYPE: postgres DB_HOST: db DB_PORT: 5432 DB_NAME: wiki DB_USER: wikijs DB_PASSWORD: ${DB_PASSWORD} volumes: - ./data/wiki-data:/wiki/data.env文件里放敏感信息DB_PASSWORD此处替换为强密码这里有几件事必须单独拎出来讲depends_on配合healthcheck非常关键。如果不加健康检查Wiki.js 容器可能在 PostgreSQL 还没完成初始化时就开始连接数据库启动大概率失败。加了service_healthy条件后Compose 会等待 PostgreSQL 进入 healthy 状态才启动 Wiki.js。restart: unless-stopped保证服务异常退出后自动拉起。服务器重启后 Docker 也会自动启动这两个容器省去手动操作的烦恼。端口映射的3000:3000是内网访问的基础但外部访问时我不会直接暴露3000端口这一点放在后面反向代理部分细说。注意PostgreSQL 的数据目录映射到宿主机后容器重建不会丢数据。但对应的权限问题很折磨人——容器内的postgres用户 UID 是999宿主机目录如果权限不对容器直接拒绝启动。遇到Permission denied时先检查宿主机目录属主和属组或者干脆chown 999:999 ./data/pg-data。3.2 启动服务与初始化 Wiki.js配置文件就绪后在/opt/wikijs目录下执行docker compose up -d第一次启动会拉取镜像网络状况正常的话几分钟内完成。查看容器状态docker compose ps两个容器都显示 running 且 healthy数据库容器后打开浏览器访问http://服务器IP:3000这时候会看到 Wiki.js 的安装引导页面。按页面提示完成以下操作设置管理员邮箱和密码这里会要求密码复杂度较高别偷懒后面要用来登录后台。确认站点名称比如「团队知识库」。选择系统语言Wiki.js 自带中文界面可以直接选简体中文。初始化完成后你会进入 Wiki.js 的主界面。此时系统是「裸」状态建议先去「管理」-「存储」里确认数据库连通正常再到「管理」-「主题」里挑一个喜欢的视觉风格。这些操作都是图形界面的没有难度我就不展开讲了。3.3 本地访问通了的下一步外部访问的方案对比本地能访问只是第一步。如果你只在局域网里用到这步就已经可以收工了如果需要在外网访问我梳理了几种常见方案优缺点都列出来了方案优点缺点适用场景路由器端口映射 动态域名成本低、可控性强需要路由器后台操作、可能需要备案、家用宽带 IP 变化要处理有公网 IP 的家庭/小型办公室云服务器反向代理稳定、可备案、带宽可控需要额外买服务器对可用性有要求的团队内网穿透工具frp/ngrok 类不需要公网 IP部署简单依赖中转服务器速度取决于服务商临时演示或没有公网 IP 的环境我最终选择了云服务器反向代理的组合因为团队已经有了一台云服务器随手就能用。如果你用的是家用宽带且确定运营商分配了公网 IP那「光猫桥接路由器端口映射DDNS」完全够用成本和门槛都低不少。顺带说一句备案的事如果你部署在国内服务器且使用了域名解析到国内 IP按照监管要求域名需要完成 ICP 备案才能正常用 80/443 端口提供服务。如果不想折腾备案要么用海外服务器要么就做好访问来源控制只允许特定 IP 段访问。方案取舍看你自己的实际情况。3.4 反向代理配置用 Nginx 把 80/443 流量转给 Wiki.js我不用3000端口直接对外因为直接暴露应用端口会有几个实际的问题浏览器地址栏带端口号既不好看也不专业。未来同一台服务器上可能要跑多个 Web 服务80/443 端口只有一个必须靠反向代理做域名转发。HTTPS 证书统一在 Nginx 层配置比在 Wiki.js 里逐个配置省事得多。Nginx 安装就不重复说了重点贴出关键配置。在/etc/nginx/conf.d/里新建wiki.confserver { listen 80; server_name wiki.example.com; # 强制跳转 HTTPS return 301 https://$host$request_uri; } server { listen 443 ssl http2; server_name wiki.example.com; # 证书路径由 certbot 自动生成和续期 ssl_certificate /etc/letsencrypt/live/wiki.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/wiki.example.com/privkey.pem; # 上传文件大小限制默认 1m 不够Wiki.js 上传图片容易失败 client_max_body_size 50m; location / { proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # WebSocket 支持Wiki.js 后台实时通知依赖这个 proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; } }配置完成后测试语法并重新加载nginx -t systemctl reload nginx关于 HTTPS 证书我用的是 Lets Encrypt 免费证书certbot 自动签发和续期。签发命令大概是certbot --nginx -d wiki.example.comcertbot 会自动修改 Nginx 配置并加载证书后续证书到期前也会自动续期基本不用管。提示如果你暂时不打算上 HTTPS也请至少用 HTTPS。因为 Wiki.js 登录是基于 Cookie 的明文 HTTP 下任何中间人都能抓到你登录后的会话凭证。公网环境裸奔 HTTP 等于把管理员后台拱手送人。3.5 防火墙、安全组与 DNS 解析的最后一公里Nginx 配置好了但外网还是不一定能访问问题大概率出在防火墙和 DNS 这两个环节。先确认 DNS 解析dig wiki.example.com或者用nslookup看看解析结果是否指向你的服务器 IP。如果指错了去域名服务商的控制台改 A 记录。再查服务器防火墙。这里要区分「系统防火墙」和「云厂商安全组」两个层面缺一不可# 查看系统防火墙是否放行 80/443 firewall-cmd --list-all # CentOS/Fedora ufw status # Ubuntu/Debian # 放行命令示例Ubuntu sudo ufw allow 80/tcp sudo ufw allow 443/tcp sudo ufw reload云厂商安全组的话比如阿里云或腾讯云需要在控制台「安全组」里添加入方向规则放行 TCP 80 和 443 端口。这一步做完理论上外网就能访问https://wiki.example.com了。4. 日常使用中的常见问题与排查技巧4.1 容器起不来端口占用和数据库健康检查失败是重灾区我遇到过两次意料之外的坑一次是服务器上已经有另一个服务占了3000端口。排查过程很简单ss -tlnp | grep 3000找到占用进程后要么换 Wiki.js 的映射端口比如3001:3000要么处理掉冲突服务。另一次是数据库容器反复重启查看日志docker logs wikijs-db发现报错是数据目录权限问题。解决方式就是之前提到的检查宿主机目录属主属组必要时强制调整。4.2 外网访问不通先本机 curl再逐层排查外部访问失败时我最常用的排查顺序在服务器本机执行curl -I http://localhost:3000确认 Wiki.js 服务正常。再执行curl -I http://127.0.0.1确认 Nginx 转发正常。检查防火墙和安全组是否放行端口。从外部机器ping服务器 IP 和telnet 服务器IP 443测试连通性。绝大多数时候问题都出在安全组规则或系统防火墙没有放行端口反代配置本身反而是最可靠的一环。4.3 手动备份数据库和文件目录分开处理Wiki.js 的所有内容都存在数据库里但上传到 Wiki.js 的附件和图片是存在文件系统的/wiki/data映射到宿主的./data/wiki-data所以完整备份必须两者兼顾。我写了一个简单的备份脚本核心逻辑如下#!/bin/bash BACKUP_DIR/opt/backups/wikijs DATE$(date %Y%m%d%H%M) mkdir -p $BACKUP_DIR # 备份 PostgreSQL docker exec wikijs-db pg_dump -U wikijs -d wiki $BACKUP_DIR/wiki_db_$DATE.sql # 备份上传文件 tar czf $BACKUP_DIR/wiki_files_$DATE.tar.gz -C /opt/wikijs/data wiki-data # 清理 7 天前的备份 find $BACKUP_DIR -type f -mtime 7 -delete定时任务用 crontab 挂上每天凌晨两点运行。恢复时先创建新容器再pg_restore注入数据库备份解压文件覆盖即可。注意备份脚本运行前先确认宿主机装了pg_dump或者直接用docker exec调容器内的 pg_dump避免版本不一致导致备份文件无法恢复。4.4 权限问题Wiki.js 后台管理员的几个小坑还有两个后台相关的坑提一下都是实际工作中很容易遇到的忘记管理员密码如果只有这一个管理员账号可以进入postgres容器手动更新数据库里对应用户记录但操作比较复杂。最省事的办法是直接在docker-compose.yml里暂时加一个环境变量WIKIJS_ADMIN_EMAIL和WIKIJS_ADMIN_PASSWORD重建容器后用这个新账号登录再重置原账号密码。这个功能官方支持叫「初始管理员重置」。权限粒度设置Wiki.js 的权限模型是按「组」来分配权限的新人入职时直接拉进「authors」组只给编辑权限别给删除权限。别省这一步日后人多手杂时能省很多心。5. 安全加固与日常维护的几点补充5.1 开启两步验证2FAWiki.js 后台支持 TOTP 两步验证。登录管理员账号后在「管理」-「安全」里强制开启两步验证这样即使账号口令泄露攻击者也过不了验证码这一关。对这一层安全有顾虑的团队强烈建议全员开启。5.2 限制后台管理路径的访问来源如果团队的办公出口 IP 是固定的可以进一步在 Nginx 层做来源限制。只允许特定 IP 访问/login路径location /login { allow 办公出口IP; deny all; proxy_pass http://127.0.0.1:3000; }这样外部任何人想登录后台都会被 Nginx 直接拒绝。不过这个方案只适用于固定 IP 的场景如果团队成员经常出差、IP 不固定就不要这么搞。5.3 升级策略升级前先备份升级后先验证Wiki.js 更新频率不算低每次升级我都是这么操作的先跑一遍备份脚本确保数据库和文件都在。修改docker-compose.yml里的镜像版本号。docker compose pull docker compose up -d。打开页面确认登录正常、几篇核心文档能正常读。跑一遍搜索确认全文索引没坏。这套流程耗时不到十分钟但能挡住绝大多数升级翻车的风险。6. 一个容易被忽略的扩展玩法把它做成团队知识库的真正入口部署完成只是开始怎么让它真正落地才是重点。我这里可以分享几个基于 Wiki.js 的实用玩法用「导航栏」组织知识结构Wiki.js 支持在顶部导航栏自定义分组我会把「新人指南」「系统架构」「接口文档」「运维手册」「会议纪要」放进去让每个成员一进站就能找到入口。启用评论和修订记录Wiki.js 自带页脚评论功能和历史版本对比特别适合团队协作。每个人对文档的修改都会被记录可回溯、可恢复团队拿它当协作工具完全没问题。配合外部工具做定时备份到对象存储备份脚本生成的文件可以再传一份到云对象存储桶异地容灾防止服务器磁盘故障导致数据全丢。我在实际使用中还发现Wiki.js 的搜索对中文支持还算可以但如果你要更智能的语义检索可以结合一些大模型项目来做知识库问答这个方向现在热得不行。把 Wiki.js 作为知识底座再用大模型接口做对话式检索就是一套轻量的企业级知识中台。我个人的体会是部署这套系统这件事本身不难难的是坚持把文档写进去、把更新维护变成团队习惯。工具只是载体知识沉淀才是最终目的。最后再分享一个小技巧如果某一天 Wiki.js 打开页面一直转圈先看容器日志docker logs -f wikijs多数是数据库连接数满或者磁盘满了。清一下日志、扩容磁盘一般都能救回来。
返回列表