前言
Overleaf是一款协作式的云端LaTeX编辑工具。以前上学的时候,软件工程课的老师要求我们使用该工具和小组组员协作写报告。刚接触时,一头雾水,觉得它比word麻烦。不过随着写报告过程中的使用与熟悉,发现了它的便利与强大。先让AI总结下它的优缺点:
优点 |
缺点 |
在线协作 |
依赖网络(国内最好代理连接) |
跨平台与便捷性 |
编译速度与稳定性 |
模板丰富 |
学习曲线 |
集成化功能(PDF,Zotero,Git) |
自定义性受限 |
免费基础功能够用 |
高级功能需付费 |
云存储与分享 |
隐私与数据安全 |
说下我自己的看法:
-
命令确实繁多,对新手不友善。但实际使用中,最常用的命令只有图片、表格和引文这关键三项。附上官方教程。
-
从零构建项目费点事,但模板实在是太多了。大学或机构(特别是国外)格式要求严格的各种形式的文档、报告、论文模板等等几乎都有人上传,而且一般都带有使用说明。附上模板市场
-
云端编辑,实时保存,所以几乎不会丢失最新进度。
所以后面不少课程的报告,包括最后61页的毕业论文,我都是用Overleaf完成的。工作后有些文书工作,我还在继续使用Overleaf。
自部署Overleaf的想法,始于官方端免费账户的限制(编译时间限制已经缩短到20s)以及国内网络连接的稳定性。20s编译时限这一刀砍得太厉害,对于小报告来说,没啥影响。但对于稍大些的项目,编译时长很容易超限,导致编译失败。另外,部署在国内VPS上,能保证网络连接的稳定性。
部署
官方推荐使用Overleaf Toolkit部署和管理,不过也支持Docker部署。个人更习惯于使用Docker搭建。
构建镜像包
Overleaf只提供了amd64架构的镜像包,而我的VPS是arm64架构,因此需要依照官方所说,利用Dockerfile-base
和Dockerfile
分别构建arm64架构的sharelatex/sharelatex-base
和sharelatex/sharelatex
。
Fork源仓库后,编写自动化文档,完成自动追随上游代码更新和自动生成最新的基于arm64架构的镜像包发布到GitHub上。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
|
name: Build ARM64 Overleaf Images
on:
schedule:
- cron: '0 0 * * *' # 每日午夜运行
workflow_dispatch: # 允许手动触发
push:
paths:
- 'server-ce/Dockerfile*'
- '.github/workflows/build-arm64-overleaf.yml'
jobs:
check-upstream:
runs-on: ubuntu-latest
outputs:
update_needed: ${{ steps.check.outputs.update_needed }}
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Setup upstream remote
run: |
git remote add upstream https://github.com/overleaf/overleaf.git
git fetch upstream
- name: Check for updates
id: check
run: |
UPSTREAM_LATEST=$(git rev-parse upstream/main)
FORK_LATEST=$(git rev-parse HEAD)
if [ "$UPSTREAM_LATEST" != "$FORK_LATEST" ]; then
echo "update_needed=true" >> $GITHUB_OUTPUT
# 合并上游更改
git config user.name "GitHub Actions"
git config user.email "[email protected]"
git merge upstream/main --no-edit
git push origin main
else
echo "update_needed=false" >> $GITHUB_OUTPUT
fi
build-arm64-images:
needs: check-upstream
if: ${{ needs.check-upstream.outputs.update_needed == 'true' || github.event_name == 'workflow_dispatch' }}
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to GitHub Container Registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Get current date
id: date
run: echo "date=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT
- name: Build and push base image
uses: docker/build-push-action@v4
with:
context: ./server-ce
file: ./server-ce/Dockerfile-base
platforms: linux/arm64
push: true
tags: |
ghcr.io/${{ github.repository_owner }}/sharelatex-base:arm64-latest
ghcr.io/${{ github.repository_owner }}/sharelatex-base:arm64-${{ steps.date.outputs.date }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Build and push community image
uses: docker/build-push-action@v4
with:
context: .
file: ./server-ce/Dockerfile
platforms: linux/arm64
build-args: |
OVERLEAF_BASE_TAG=ghcr.io/${{ github.repository_owner }}/sharelatex-base:arm64-latest
push: true
tags: |
ghcr.io/${{ github.repository_owner }}/sharelatex:arm64-latest
ghcr.io/${{ github.repository_owner }}/sharelatex:arm64-${{ steps.date.outputs.date }}
cache-from: type=gha
cache-to: type=gha,mode=max
|
耗时1h30min+后,镜像包构建完成,地址:ypxun/overleaf_packages
搭建容器
官方的compose文档,按需修改,并注释Pro用户相关参数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
|
services:
sharelatex:
restart: always
# Server Pro users:
# image: quay.io/sharelatex/sharelatex-pro
image: ghcr.io/ypxun/sharelatex:arm64-latest
container_name: sharelatex
depends_on:
mongo:
condition: service_healthy
redis:
condition: service_started
ports:
- 80:80
stop_grace_period: 60s
volumes:
- ~/sharelatex_data:/var/lib/overleaf
########################################################################
#### Server Pro: Uncomment the following line to mount the docker ####
#### socket, required for Sibling Containers to work ####
########################################################################
# - /var/run/docker.sock:/var/run/docker.sock
environment:
OVERLEAF_APP_NAME: Overleaf Community Edition
OVERLEAF_MONGO_URL: mongodb://mongo/sharelatex
# Same property, unfortunately with different names in
# different locations
OVERLEAF_REDIS_HOST: redis
REDIS_HOST: redis
ENABLED_LINKED_FILE_TYPES: project_file,project_output_file
# Enables Thumbnail generation using ImageMagick
ENABLE_CONVERSIONS: "true"
# Disables email confirmation requirement
EMAIL_CONFIRMATION_DISABLED: "true"
## Set for SSL via nginx-proxy
#VIRTUAL_HOST: 103.112.212.22
OVERLEAF_SECURE_COOKIE: true
OVERLEAF_BEHIND_PROXY: true
# OVERLEAF_SITE_URL: http://overleaf.example.com
# OVERLEAF_NAV_TITLE: Overleaf Community Edition
# OVERLEAF_HEADER_IMAGE_URL: http://example.com/mylogo.png
# OVERLEAF_ADMIN_EMAIL: [email protected]
# OVERLEAF_LEFT_FOOTER: '[{"text": "Another page I want to link to can be found <a href=\"here\">here</a>"} ]'
# OVERLEAF_RIGHT_FOOTER: '[{"text": "Hello I am on the Right"} ]'
# OVERLEAF_EMAIL_FROM_ADDRESS: "[email protected]"
# 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"
# ENABLE_CRON_RESOURCE_DELETION: true
################
## Server Pro ##
################
## Sandboxed Compiles: https://github.com/overleaf/overleaf/wiki/Server-Pro:-Sandboxed-Compiles
# SANDBOXED_COMPILES: 'true'
# SANDBOXED_COMPILES_SIBLING_CONTAINERS: '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'
## Works with test LDAP server shown at bottom of docker compose
# OVERLEAF_LDAP_URL: 'ldap://ldap:389'
# OVERLEAF_LDAP_SEARCH_BASE: 'ou=people,dc=planetexpress,dc=com'
# OVERLEAF_LDAP_SEARCH_FILTER: '(uid={{username}})'
# OVERLEAF_LDAP_BIND_DN: 'cn=admin,dc=planetexpress,dc=com'
# OVERLEAF_LDAP_BIND_CREDENTIALS: 'GoodNewsEveryone'
# OVERLEAF_LDAP_EMAIL_ATT: 'mail'
# OVERLEAF_LDAP_NAME_ATT: 'cn'
# OVERLEAF_LDAP_LAST_NAME_ATT: 'sn'
# OVERLEAF_LDAP_UPDATE_USER_DETAILS_ON_LOGIN: 'true'
# OVERLEAF_TEMPLATES_USER_ID: "578773160210479700917ee5"
# OVERLEAF_NEW_PROJECT_TEMPLATE_LINKS: '[ {"name":"All Templates","url":"/templates/all"}]'
# OVERLEAF_PROXY_LEARN: "true"
mongo:
restart: always
image: mongo:6.0
container_name: sharelatex-mongo
command: --replSet overleaf
volumes:
- ~/mongo_data:/data/db
- ./bin/shared/mongodb-init-replica-set.js:/docker-entrypoint-initdb.d/mongodb-init-replica-set.js
environment:
MONGO_INITDB_DATABASE: sharelatex
extra_hosts:
# Required when using the automatic database setup for initializing the replica set.
# This override is not needed when running the setup after starting up mongo.
- mongo:127.0.0.1
healthcheck:
test: echo 'db.stats().ok' | mongosh localhost:27017/test --quiet
interval: 10s
timeout: 10s
retries: 5
redis:
restart: always
image: redis:6.2
container_name: sharelatex-redis
volumes:
- ~/redis_data:/data # ldap:
# restart: always
# image: rroemhild/test-openldap
# container_name: ldap
# See https://github.com/jwilder/nginx-proxy for documentation on how to configure the nginx-proxy container,
# and https://github.com/overleaf/overleaf/wiki/HTTPS-reverse-proxy-using-Nginx for an example of some recommended
# settings. We recommend using a properly managed nginx instance outside of the Overleaf Server Pro setup,
# but the example here can be used if you'd prefer to run everything with docker-compose
# nginx-proxy:
# image: jwilder/nginx-proxy
# container_name: nginx-proxy
# ports:
# - "80:80"
# - "443:443"
# volumes:
# - /var/run/docker.sock:/tmp/docker.sock:ro
# - /home/overleaf/tmp:/etc/nginx/certs
|
Nginx反代
官方反代文档,本人overleaf.conf
配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name overleaf.example.com;
ssl_certificate /path/to/your/cert.pem; # 证书位置
ssl_certificate_key /path/to/your/key.pem; # 私钥位置
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m;
ssl_session_tickets off;
ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
# config to enable HSTS(HTTP Strict Transport Security) https://developer.mozilla.org/en-US/docs/Security/HTTP_Strict_Transport_Security
# to avoid ssl stripping https://en.wikipedia.org/wiki/SSL_stripping#SSL_stripping
add_header Strict-Transport-Security "max-age=31536000; includeSubdomains;";
server_tokens off;
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
client_max_body_size 500M;
location / {
proxy_pass http://127.0.0.1:80; # change to whatever host/port the docker container is listening on.
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_read_timeout 3m;
proxy_send_timeout 3m;
}
}
|
80端口的配置文件详见MinIO部署与PicGo中的/etc/nginx/nginx.conf
(通用配置)。
至此,Overleaf搭建完成,网页前端设置Admin账户后,就可以开始使用了。
感想
标题说的AI,似乎并没有提及,其实就在最关键的构建镜像包那一步。平常我也有用ChatGPT、Claude和DeepSeek,只是没想到现在的AI强到这个地步。最惊讶到我的是我仅仅使用一段不长的普通的人类语句询问Claude 3.7 Sonnet,就一步成型自动化配置文档,文档中的代码一句不用改,完美运行。AI现在的实力真是恐怖如斯,也难怪现在的通用智能体如火如荼。