由官方提供的Overleaf免费服务近期再次缩短编译时长,限制已降至10秒,这为用户日常使用带来了显著不便。虽然市面上还有不少Overleaf的替代方案,但自部署Overleaf镜像能在最大程度上提供更无缝的编辑体验。本文记录在 Ubuntu 24.04 服务器上通过 Docker 部署 Overleaf 的完整流程,旨在为需要自建服务的用户提供参考。
Overleaf Community Edition (Overleaf CE) 提供两种本地部署方式:
注意
本文只介绍使用Docker镜像部署的全流程,使用镜像部署的目的在于定制TexLive版本。Toolkit默认安装TexLive 2025,而Overleaf在线版使用的是TexLive 2024,为了保证编译的顺畅进行,希望CE使用的TexLive与Online保持一致。因此如果你不需要自定义TexLive版本,那么你完全可以从“正式开始构建Overleaf CE”开始
Docker官方提供了不同的几种安装Docker的方式,以下从Apt源安装
bash# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
# Add the repository to Apt sources:
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
# Install the latest Version
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# Docker在安装完成后默认启动,可以使用以下方式验证Docker服务是否运行
sudo systemctl status docker
# 部分系统禁用了该功能,此时可使用以下命令启动Docker服务
sudo systemctl start docker
# 最后,使用`hello-world`镜像验证docker安装
sudo docker run hello-world
# 你应该看到
Hello from Docker! \
This message shows that your installation appears to be working correctly
# 如果你不想每次使用docker命令都需要sudo权限,先检查是否存在docker用户组,通常会自动生成
grep docker /etc/group
# 将当前用户添加到用户组
sudo usermod -aG docker $USER
使用以下命令克隆Overleaf仓库
bashgit clone https://github.com/overleaf/overleaf.git
其中server-ce目录下包含构建镜像用到的Dockerfile
和Dockerfile-base
,后者专门用于构建基础镜像,这个基础镜像包含了所有不常变动的基础设施,正如官方在README中说的
We split this out because it's a pretty heavy set of dependencies, and it's nice to not have to rebuild all of that every time.
首先编辑Dockerfile-base
以修改安装的TexLive版本
# Install TexLive # --------------- # ... # 在这里直接修改镜像源地址,例如使用南京大学Docker源,注意历史版本位于tex-historic的tlnet-final下 ARG TEXLIVE_MIRROR=https://mirror.nju.edu.cn/tex-historic/systems/texlive/2024/tlnet-final # 仅仅修改镜像源地址是不够的,默认状态下,下面几行会执行安全验证 RUN mkdir /install-tl-unx \ # 请注释指定的语句 # 下载当前最新的GPG公钥texlive.asc && wget --quiet https://tug.org/texlive/files/texlive.asc \ <-注释 && gpg --import texlive.asc \ <-注释 && rm texlive.asc \ <-注释 && wget --quiet ${TEXLIVE_MIRROR}/install-tl-unx.tar.gz \ && wget --quiet ${TEXLIVE_MIRROR}/install-tl-unx.tar.gz.sha512 \ # 下载TexLive 2024的签名文件install-tl-unx.tar.gz.sha512.asc && wget --quiet ${TEXLIVE_MIRROR}/install-tl-unx.tar.gz.sha512.asc \ <-注释 # 使用当前最新的GPG公钥texlive.asc对进行验证,这显然是不可能通过的 && gpg --verify install-tl-unx.tar.gz.sha512.asc \ <-注释 && sha512sum -c install-tl-unx.tar.gz.sha512 \ && tar -xz -C /install-tl-unx --strip-components=1 -f install-tl-unx.tar.gz \ && rm install-tl-unx.tar.gz* \ && echo "tlpdbopt_autobackup 0" >> /install-tl-unx/texlive.profile \ && echo "tlpdbopt_install_docfiles 0" >> /install-tl-unx/texlive.profile \ && echo "tlpdbopt_install_srcfiles 0" >> /install-tl-unx/texlive.profile \ # 在构建base镜像时建议修改这行的scheme-basic为scheme-full,安装完整版TexLive,避免后续升级的麻烦 && echo "selected_scheme scheme-basic" >> /install-tl-unx/texlive.profile \
接下来正式开始构建Overleaf CE镜像
bash# 首先安装make软件包
sudo apt update
sudo apt install make
# 验证安装
make --version
# 先确保你位于server-ce/目录下
cd server-ce
# 执行基础镜像的构建命令
make build-base
# 在构建完成后,你应该就能使用以下命令查看到刚刚构建好的base镜像
docker images
# 输出类似于
# 值得注意的是,overleaf镜像名称实际上是sharelatex,这是overleaf合并sharelatex的历史原因造成的
# 另外,同一个镜像被打上两个TAG,这是正常现象,符合Makefile中的定义
REPOSITORY TAG IMAGE ID ...
sharelatex/sharelatex-base main 757806628bdc ...
sharelatex/sharelatex-base main-16422f972bb4da0833be87675a3d34fe694d0941 757806628bdc ...
# 接下来构建CE镜像
make build-community
# 在构建完成后
docker images
# 输出类似于
REPOSITORY TAG IMAGE ID CREATED SIZE
sharelatex/sharelatex main f2ad213cc75d ...
sharelatex/sharelatex main-644db1722e8cce6bc85ea794156910928375cc0c f2ad213cc75d ...
sharelatex/sharelatex-base main a089e357f3a7 ...
sharelatex/sharelatex-base main-644db1722e8cce6bc85ea794156910928375cc0c a089e357f3a7 ...
# 返回overleaf根目录
cd ..
# 目录正确的话你应该能看到docker-compose.yml
ls docker-compose.yml
# 建议新建一个统一的数据目录
mkdir data_folders
# 并在docker-compose.yml分别修改sharelatex mongo 和 redis 容器的数据目录位置,例如
volumes:
- ./data_folers/sharelatex_data:/var/lib/overleaf
volumes:
- ./data_folers/mongo_data:/data/db
volumes:
- ./data_folers/redis_data:/data
# 启动服务
docker-compose up
警告
首次启动服务时不要使用-d
参数,你必须密切关注控制台输出。
理想情况下,由于已经构建好sharelatex镜像,不应该再从Docker源拉取,因此如果你看到以下内容,请使用Ctrl + C
终止进程
bash# 拉取 mongo 和 redis 是正常现象,无需在意
[+] Running 82/87
⠏ mongo [⣿⣿⣿⣿⣿⣿⣿⣿] 265.9MB / 265.9MB Pulling 37.0s
✔ redis Pulled
# sharelatex 已经在本地构建好,绝不应该再从镜像源拉取
17.5s
⠏ sharelatex [⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣷] 877.3MB / 902.9MB Pulling
这是由于docker-compose.yml
中
ymlservices:
sharelatex:
restart: always
# 未指定为我们定制化后的sharelatex镜像
image: sharelatex/sharelatex
# 使用docker images查看你的镜像,并将上述内容修改为
# image: sharelatex/sharelatex:{你的TAG}
# 示例
# image: sharelatex/sharelatex:main-644db1722e8cce6bc85ea794156910928375cc0c
...
重新启动服务
bash# 同样,你不应该使用-d参数,在下面的日志中不应该出现sharelatex/sharelatex ... Pulling
docker-compose up
# 容器运行后新开一个bash,使用以下命令检查正在运行的容器其TAG是否正确
docker ps
现在,访问http://localhost/launchpad
即可创建管理员账户
首次登录编译时会遇到编译失败的问题,请将docker-compose.yml
中关于启用沙箱编译的配置全部注释,这一点在yaml文件内也有对应提示
yml################
## Server Pro ##
################
## The Community Edition is intended for use in environments where all users are trusted and is not appropriate for
## scenarios where isolation of users is required. Sandboxed Compiles are not available in the Community Edition,
## so the following environment variables must be commented out to avoid compile issues.
##
## Sandboxed Compiles: https://docs.overleaf.com/on-premises/configuration/overleaf-toolkit/server-pro-only-configuration/sandboxed-compiles
# SANDBOXED_COMPILES: 'true'
### Bind-mount source for /var/lib/overleaf/data/compiles inside the container.
# SANDBOXED_COMPILES_HOST_DIR_COMPILES: '/home/user/sharelatex_data/data/compiles'
### Bind-mount source for /var/lib/overleaf/data/output inside the container.
# SANDBOXED_COMPILES_HOST_DIR_OUTPUT: '/home/user/sharelatex_data/data/output'
### Backwards compatibility (before Server Pro 5.5)
# DOCKER_RUNNER: 'true'
# SANDBOXED_COMPILES_SIBLING_CONTAINERS: 'true'
Overleaf CE注册由管理员完成,允许管理员配置SMTP服务向用户发送注册邮件,所有配置项都位于docker-compose.yml
文件
提示
首先注册网易云163邮箱,开启SMTP服务并记录SMTP密钥
# Overleaf CE可以使用AWS和SMTP服务完成邮件发送,这里我们使用SMTP服务 # 注意这一行一定要填,我怀疑它还起到了一个开启Email功能的作用 # OVERLEAF_EMAIL_FROM_ADDRESS: "hello@example.com" # OVERLEAF_EMAIL_AWS_SES_ACCESS_KEY_ID: # OVERLEAF_EMAIL_AWS_SES_SECRET_KEY: # OVERLEAF_EMAIL_SMTP_HOST: smtp.example.com # OVERLEAF_EMAIL_SMTP_PORT: 587 # OVERLEAF_EMAIL_SMTP_SECURE: false # OVERLEAF_EMAIL_SMTP_USER: # OVERLEAF_EMAIL_SMTP_PASS: # OVERLEAF_EMAIL_SMTP_TLS_REJECT_UNAUTH: true # OVERLEAF_EMAIL_SMTP_IGNORE_TLS: false # OVERLEAF_EMAIL_SMTP_NAME: '127.0.0.1' # OVERLEAF_EMAIL_SMTP_LOGGER: true # OVERLEAF_CUSTOM_EMAIL_FOOTER: "This system is run by department x" # 以网易云163免费邮的SMTP服务为例 OVERLEAF_EMAIL_SMTP_HOST: smtp.163.com OVERLEAF_EMAIL_SMTP_PORT: 465 OVERLEAF_EMAIL_SMTP_SECURE: true OVERLEAF_EMAIL_SMTP_USER: "XXXXX@163.com" OVERLEAF_EMAIL_SMTP_PASS: "这里是SMTP服务的密钥,而不是登录密码" OVERLEAF_EMAIL_SMTP_TLS_REJECT_UNAUTH: true OVERLEAF_EMAIL_SMTP_IGNORE_TLS: false OVERLEAF_EMAIL_SMTP_NAME: 'Overleaf-XXX' OVERLEAF_EMAIL_SMTP_LOGGER: true OVERLEAF_CUSTOM_EMAIL_FOOTER: "可用HTML元素深度定制"
修改完成后一定要记得重启容器来让新的环境变量生效
bashdocker-compose down && docker-compose up -d
作为本地部署的Overleaf实例,灾难应对是避不开的话题,要是你的同学们在使用CE时出现意外情况导致数据丢失,后果可想而知。为了让咱们能睡个好觉,容器数据自动备份任务是必不可少的。
根据官方指南,我们可以确定必须参与备份的文件和文件夹如下
提示
请先检查各数据目录的权限是否正确
bashubuntu:~/overleaf/data_folers$ ll -n
总计 36
drwxr-xr-x 5 0 0 4096 Sep 10 22:38 ./
drwxrwxr-x 12 1001 1001 4096 Sep 10 20:14 ../
drwxr-xr-x 5 999 999 20480 Sep 17 15:27 mongo_data/
drwxr-xr-x 2 999 999 4096 Sep 17 04:00 redis_data/
drwxr-xr-x 4 33 33 4096 Sep 10 21:58 sharelatex_data/
# 如果权限不对的话
# sharelatex_data 的所有权,递归地交给 www-data 用户 (UID 33)
sudo chown -R 33:33 ~/sharelatex_data
# mongo_data 的所有权,递归地交给 mongodb 用户 (UID 999)
sudo chown -R 999:999 ~/mongo_data
# redis_data 的所有权,递归地交给 redis 用户 (UID 999)
sudo chown -R 999:999 ~/redis_data
备份脚本最好挂载到root用户的crontab下,假设我们的备份脚本名为run_backup.sh
bash# 切换root用户
sudo -i
# 编辑自动任务
sudo crontab -e
# 添加这行
# 第0分钟 凌晨3点 每天 每月 每周 执行run.backup.sh 输出重定向到backup_cron.log
0 3 * * * xxx/run_backup.sh >> xxxx/overleaf_backups/backup_cron.log 2>&1
相对应的,我们需要一个恢复脚本,用于将容器恢复到某次备份时的状态,这里有一个注意点就是最好在脚本最后添加权限修正的部分。
sh# =================================================================
# == Overleaf Community Edition - 自动化备份脚本 ==
# =================================================================
# 备份文件存储目录,最好是异地存储
BACKUP_DIR="xxx/Overleaf_Backups"
# 数据目录根目录
SOURCE_DIR="xxx/overleaf/data_folers"
# docker-compose.yml文件所在的目录
COMPOSE_DIR="xxx/overleaf"
# 有效期,超过有效期的备份将自动删除
RETENTION_DAYS=14
# 生成带时间戳的文件名
TIMESTAMP=$(date +"%Y-%m-%d_%H-%M-%S")
FILENAME="overleaf-backup-$TIMESTAMP.tar.gz"
BACKUP_PATH="$BACKUP_DIR/$FILENAME"
echo "========================================="
echo "Starting Overleaf Backup: $(date)"
echo "========================================="
# 确保备份目录存在
mkdir -p $BACKUP_DIR
# 停止服务以确保数据一致性
echo "[Step 1/5] Stopping Overleaf services..."
cd $COMPOSE_DIR
docker compose down
if [ $? -ne 0 ]; then
echo "Error: Failed to stop Overleaf services. Aborting backup."
exit 1
fi
echo "=> Services stopped successfully."
# 创建备份压缩包
echo "[Step 2/5] Creating backup archive: $FILENAME"
tar -czf $BACKUP_PATH \
-C $SOURCE_DIR sharelatex_data \
-C $SOURCE_DIR mongo_data \
-C $SOURCE_DIR redis_data \
-C $COMPOSE_DIR docker-compose.yml
if [ $? -ne 0 ]; then
echo "Error: Failed to create tar archive. Aborting backup."
# 备份失败, 尝试重启服务
docker compose up -d
exit 1
fi
echo "=> Archive created successfully at $BACKUP_PATH"
# 重启服务
echo "[Step 3/5] Restarting Overleaf services..."
docker compose up -d
if [ $? -ne 0 ]; then
echo "Error: Failed to restart Overleaf services. Please check manually."
exit 1
fi
echo "=> Services restarted successfully."
# 清理旧的备份
echo "[Step 4/5] Cleaning up old backups (older than $RETENTION_DAYS days)..."
find $BACKUP_DIR -name "overleaf-backup-*.tar.gz" -mtime +$RETENTION_DAYS -delete
echo "=> Cleanup complete."
echo "========================================="
echo "Overleaf Backup Finished Successfully!"
echo "========================================="
exit 0
sh#!/bin/bash
# =================================================================
# == Overleaf Community Edition - 灾难恢复脚本 ==
# =================================================================
#
# !! 警告 !!
# 此脚本将彻底删除现有的 Overleaf 数据,并从指定的备份文件中恢复。
# 这是一个具有破坏性的操作,请在执行前再三确认。
#
# 使用方法:
# sudo ./restore_overleaf.sh /path/to/your/overleaf-backup-file.tar.gz
#
# =================================================================
# --- 配置区 (请根据你的实际情况修改) ---
# 1. Overleaf 数据应该存放的根目录
DATA_ROOT="xxx/overleaf/data_folers"
# 2. docker-compose.yml 文件所在的目录
COMPOSE_DIR="xxx/overleaf"
LOG_DIR="xxx/Overleaf_Backups/log"
LOG_FILE="$LOG_DIR/restore_activity.log"
# 检查是否以 root 身份运行
if [ "$(id -u)" -ne 0 ]; then
echo "!! 错误: 此脚本必须以 root 用户或使用 sudo 运行。"
exit 1
fi
# 确保日志目录存在
mkdir -p "$LOG_DIR"
echo -e "\n\n=======================================================" >> "$LOG_FILE"
echo "=== Starting New Restore Session at $(date) ===" >> "$LOG_FILE"
echo "=======================================================" >> "$LOG_FILE"
exec > >(tee -a "$LOG_FILE") 2>&1
# 检查是否提供了备份文件路径作为参数
BACKUP_FILE=$1
if [ -z "$BACKUP_FILE" ]; then
echo "!! 错误: 请提供备份文件的完整路径作为第一个参数。"
echo "用法: sudo $0 /path/to/your/backup.tar.gz"
exit 1
fi
# 检查备份文件是否存在
if [ ! -f "$BACKUP_FILE" ]; then
echo "!! 错误: 找不到指定的备份文件: $BACKUP_FILE"
exit 1
fi
# 最后的确认,给用户一个反悔的机会
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
echo "!! 警告:危险操作 "
echo "!! 此脚本将执行以下操作: "
echo "!! 1. 停止并移除所有 Overleaf 容器。 "
echo "!! 2. 永久删除以下现有数据目录: "
echo "!! - $DATA_ROOT/sharelatex_data"
echo "!! - $DATA_ROOT/mongo_data"
echo "!! - $DATA_ROOT/redis_data"
echo "!! 3. 从以下备份文件恢复数据: "
echo "!! $BACKUP_FILE"
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
read -p "你确定要继续吗? (输入 'yes' 继续): " CONFIRMATION
if [ "$CONFIRMATION" != "yes" ]; then
echo "操作已取消。"
exit 0
fi
echo "========================================="
echo "Starting Overleaf Restore: $(date)"
echo "========================================="
# 1. 停止并移除现有服务
echo "[Step 1/7] Stopping and removing existing Overleaf services..."
cd "$COMPOSE_DIR" || { echo "!! 错误: 找不到部署目录 $COMPOSE_DIR"; exit 1; }
docker compose down
echo "=> Services stopped and removed."
# 2. 创建一个临时的恢复工作目录
RESTORE_WORKDIR="/tmp/overleaf_restore_$$" # $$ 是当前进程ID,确保唯一性
mkdir -p "$RESTORE_WORKDIR"
echo "[Step 2/7] Created temporary restore directory: $RESTORE_WORKDIR"
# 3. 将备份压缩包复制并解压到临时目录
echo "[Step 3/7] Copying and extracting backup file..."
cp "$BACKUP_FILE" "$RESTORE_WORKDIR/"
tar -xzf "$RESTORE_WORKDIR/$(basename "$BACKUP_FILE")" -C "$RESTORE_WORKDIR"
echo "=> Backup extracted."
# 4. 永久删除现有的数据目录
echo "[Step 4/7] Deleting existing data directories..."
rm -rf "$DATA_ROOT/sharelatex_data"
rm -rf "$DATA_ROOT/mongo_data"
rm -rf "$DATA_ROOT/redis_data"
echo "=> Existing data directories removed."
# 5. 移动恢复出来的数据到目标位置
echo "[Step 5/7] Moving restored data to final destination..."
mv "$RESTORE_WORKDIR/sharelatex_data" "$DATA_ROOT/"
mv "$RESTORE_WORKDIR/mongo_data" "$DATA_ROOT/"
mv "$RESTORE_WORKDIR/redis_data" "$DATA_ROOT/"
# 询问是否恢复配置文件,大部分时候我们不需要修改docker-compose.yml文件
while true; do
read -p "是否恢复备份中的 docker-compose.yml 配置文件? (yes/no): " yn
case $yn in
[Yy][Ee][Ss])
RESTORE_CONFIG_FILE=true
echo "=> 将会恢复 docker-compose.yml。"
mv "$RESTORE_WORKDIR/docker-compose.yml" "$COMPOSE_DIR/"
break # 跳出循环
;;
[Nn][Oo])
RESTORE_CONFIG_FILE=false
echo "=> 将会跳过恢复 docker-compose.yml,请确保你当前的配置文件是正确的。"
break # 跳出循环
;;
*)
echo "!! 无效输入: 请输入 'yes' 或 'no'。"
;;
esac
done
echo "=> Data moved."
# 6. 为恢复出来的数据设置正确的权限
echo "[Step 6/7] Setting correct permissions for restored data..."
chown -R 33:33 "$DATA_ROOT/sharelatex_data"
chown -R 999:999 "$DATA_ROOT/mongo_data"
chown -R 999:999 "$DATA_ROOT/redis_data"
echo "=> Permissions set."
# 7. 启动服务并清理临时文件
echo "[Step 7/7] Starting Overleaf services and cleaning up..."
docker compose up -d
rm -rf "$RESTORE_WORKDIR"
echo "=> Services started and temporary files removed."
echo "========================================="
echo "Overleaf Restore Finished Successfully!"
echo "========================================="
exit 0
本文作者:MoooYuuu
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!