2025年,我把课题组内部的 LaTeX 协作平台正式迁到了自托管的 Overleaf Community Edition 上,服务器是一台 Ubuntu 22.04,部署过程从零到能用花了差不多一个下午。中间踩了不少坑,尤其是中文字体、编译镜像、磁盘占用这几个地方,所以把完整过程整理出来,希望对正打算在 Ubuntu 上部署 Overleaf Community Edition 的同学有帮助。
1. 为什么要把论文平台搬到自己服务器上
1.1 Overleaf Community Edition 到底是什么、跟官网版差在哪
Overleaf 是很多人写论文的首选工具,浏览器打开就能写 LaTeX,还能多人实时协作。官网免费版对普通用户来说够用,但真正进入课题组成批量使用阶段,你会发现几个痛点:免费版编译队列偶尔要等、单个项目大小有限制、项目数量也有限制,团队协作时这些限制会直接卡住进度。
Overleaf Community Edition 是官方开源的社区版,允许你自己部署,部署之后核心功能都在:LaTeX 实时编辑、多人协作、修订模式、模板导入、编译日志查看这些一样不少。和官网版相比,主要区别是它不带官网商业版的那些高级特性,比如高级参考文献搜索、可视化 diff、更细粒度的权限管理。但对大多数课题组来说,CE 的核心能力已经足够覆盖日常写作。
1.2 适合部署 CE 的几个典型场景
我总结下来,以下三类场景最适合自托管 Overleaf CE:
- 课题组内部有多人同时写论文、写报告,需要统一的协作空间,但不想受在线版额度限制。
- 论文内容涉及未公开数据或合作方保密要求,不适合放到第三方云平台,需要在内网或自己可控的服务器上运行。
- 团队经常使用自定义模板、自定义 LaTeX 宏包、特殊字体,CE 允许你深度定制编译环境,这一点在线版反而做不到。
如果你只是个人偶尔写写简历、记点笔记,那直接用官网免费版就行,没必要折腾自托管。CE 的价值在"团队"和"可定制"这两个词上。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 安装之前必须想清楚的几件事
2.1 硬件底线:不要低估 LaTeX 编译的胃口
LaTeX 编译本身不算特别吃资源,但 Overleaf CE 的架构决定了它需要同时跑数据库、缓存、后端服务和编译容器,资源占用是叠加的。我的实际经验是:最低配 2 核 4GB 内存、20GB 空闲磁盘能把服务跑起来,但一旦两个人同时编译比较大的文档(比如几十页的论文配大量 TikZ 图片),4GB 内存很容易吃紧,编译容器可能直接被系统杀掉。
更现实的配置是 4 核 8GB 内存起步,磁盘预留 30GB 以上。主要磁盘消耗来自 TeX Live 镜像,默认的 sharelatex/texlive-full 镜像解压后接近 4GB,加上 MongoDB 数据和上传的文件,20GB 是底线而不是舒适区。
操作系统我推荐 Ubuntu 20.04 LTS 或 22.04 LTS,内核相对成熟,Docker 支持也稳定。部署前先确认系统架构,CE 的默认容器镜像基本都是 x86_64,用 uname -m 看一下,如果是 arm64 架构,后面很多现成镜像不能直接用,需要自己构建,复杂度会明显上升。
2.2 组件架构:它不是一个单进程应用
Overleaf CE 不是一个装完就能跑的程序,它由多个组件协作:
| 组件 | 作用 |
|---|---|
| 前端 Web 服务 | Angular 应用,提供编辑界面和用户交互 |
| 后端 API 服务 | Node.js 写的服务端,处理文档、项目、用户请求 |
| MongoDB | 存储用户信息、项目元数据、文档结构 |
| Redis | 缓存和编译任务队列 |
| TeX Live 编译容器 | 真正执行 LaTeX 编译的隔离环境 |
| Filestore / Docstore | 文件存储和文档快照存储 |
这些组件通过 Docker 编排在一起,所以理解 CE 的部署本质上是理解一组容器的协作关系。官方为此提供了一个叫 toolkit 的部署工具,本质上是一套脚本加配置模板,用来启动和管理这些容器,这也是官方推荐的社区版安装方式。
2.3 数据到底存在哪:目录与持久化
部署之前必须知道数据落在哪些目录,不然备份和升级都会抓瞎。使用官方 toolkit 部署时,默认目录结构是这样的:
code复制toolkit/
├── bin/ # 管理脚本,up/down/reboot 等
├── config/ # 配置文件
├── data/ # 数据持久化目录,MongoDB、上传文件等
└── lib/ # 脚本和帮助文件
其中 data 目录最关键,MongoDB 的数据文件、用户上传的项目文件、编译产生的临时数据都在里面。升级或迁移时,只要把这个目录完整保留下来,理论上数据就不会丢。
2.4 安装方式选型:官方 toolkit 还是手动 compose
我最初也想过不用 toolkit,自己写 docker-compose 文件来编排,因为 toolkit 的封装逻辑不太透明,出了问题不好排查。但实际操作下来,除非你对 Overleaf 的组件非常熟悉,否则不建议绕过 toolkit。
原因有两点:第一,Overleaf CE 的容器之间有很多隐含的依赖关系和初始化步骤,人工编排容易漏;第二,toolkit 提供了 bin/up、bin/down、bin/reboot 这类命令,启动、停止、重启都封装好了,比手动敲 docker-compose 命令省心很多。toolkit 本质上只是配置和脚本的集合,底层还是调用 docker compose,出问题的时候照样可以进到目录里手动排查。
3. 完整安装步骤,从零到登录页
3.1 安装 Docker 和 compose 插件
在开始之前,先把 Docker 装好。Ubuntu 上推荐用官方源安装 Docker Engine,不要用 Ubuntu 自带的 docker.io 包,因为版本偏旧,部分 compose 语法不兼容。
官方源安装的大致过程如下:
bash复制# 卸载可能存在的旧版本
sudo apt remove docker docker-engine docker.io containerd runc
# 安装依赖
sudo apt update
sudo apt install ca-certificates curl gnupg lsb-release
# 添加 Docker 官方 GPG 密钥
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
# 添加软件源
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# 安装 Docker Engine 和 compose 插件
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# 设置开机自启并启动
sudo systemctl enable docker
sudo systemctl start docker
安装完成后,把当前用户加入 docker 组,避免每次执行 docker 命令都加 sudo:
bash复制sudo usermod -aG docker $USER
这一步之后要重新登录终端才能生效。检查 Docker 是否正常:
bash复制docker --version
docker compose version
3.2 拉取 toolkit 与初始化配置
接下来拉取官方的部署工具:
bash复制git clone https://github.com/overleaf/toolkit.git
cd toolkit
toolkit 仓库本身不包含业务代码,它只是启动脚本和配置模板。目录下有一个 config/overleaf.rc 文件,这是 CE 的核心配置文件。第一次运行前需要复制一份默认配置:
bash复制cp config/overleaf.rc.example config/overleaf.rc
然后编辑 config/overleaf.rc。最关键的几个配置项如下:
bash复制# 对外服务端口,默认是 80
SHARELATEX_PORT=80
# MongoDB 连接地址,toolkit 会自动启动 mongo 容器
SHARELATEX_MONGO_URL=mongodb://sharelatex:sharelatex@mongo/sharelatex
# Redis 连接地址
SHARELATEX_REDIS_HOST=redis
# 服务器域名,如果是 IP 访问就填 IP
SHARELATEX_APP_NAME=Overleaf Community Edition
# TeX Live 编译镜像,默认是官方镜像
# TEXLIVE_IMAGE=sharelatex/texlive-full:latest
有一个容易被忽略的地方:如果你之后要用域名 + HTTPS 访问,SHARELATEX_APP_NAME 不要随意改,因为登录后的 cookie 是和这个域名绑定的,改完之后老用户全部需要重新登录。这个细节我们后面专门说。
3.3 启动服务并处理首次初始化
配置好之后,执行:
bash复制bin/up
第一次启动会拉取大量容器镜像,包括 MongoDB、Redis、后端服务、前端服务、TeX Live 编译镜像。其中 TeX Live 镜像有好几 GB,网速快的话也要等十几分钟,网速慢的话可能得等半小时以上。这一步最容易让人误以为卡住了,实际上只是镜像太大在慢慢拉。
镜像拉完,容器开始初始化。MongoDB 首次启动需要做数据初始化,后端服务会在启动时自动创建需要的集合和索引。等待所有容器状态变成 healthy 或者 running,然后浏览器访问 http://服务器IP 就能看到 Overleaf 的登录界面。
3.4 创建第一个管理员账号,并验证编译
首次访问时,Overleaf CE 没有预设管理员账号。注册的第一个账号会被自动赋予管理员权限。这跟很多系统的习惯不一样,所以要注意:部署完成后第一件事就是注册账号,不要把这个机会留给别人。
注册并登录之后,建议立刻做一个最小验证:新建项目,选择 blank 模板,写入以下内容:
latex复制\documentclass{article}
\begin{document}
Hello, Overleaf Community Edition!
\end{document}
点击 Recompile,等编译完成,预览区出现 PDF 就说明整个链路正常。这一步务必在正式投入使用前完成,因为很多服务器问题都是在编译阶段才暴露出来的。
3.5 验证用户注册、项目管理、模板导入
编译通过后,继续验证几个常用功能:
- 用户注册:能否正常注册第二个、第三个账号。
- 项目管理:新建项目、删除项目、复制项目是否正常。
- 模板导入:找一个标准的
.zip格式的 LaTeX 模板,在 New Project 里选择 Upload Project 导入,确认整个项目结构能正常加载。
至此,一个基础的 Overleaf CE 就装好了。但正式投入生产使用之前,还有几个深度问题要处理,尤其是中文字体和长期运维。
4. 一个绕不开的坑:中文字体与 TeX Live 编译镜像
4.1 为什么编译中文文档会报错找不到字体
我用 CE 编译一个含中文的 LaTeX 文档时,第一次就遇到了 fontspec 找不到字体的错误。原因不复杂:Overleaf 官方提供的 sharelatex/texlive-full 镜像虽然预装了完整 TeX Live 发行版,但默认不包含中文字体。
很多中文文档用 ctex 宏包配合系统的中文字体工作,在本地安装的 TeX Live 上没问题,是因为操作系统本身装了中文字体。而 Docker 编译容器是一个精简环境,里面没有安装任何 CJK 字体,所以 ctex 找不到可用的中文字体,编译直接失败。
4.2 解决方案一:自定义编译镜像,加入中文字体
这个问题需要创建一个新的编译镜像,在官方镜像基础上添加中文字体。方法不唯一,我用的思路是:拉取官方 texlive-full 镜像,在容器里安装字体,然后重新打包成自己的镜像,再将 CE 配置指向这个新镜像。
具体步骤如下。
先创建一个目录,放构建文件:
bash复制mkdir ~/overleaf-texlive && cd ~/overleaf-texlive
写一个 Dockerfile:
dockerfile复制FROM sharelatex/texlive-full:latest
# 安装中文字体(以 Noto CJK 为例)
RUN apt-get update && \
apt-get install -y \
fonts-noto-cjk \
fonts-noto-cjk-extra \
fonts-arphic-uming \
fonts-arphic-ukai \
&& rm -rf /var/lib/apt/lists/*
然后构建镜像:
bash复制docker build -t my-texlive-full:latest .
这一步同样会比较耗时,因为要在基本系统上安装字体包。构建完成后,修改 config/overleaf.rc 中的 TEXLIVE_IMAGE:
bash复制TEXLIVE_IMAGE=my-texlive-full:latest
然后重启 CE:
bash复制bin/reboot
重启之后,编译容器的镜像会切换成新镜像,中文文档就能正常编译了。
4.3 解决方案二:基础镜像加字体,但不依赖包管理器
如果目标服务器网络不是很通畅,安装字体包可能较慢甚至失败。另一种办法是直接把系统中已有的字体文件复制进镜像。Windows 上的中易字体、macOS 上的 PingFang,或者你下载的思源宋体,都可以用这种方式打进去。
dockerfile复制FROM sharelatex/texlive-full:latest
# 创建字体目录
RUN mkdir -p /usr/share/fonts/custom
# 复制本地字体文件
COPY fonts/ /usr/share/fonts/custom/
# 刷新字体缓存
RUN fc-cache -f -v
然后同样构建镜像并修改配置。这个方案的好处是不依赖 apt 源,字体选择更灵活。要注意的是,字体文件的授权要确认清楚,避免把需要商业授权的字体打包进去。
4.4 字体问题之外的镜像体积控制
自定义镜像之后,磁盘占用会进一步上升。sharelatex/texlive-full 解压后接近 4GB,加字体后可能到 5~6GB。如果服务器磁盘紧张,可以看一下 docker system df 的输出,确认哪些镜像占用空间。旧的官方 texlive-full 镜像如果不再使用,可以清理掉:
bash复制docker image prune
但要注意,确认 TEXLIVE_IMAGE 已经指向新镜像后再清理,否则编译会崩溃。
5. 上线前的运维细节:备份、升级与反向代理
5.1 数据备份:不能只备份一个目录
Overleaf CE 的数据分散在 MongoDB、文件存储和文档存储里,备份必须覆盖所有部分。最省事的方式是整目录备份 toolkit/data,但这样备份文件可能很大,而且 MongoDB 的一致性不能保证。更稳妥的做法是分开处理。
MongoDB 中的数据可以用 mongodump 导出:
bash复制docker exec overleaf-mongo mongodump --archive=/tmp/mongo-dump.gz --gzip --db sharelatex
docker cp overleaf-mongo:/tmp/mongo-dump.gz ./
文件存储和文档存储对应的物理文件在 data/sharelatex/data 目录下,直接把目录压缩即可:
bash复制tar czf sharelatex-data.tar.gz data/sharelatex/data
恢复的时候反过来:先用 mongorestore 恢复数据库,再把文件目录原样放回去。备份周期看你团队的活跃度,我建议至少每天备份一次,如果项目重要,可以考虑每小时备份一次 MongoDB,文件存储每天备份一次。
5.2 升级版本:CE 升级到底在升什么
社区版升级路径比想象中简单,本质上就是更新 toolkit 仓库、再重新拉取最新镜像:
bash复制cd toolkit
git pull origin main
bin/up --force-recreate
执行前务必先备份数据和配置。git pull 拉的是 toolkit 的脚本更新,bin/up --force-recreate 会用最新镜像重新创建容器。CE 版本迭代不算快,但每次升级都有可能涉及数据库 schema 变化,升级后最好立刻验证一下项目编译是否正常。
还有一个容易忽略的问题:升级前确认 config/overleaf.rc 里有没有自定义配置(比如自定义镜像、自定义端口),因为 toolkit 更新后配置项的名字偶尔会变,可能会被自动忽略或覆盖。
5.3 Nginx 反向代理与 HTTPS
很多人部署完成后直接用 IP 访问,这在测试环境没问题,但正式使用时强烈建议配置域名和 HTTPS。用 Nginx 做反向代理是最常见的方案。
安装 Nginx:
bash复制sudo apt install nginx
创建站点配置:
nginx复制server {
listen 80;
server_name your-domain.com;
location / {
proxy_pass http://127.0.0.1:80;
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 支持
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
这里的关键是 WebSocket 支持。Overleaf 编辑器与后端之间通过 WebSocket 保持实时通信,如果 Nginx 配置里不加 Upgrade 相关头,编辑器会一直报连接断开或者保存失败。
HTTPS 直接用 certbot 申请证书:
bash复制sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d your-domain.com
certbot 会自动修改 Nginx 配置并配置自动续期。配置完 HTTPS 后,再检查一遍 Overleaf 的配置,确保 SHARELATEX_APP_NAME 和实际域名一致,否则登录状态可能异常。
6. 运行过程中遇到的那些坑和排查链路
6.1 端口 80 被占用:最常见的第一个坑
如果你在服务器上已经跑了 Nginx 或者其他 Web 服务,bin/up 会失败,提示端口占用。这不是 Overleaf 的问题,而是端口冲突。
排查链路很清晰:先看 config/overleaf.rc 里 SHARELATEX_PORT 设的是什么,再看哪个进程占了端口:
bash复制sudo ss -tlnp | grep :80
解决办法有两种。第一种,改 CE 的端口,比如改成 8080:
bash复制SHARELATEX_PORT=8080
然后 bin/reboot。第二种,保留 CE 的 80 端口,把 Nginx 的默认站点禁用,或者把 Nginx 的监听端口改成别的,让 80 端口专门给 Overleaf。
我实际推荐第二种方案,因为后面大概率还是要用 Nginx 做 HTTPS 代理,把 80 端口让给 Nginx 更合理。
6.2 编译过程中被 OOM Kill:内存不足的典型表现
服务跑了一段时间,团队成员开始集中写论文,你会发现某些大文档编译到一半,预览区报错,日志里隐约有 "Killed" 字样。这通常是编译容器的内存被操作系统杀掉了。
排查时先看系统内存和 Docker 容器的资源使用:
bash复制free -h
docker stats
我遇到的情况是:两个编译任务同时执行,每个 LaTeX 编译进程占 1.5~2GB 内存,加上 MongoDB 和 Redis 的常驻内存,4GB 的服务器直接爆了。Linux 在内存不足时会启动 OOM Killer,编译容器作为内存大户很容易被选中。
解决办法是给容器设置资源限制。编辑 config/overleaf.rc,加入:
bash复制SHARELATEX_COMPILER_MEMORY_LIMIT=2g
或者手动调整 Docker 的内存限制,强制编译容器的内存上限。另一个更硬核的办法是加 swap,但编译任务对 swap 的容忍度很低,内存换页导致的性能下降会让编译时间翻倍,不如直接加内存。
6.3 模板导入失败:zip 的结构问题
Overleaf 支持导入 zip 格式的 LaTeX 模板,但很多用户第一次导入就失败。原因绝大多数是 zip 包的结构不符合要求。
Overleaf 期望的 zip 结构是项目根目录直接包含 .tex 文件,而不是套一层文件夹。比如你从期刊官网下载的模板解压出来是 sample/ 文件夹,里面有 main.tex、sample.bst 这些文件,如果你把 sample 文件夹直接压缩成 zip 上传,Overleaf 会认为 zip 的根目录就是这个文件夹,项目结构会变得很别扭,有时候直接导入失败。
正确的做法是:进入 sample 文件夹,把里面的所有文件和文件夹选中,压缩成 zip,保证 zip 解压后第一层就是 main.tex 而不是 sample/main.tex。
如果是自己团队的内部模板,导入前建议先手动解压确认结构。另外,zip 文件本身的编码也可能导致中文文件名乱码,尽量用 UTF-8 压缩。
6.4 改了域名之后所有用户强制下线
这是我折腾了一次才明白的坑。CE 的登录状态和域名是绑定的,具体来说是通过 cookie 实现的。一开始我用 IP 访问,注册了一批账号,后来配了域名,结果所有用户再次访问时发现 session 全部失效,需要重新登录。
这不是 bug,而是安全机制在起作用。如果配置文件里的应用域名和用户访问的地址不一致,后端会判断为跨域请求,拒绝读取 cookie。
彻底解决的方法是:从一开始就确定最终要用的域名,首次部署时就把 SHARELATEX_APP_NAME 配置好。如果中途换域名,只能让所有用户重新登录一次,没有别的办法。
6.5 编译队列积压:并发编译超时的排查
团队人多之后,可能出现编译任务长时间排队、点 Recompile 迟迟不动的现象。排查思路是看编译容器是否在正常处理任务,以及 Redis 队列是否积压。
bash复制docker logs overleaf-clsi
docker logs overleaf-real-time
如果 CLSI 容器日志里持续出现无法连接或超时,多半是容器的网络配置有问题,最直接的解决办法是把整个服务重启一遍:
bash复制bin/reboot
重启之后网络连接会重新建立,队列会恢复消费。如果是频繁出现这种问题,带宽或 DNS 配置可能有隐患,需要在宿主机层面进一步排查。
7. 一些个人建议
经过这一轮部署,我的感受是 Overleaf CE 本身不复杂,真正的复杂度都在环境适配和团队使用习惯上。有一点要特别提醒:Community Edition 的定位是社区版,官方不提供商业支持,出了问题基本靠自己看日志、查文档。如果你是给整个课题组部署,建议做好这两件事:
第一,把 config/overleaf.rc 和 data 目录的备份脚本写好,定时执行,不要等磁盘坏了才想起备份。第二,把自定义镜像的 Dockerfile 保存到 Git 仓库里,免得服务器重装之后要从头摸一遍怎么加字体、怎么调内存。
如果你只是自己写论文用,直接在官网注册一个账号就够了,不用自托管;但如果你和我一样需要给团队提供稳定的协作环境,CE 确实是目前最靠谱的方案。希望这篇记录能帮你少踩几个坑,顺利把平台跑起来。
