Files
docker-compose-repo/overleaf/README.md
T

191 lines
7.4 KiB
Markdown

# Overleaf
Self-hosted LaTeX editor — the Community Edition of overleaf.com. Real-time
collaborative editing, compiles server-side, keeps a full TeX Live install so
you don't maintain one locally.
## Quick start
```bash
cp .env.example .env
echo "OVERLEAF_INVITE_TOKEN_SECRET=$(openssl rand -base64 32)" >> .env
$EDITOR .env # set OVERLEAF_SITE_URL
docker compose up -d
```
First boot takes a minute or two. Then create the first admin account — there
is no signup form until a user exists:
```bash
docker compose exec sharelatex bash -c \
'cd /overleaf/services/web && node modules/server-ce-scripts/scripts/create-user.mjs --admin --email=you@example.com'
```
It prints an activation URL. Open it, set a password, done.
## Ports
| Port | Proto | Purpose |
|------|-------|---------|
| 8020 | http | Web UI (container listens on 80) |
Mongo and Redis are reachable only on the internal compose network.
## Why it looks like this
**Four containers, not one.** The app, MongoDB, Redis, and a one-shot replica-set
initializer. Overleaf is a small distributed system pretending to be an app.
**Mongo runs as a replica set** (`--replSet overleaf`) even though there's one
node. Overleaf uses transactions and change streams, which Mongo only provides
in replica-set mode. Something has to call `rs.initiate()` exactly once, which
is what [`init/mongodb-init-replica-set.js`](init/mongodb-init-replica-set.js)
does — Mongo runs anything in `/docker-entrypoint-initdb.d/` on first start
against an empty data directory. Skip this and Overleaf hangs at boot with
errors that don't mention replica sets.
`extra_hosts: mongo:127.0.0.1` is part of the same trick: the init script
registers the member as `mongo:27017`, so during initialization the container
has to resolve its own service name.
**No `SANDBOXED_COMPILES`.** Upstream's sample `docker-compose.yml` ships these
*enabled*:
```yaml
SANDBOXED_COMPILES: "true"
DOCKER_RUNNER: "true"
SANDBOXED_COMPILES_SIBLING_CONTAINERS: "true"
```
Directly above them, its own comment says sandboxed compiles are Server Pro
only and "must be commented out to avoid compile issues" on Community Edition.
Copy that file as-is and your documents don't compile. They're absent here on
purpose.
**The image is pinned to `6.2.2`.** Upstream's sample is unpinned. This is a
database-backed service with schema migrations between majors — an unattended
`docker compose pull` picking up a new major is not something you want to
discover on a Sunday.
**`container_name: overleaf-mongo` / `overleaf-redis`**, while the *service*
names stay `mongo` and `redis`. The service names are load-bearing —
`OVERLEAF_MONGO_URL: mongodb://mongo/sharelatex` resolves them — but upstream's
`container_name: mongo` would claim a very generic name on the host and collide
with the next stack that wants it.
**`stop_grace_period: 60s`** so in-flight compiles finish instead of being
killed mid-run.
## Behind your own domain
Set the public URL — this is the setting people miss:
```bash
# .env
OVERLEAF_SITE_URL=https://overleaf.example.com
```
Then uncomment `OVERLEAF_SECURE_COOKIE` in `compose.yaml`.
Caddy, which handles WebSockets automatically (Overleaf needs them for
collaborative editing and the compile log):
```caddy
overleaf.example.com {
reverse_proxy 192.168.1.50:8020
}
```
That's the whole config — Caddy gets the certificate itself. See
[reverse proxy](../docs/reverse-proxy.md).
A [Cloudflare Tunnel](../cloudflare-tunnel/) also works and passes WebSockets,
but mind the ~100 MB upload cap if you bring in large figures or datasets.
**Order matters:** change `OVERLEAF_SITE_URL` *before* creating accounts, or the
activation links you've already sent point at the wrong host.
## Running it on OpenMediaVault
Two things differ from a plain `docker compose up`, and both cost me an evening.
**Copy `init/mongodb-init-replica-set.js` across before the first start.** OMV's
compose plugin deploys the compose file and the env file, not the rest of the
directory. If that script isn't on disk when Mongo first starts, Docker creates
it as an empty *directory* — bind mounts do that for missing paths — Mongo skips
it, and the replica set is never initialized.
The symptom points nowhere near the cause: Mongo reports **healthy** while the
app restart-loops with `500_check_db_access.sh failed with status 1`. Mongo's
healthcheck only runs `db.stats().ok`, which succeeds fine without a replica set.
If you've already started it, fix it in place — the entrypoint won't re-run once
the data directory has data:
```bash
docker exec overleaf-mongo mongosh --quiet --eval \
'rs.initiate({_id:"overleaf",members:[{_id:0,host:"mongo:27017"}]})'
docker restart overleaf
```
**Use `docker exec`, not `docker compose`, for one-off commands.** OMV names the
env file `<stack>.env`, and Compose only auto-loads a file called `.env`. So a
manual compose command fails on the required variables even though the running
stack is perfectly configured:
```
required variable OVERLEAF_INVITE_TOKEN_SECRET is missing a value
```
The container already has the environment, so talk to it directly:
```bash
docker exec overleaf bash -c \
'cd /overleaf/services/web && node modules/server-ce-scripts/scripts/create-user.mjs --admin --email=you@example.com'
```
If you'd rather have compose work by hand too, symlink it once — OMV keeps
passing its own `--env-file` and won't notice:
```bash
ln -s overleaf.env .env
```
## Gotchas
- **`OVERLEAF_SECURE_COOKIE` is tested with `!= null`.** Setting it to `"false"`
turns secure cookies **on**. The only way to disable it is to leave it unset —
and with it wrongly on over plain HTTP, login silently fails to stick.
- **Mongo 8.0 needs AVX.** Mongo 5.0+ won't start on CPUs without it, and the
failure is an immediate exit with nothing useful logged. Check first:
`grep -o avx2 /proc/cpuinfo | head -1`
- **A healthy Mongo does not mean the replica set is up.** The healthcheck runs
`db.stats().ok`, which passes without one — so `depends_on: service_healthy`
is satisfied and the app starts anyway, then fails its own DB check.
- **The replica-set script only runs on an empty data directory.** If Mongo has
data but no replica set, initialize by hand:
`docker compose exec mongo mongosh --eval 'rs.initiate({_id:"overleaf",members:[{_id:0,host:"mongo:27017"}]})'`
- **No signup page until the first user exists.** Use the `create-user.mjs`
script above; the web UI won't offer to make one.
- **Back up `DATA_PATH`.** `data/mongo` holds every project. `data/overleaf`
holds uploaded files and compile output.
- **Upgrading across majors** may need migrations, and Mongo itself can't jump
several versions at once. Read the release notes rather than pulling blind.
## Health checks
The image ships its own:
```bash
docker compose exec sharelatex bash -c 'cd /overleaf/services/web && node modules/server-ce-scripts/scripts/check-mongodb.mjs'
docker compose exec sharelatex bash -c 'cd /overleaf/services/web && node modules/server-ce-scripts/scripts/check-redis.mjs'
docker compose exec mongo mongosh --quiet --eval 'rs.status().members.map(m => m.name + " " + m.stateStr)'
```
## Links
- Upstream repo: <https://github.com/overleaf/overleaf>
- Their sample compose: <https://github.com/overleaf/overleaf/blob/main/docker-compose.yml>
- The Toolkit (upstream's recommended installer): <https://github.com/overleaf/toolkit>
- Image: <https://hub.docker.com/r/sharelatex/sharelatex>