Overleaf部署实战指南
本文详细记录了在 fnOS NAS 上自建 Overleaf 6.2.2 社区版的完整实战过程,涵盖架构规划、overleaf-toolkit 部署、数据目录迁移、TeX Live 宏包安装与持久化、管理员账号创建及 Lucky 反向代理配置,并总结了 7 个关键踩坑点与解决方案。
部署环境:fnOS(基于 Debian 深度定制)NAS · 2026-08-24 最终成果:Overleaf 6.2.2 社区版 + TeX Live 2026 全量宏包 + 域名 HTTPS 外网访问 + 多人协作 阅读对象:想在 NAS 上自建 Overleaf 的人
一、为什么要在 NAS 上自建 Overleaf
Overleaf 是在线 LaTeX 编辑器,官方 SaaS 版有诸多限制(免费版编译慢、不能调宏包)。自建社区版(CE)的好处:
- ✅ 完全免费、无限项目、私有部署
- ✅ 可自由安装 TeX 宏包(ctex 中文支持等)
- ✅ 多人实时协作(类似 Google Docs 的 LaTeX 版)
- ✅ 数据完全掌握在自己手里
二、架构总览
外网用户 (IPv6)
│
▼
┌──────────────────────┐
│ Lucky 反代 (fnOS 应用)│ ← 443 端口,HTTPS 终止
│ overleaf.epochwl.top │ ← ZeroSSL 正式证书
└──────────┬───────────┘
│ 反代转发
▼
┌──────────────────────┐
│ sharelatex 容器 │ ← 18080:80
│ (Overleaf 6.2.2) │
└──────┬────────┬───────┘
│ │
┌──────▼──┐ ┌───▼──────┐
│ mongo 8 │ │ redis 7 │
└─────────┘ └──────────┘端口规划(fnOS 上避免冲突):
- Overleaf Web:
18080(避让 8080/8081/8890 等) - Lucky 管理:
16666 - Lucky 反代:
443 - mongo/redis:容器内网互连,不暴露宿主机
三、第一步:拉取部署(overleaf-toolkit)
官方推荐用 overleaf-toolkit 部署:
git clone https://github.com/overleaf/toolkit.git
cd toolkit
# 配置
cp config/overleaf.rc.example config/overleaf.rc
cp config/variables.env.example config/variables.env关键配置项
config/overleaf.rc:
OVERLEAF_DATA_PATH=/vol1/1000/docker/overleaf/overleaf
MONGO_DATA_PATH=/vol1/1000/docker/overleaf/mongo
REDIS_DATA_PATH=/vol1/1000/docker/overleaf/redis
GIT_BRIDGE_DATA_PATH=data/git-bridgeconfig/variables.env(核心):
OVERLEAF_SITE_URL=https://overleaf.epochwl.top # ← 最终访问地址
OVERLEAF_NAV_TITLE=Overleaf
OVERLEAF_ADMIN_EMAIL=minlonghuo@gmail.com
OVERLEAF_BEHIND_PROXY=true # ← 反代模式(必须)
# 注意:OVERLEAF_SECURE_COOKIE 绝对不能设!见踩坑 #7启动
bin/up -d⚠️ 坑 #1:国内网络拉 Docker 镜像
sharelatex/sharelatex:6.2.2(约 3GB)可能很慢或超时。建议配置 Docker 国内镜像加速器(如 docker.m.daocloud.io、registry.cn-hangzhou.aliyuncs.com),或用docker pull分步拉取。
四、第二步:数据目录迁移(关键!)
为什么必须迁移
overleaf-toolkit 默认把数据放在 toolkit/data/ 下(也就是应用安装目录里)。但 fnOS 上:
/vol1/docker是系统路径,文件管理器不可见,备份/管理不便- 用户可见的数据目录是
/vol{N}/<uid>/形式(如/vol1/1000/) - 升级/卸载应用可能清掉数据目录
迁移步骤
# 1. 先停止服务
cd overleaf-toolkit && bash bin/stop
# 2. 建目标目录(用户可见)
mkdir -p /vol1/1000/docker/overleaf/
# 3. 移动各数据子目录(保留权限)
mv toolkit/data/overleaf /vol1/1000/docker/overleaf/overleaf
mv toolkit/data/mongo /vol1/1000/docker/overleaf/mongo
mv toolkit/data/redis /vol1/1000/docker/overleaf/redis
mv toolkit/data/git-bridge /vol1/1000/docker/overleaf/git-bridge
# 4. 改 overleaf.rc 指向新路径(见上文配置)
# 5. 重新启动
bash bin/up -d⚠️ 坑 #2:迁移后必须删容器重建(
docker rm -f sharelatex mongo redis && bin/up -d),因为 docker volume 挂载关系在容器创建时就已经固定,改配置文件后bin/restart不生效。
💡 最终目录结构(本机):
/vol1/1000/docker/overleaf/ ├── overleaf/ # Overleaf 应用数据(项目、用户上传) ├── mongo/ # 用户/项目数据库 ├── redis/ # 缓存 └── texlive/ # TeX Live 宏包(持久化挂载,见踩坑 #4)
五、第三步:TeX Live 宏包安装(最大的坑)
Overleaf 社区版自带 TeX Live 2026,但只有基础包,没有 ctex(中文)、float、booktabs、tikz 等常用宏包。装这些需要 tlmgr。
5.1 踩坑:容器重建 = 宏包全丢
⚠️ 坑 #3(最重要的坑):sharelatex 容器是无状态的,tlmgr 装的宏包写在容器可写层。只要容器被删除重建(docker rm -f),所有手动安装的宏包全部丢失!表现就是:昨天还能编译的中文文档,今天报
File 'ctexart.cls' not found。
解决方案:把 texlive 目录持久化挂载到宿主机:
# 1. 先把容器内的 texlive 复制到宿主机(一次性)
mkdir -p /vol1/1000/docker/overleaf/texlive
docker cp sharelatex:/usr/local/texlive/. /vol1/1000/docker/overleaf/texlive/
# 2. 修改 docker-compose.base.yml,加一行挂载
# 文件:overleaf-toolkit/lib/docker-compose.base.yml
# 在 volumes 部分追加:
# - "${TEXLIVE_DATA_PATH:-/vol1/1000/docker/overleaf/texlive}:/usr/local/texlive"
# 3. 重建容器生效
docker rm -f sharelatex && bash bin/up -d这样以后容器重建,宏包都还在。
5.2 踩坑:tlmgr 卡死(默认源被墙)
⚠️ 坑 #4:tlmgr 默认用
https://mirror.ox.ac.uk/sites/ctan.org/...(英国镜像),国内网络访问极慢甚至卡死——进程看着在跑(ps有 perl 进程),但 CPU 时间几乎不动,等 13 分钟毫无进展。
解决方案:切换国内镜像源(清华/中科大):
# 清华镜像(推荐,实测 52 个包 13 秒装完)
tlmgr option repository https://mirrors.tuna.tsinghua.edu.cn/CTAN/systems/texlive/tlnet
# 或中科大
tlmgr option repository https://mirrors.ustc.edu.cn/CTAN/systems/texlive/tlnet验证连通性的命令(装之前先测):
curl -s -o /dev/null -w "%{http_code} %{time_total}s\n" \
https://mirrors.tuna.tsinghua.edu.cn/CTAN/systems/texlive/tlnet/tlpkg/texlive.tlpdb
# 期望:200 + 1秒内;如果超时或 FAIL 说明源不可用5.3 中文支持宏包安装清单
# 中文核心(ctex + xeCJK + fontspec)
tlmgr install ctex xecjk fontspec
# 常用补充
tlmgr install float needspace caption booktabs hyperref amsmath \
geometry listings biblatex natbib tikz pgf
# 国标参考文献(注意:新版按年份分文件!见坑 #5)
tlmgr install gbt7714
# 刷新文件数据库
mktexlsr5.4 验证
kpsewhich ctexart.cls # 应输出 /usr/local/texlive/.../ctexart.cls
kpsewhich xeCJK.sty
kpsewhich fontspec.sty⚠️ 坑 #5:新版
gbt7714宏包不再提供gbt7714.bst,而是按年份分文件:gbt7714-2015-numeric.bst、gbt7714-2015-authoryear.bst、gbt7714-2025-numeric.bst等。用\bibliographystyle{gbt7714-2015-numeric}这种带年份的名字。
5.5 编译实测
\documentclass{ctexart}
\usepackage{float, booktabs, amsmath, tikz}
\begin{document}
中文测试 $E=mc^2$
\end{document}xelatex -interaction=nonstopmode test.tex # 应生成 PDF 无致命错误六、第四步:创建管理员账号
踩坑:CE 版没有注册页
⚠️ 坑 #6:Overleaf 社区版 6.x 的注册页是写死的(
register.pug模板直接显示"Please contact admin"),没有自助注册功能。只有 0 用户时才有注册表单。所以创建账号必须直接操作 MongoDB。
用 Node 脚本直插 MongoDB
在 sharelatex 容器内执行(容器里有 mongodb 和 bcrypt 库):
const mongodb = require("mongodb");
const bcrypt = require("bcrypt");
const MongoClient = mongodb.MongoClient;
const ObjectId = mongodb.ObjectId;
(async () => {
const client = await MongoClient.connect("mongodb://mongo/sharelatex");
const db = client.db("sharelatex");
const users = db.collection("users");
const email = "minlonghuo@gmail.com";
const password = "你的密码";
const now = new Date();
const hash = bcrypt.hashSync(password, 12); // ← Overleaf 要求 bcrypt 12 轮!
await users.deleteMany({ email: email }); // 幂等:先删旧的
const user = {
_id: new ObjectId(),
email: email,
emailLower: email.toLowerCase(),
hashedPassword: hash, // ← 字段名是 hashedPassword 不是 password!
first_name: "minlonghuo",
last_name: "",
created: now,
loginCount: 0,
email_verification: { verified: true, sentAt: now }, // ← 必须 verified,否则登录被拦
features: { collaborators: -1, versioning: true, trackChanges: true, compileTimeout: 60 },
isAdmin: true, // ← 管理员标记
holdingAccount: false,
signUpDate: now,
samlIdentifiers: [],
must_reconfirm: false
};
await users.insertOne(user);
console.log("SUCCESS:", email);
await client.close();
})().catch(e => { console.error(e); process.exit(1); });执行方式:
docker cp create_user.js sharelatex:/overleaf/create_user.js
docker exec sharelatex bash -c 'cd /overleaf && node create_user.js'
docker exec sharelatex rm -f /overleaf/create_user.js # 清理验证登录
# 容器内 curl 模拟登录
curl -s -X POST http://localhost:80/login -H 'Content-Type: application/json' \
-d '{"email":"minlonghuo@gmail.com","password":"你的密码"}' -D - -o /dev/null
# 期望返回 302,Location: /project💡 要点:
- 密码字段必须是
hashedPassword(不是password)- bcrypt 轮数必须是 12(Overleaf 默认)
email_verification.verified必须为 true- 管理员设
isAdmin: true,普通用户 false
七、第五步:域名反代(Lucky)
架构
fnOS 上装 Lucky 应用(/vol2/@appcenter/Lucky),做反向代理:
overleaf.epochwl.top:443 → http://192.168.10.100:18080Lucky 配置要点
- 打开 Lucky 管理后台:
http://NAS_IP:16666(默认路径/safety/) - 反向代理模块 → 添加规则:
- 前端域名:
overleaf.epochwl.top - 前端端口:
443 - 后端地址:
http://192.168.10.100:18080 - 证书:绑定 ZeroSSL/Let's Encrypt 证书
- 前端域名:
- 保存后 443 端口立即生效
⚠️ 坑 #7(Lucky 配置导致 443 全挂):改反代规则时如果配置不当(比如证书绑定错误、监听端口配置冲突),443 端口会对所有域名 Connection reset,表现为
TLS handshake error: bad record MAC。排查方法:# 看监听是否正常 ss -tlnp | grep 443 # 模拟带 Host 头的请求 curl -sk -H "Host: overleaf.epochwl.top" https://[::1]:443/ # 期望 302 跳转;如果 000/Connection reset 说明规则坏了修复:在 Lucky 后台检查规则(证书是否绑定、端口是否正确),重新保存。
Lucky 配置文件说明
- 配置存在
/vol2/@appdata/Lucky/data/*.lkcf(AES 加密,无法直接读) - 管理 API 在
http://127.0.0.1:16666/safety/api/(需要登录 token) - 日志在
/vol2/@appdata/Lucky/info.log
八、第六步:HTTPS 证书
为什么必须配证书
- Lucky 默认自签证书(CN=Lucky),浏览器会报"您的连接不是私密连接"
- 正式证书(ZeroSSL/Let's Encrypt)→ 地址栏绿锁,无警告
证书申请(Lucky 后台操作)
Lucky 内置 ACME 客户端,支持 Let's Encrypt / ZeroSSL:
- Lucky 后台 → SSL 证书模块
- 添加证书 → 选择 ACME → 填域名
overleaf.epochwl.top - 验证方式:
- HTTP-01:需要 80 端口(Lucky 需开 80 监听 + 运营商允许 80 入站)——国内宽带 80 常被封,不推荐
- DNS-01:通过 DNS 服务商 API 验证,推荐。域名在阿里云就用阿里云 AccessKey,Lucky 的 DDNS 模块有现成凭据可复用
- 申请成功后把证书绑定到反代规则
验证证书
# 看证书信息
echo | openssl s_client -connect "[你的IPv6地址]:443" -servername overleaf.epochwl.top 2>/dev/null \
| openssl x509 -noout -subject -issuer -dates
# 完整访问测试(-k 表示跳过校验,验证链路)
curl -skL https://overleaf.epochwl.top/ -o /dev/null -w "%{http_code} %{url_effective}\n"
# 期望:200 https://overleaf.epochwl.top/login
# 严格校验(验证证书真的有效)
curl -sL https://overleaf.epochwl.top/ -o /dev/null -w "%{http_code}\n"
# 期望:200 或 302(无证书错误)⚠️ 坑 #8:ZeroSSL/Let's Encrypt 证书有效期 90 天,记得开自动续期或在到期前续期。
九、第七步:内外网登录问题修复
现象
- 外网(HTTPS 域名)能登录
- 内网(HTTP://NAS_IP:18080)登录失败,报 "Session error. Please check you have cookies enabled"
根因(非常隐蔽!)
Overleaf 源码 settings.js 里:
secureCookie: process.env.OVERLEAF_SECURE_COOKIE != null,只要 OVERLEAF_SECURE_COOKIE 环境变量存在(不管设 true 还是 false!),secureCookie 就是 true!
secureCookie=true 时:
- cookie 带
Secure标志 → 浏览器只在 HTTPS 下发送 - 内网用
http://192.168.10.100:18080访问 → HTTP 不发送 Secure cookie → 每次请求都无 session → Session error
解决方案
必须整行注释/删除 OVERLEAF_SECURE_COOKIE 变量,而不是设为 false:
# variables.env 中:
# OVERLEAF_SECURE_COOKIE=true ← 删掉或注释整行
# 千万不能写成 OVERLEAF_SECURE_COOKIE=false(等于没改,还是会 Secure!)改完删容器重建:
docker rm -f sharelatex && bash bin/up -d验证内外网都能登录
# 容器内模拟内网(无代理头)访问
curl -s -c /tmp/c.txt http://localhost:80/login -D - -o /dev/null | grep -i set-cookie
# 期望:set-cookie 不含 Secure
# 模拟外网(带 X-Forwarded-Proto: https)访问
curl -s -c /tmp/c2.txt -H "X-Forwarded-Proto: https" http://localhost:80/login -D - -o /dev/null | grep -i set-cookie
# 期望:set-cookie 正常十、踩坑全记录(速查表)
| # | 坑 | 现象 | 解决方案 |
|---|---|---|---|
| 1 | 镜像拉取慢 | docker pull 超时 | 配国内镜像加速器 |
| 2 | 数据在默认目录 | 备份/管理不便 | 迁到 /vol{N}/<uid>/docker/,改 overleaf.rc |
| 3 | 改配置不生效 | 环境变量没变 | 必须删容器重建,restart 不重读 env_file |
| 4 | 宏包丢失 | 重建后 ctexart.cls not found | texlive 目录持久化挂载到宿主机 |
| 5 | tlmgr 卡死 | 进程在但 CPU 不动 | 换清华/中科大镜像源 |
| 6 | CE 无注册页 | 无法自助注册 | MongoDB 直插 users 集合 |
| 7 | SECURE_COOKIE 坑 | 内网 Session error | 整行注释该变量(设 false 无效) |
| 8 | 证书 90 天 | 到期访问失败 | 开自动续期 |
| 9 | Lucky 443 全挂 | bad record MAC | 检查反代规则证书/端口配置 |
| 10 | 外网打不开 | 只能局域网访问 | NAS 无公网 IPv4,域名只有 IPv6;用支持 IPv6 的网络或内网穿透 |
十一、日常运维要点
1. 备份
# 数据目录(项目/用户/数据库)是重中之重
/vol1/1000/docker/overleaf/{overleaf,mongo,redis}
# texlive 宏包可备份可重装(重装用清华源很快)2. 常用命令
# 查看状态
docker ps | grep -E "sharelatex|mongo|redis"
docker logs sharelatex --tail 50
# 停止/启动(overleaf-toolkit)
cd overleaf-toolkit
bash bin/stop
bash bin/up -d
# 进容器
docker exec -it sharelatex bash3. 容器重建恢复清单(重要!)
如果需要重建 sharelatex 容器,按此顺序:
# 1. 确认挂载还在(texlive 持久化)
docker inspect sharelatex | grep -A2 texlive
# 期望:/vol1/1000/docker/overleaf/texlive -> /usr/local/texlive
# 2. 重建
docker rm -f sharelatex && cd overleaf-toolkit && bash bin/up -d
# 3. 验证宏包还在
docker exec sharelatex kpsewhich ctexart.cls
# 期望:有输出(说明持久化生效,宏包没丢)
# 4. 如果宏包丢了(早期没持久化的版本):
bash /vol2/@apphome/hermes-agent/data/workspace/reinstall_tex_pkgs.sh4. 新增用户(给协作者开账号)
复用上面的 MongoDB 直插脚本,改 email/password/isAdmin: false 即可。
附录:完整部署命令速览
# ========== 1. 部署 ==========
git clone https://github.com/overleaf/toolkit.git
cd toolkit
cp config/overleaf.rc.example config/overleaf.rc
cp config/variables.env.example config/variables.env
# 编辑 config/overleaf.rc → 数据路径
# 编辑 config/variables.env → SITE_URL / ADMIN_EMAIL / BEHIND_PROXY=true
bash bin/up -d
# ========== 2. 数据迁移 ==========
bash bin/stop
mkdir -p /vol1/1000/docker/overleaf/
mv data/{overleaf,mongo,redis,git-bridge} /vol1/1000/docker/overleaf/
# 改 overleaf.rc 路径
docker rm -f sharelatex mongo redis && bash bin/up -d
# ========== 3. texlive 持久化 ==========
mkdir -p /vol1/1000/docker/overleaf/texlive
docker cp sharelatex:/usr/local/texlive/. /vol1/1000/docker/overleaf/texlive/
# 改 docker-compose.base.yml 加挂载
docker rm -f sharelatex && bash bin/up -d
# ========== 4. 宏包安装(清华源) ==========
tlmgr option repository https://mirrors.tuna.tsinghua.edu.cn/CTAN/systems/texlive/tlnet
tlmgr install ctex xecjk fontspec float needspace caption booktabs \
hyperref amsmath geometry listings biblatex natbib tikz pgf gbt7714
mktexlsr
# ========== 5. 建账号(MongoDB 直插) ==========
# 见上文 Node 脚本
# ========== 6. Lucky 反代 + 证书 ==========
# Lucky 后台(16666)操作,见上文
# ========== 7. 验证 ==========
curl -skL https://overleaf.epochwl.top/ -o /dev/null -w "%{http_code} %{url_effective}\n"
# 期望:200 https://overleaf.epochwl.top/login本文档基于实际部署过程,由deepseek v4 flash根据聊天记录整理,环境:fnOS NAS,Overleaf 6.2.2 CE,TeX Live 2026。

