LaTeXRender
LaTeXRender is the service behind https://latex.codecogs.com: a real TeX installation,
wrapped so that an HTTP request carrying an equation comes back as a PNG, GIF, SVG, EMF or PDF of
that equation. It is the renderer of last resort and of first quality — if an equation uses
a package, a font or a construct that no browser-side engine implements, this is the one that
still draws it correctly, because it is running the same TeX a journal would.
Most people never deploy it. The hosted service at https://latex.codecogs.com is free for
ordinary use and needs no account. You deploy your own when one of the following is true:
The equations cannot leave your network. Student work, unpublished research, clinical or commercial material — a URL to a public rendering service puts the equation in somebody else's logs.
The volume is beyond fair usage. A learning platform rendering every equation of every question for every student runs into six figures of requests a day. That is a licensing conversation, not a rate-limit conversation.
You need it to be there. An internal deployment fails when your own infrastructure fails, and not otherwise.
You need your own TeX. Your own packages, your own fonts, your
own .sty files, pinned to your own versions.
If what you actually want is equations rendered in the browser with no server at all, read fxTeX first. It covers the overwhelming majority of equations at zero infrastructure cost, and the two are frequently deployed together — fxTeX for the page, LaTeXRender for export, print and the long tail.
What a licence includes
A licence is a key and a Docker Hub credential. There is no installer, no TeX to configure and no package list to curate — the images carry a TeX distribution built for this purpose, including the CodeCogs extensions.
| Image | Role |
|---|---|
eqneditor-cgi | The renderer. TeX, the rendering pipeline, and the HTTP interface documented under API. |
eqneditor-html | An optional front end — the editor and demo site, served against your own renderer. |
eqneditor-clean | Housekeeping. Expires cached equation files so the volume does not grow without limit. |
The key is checked by the cgi service at startup and is what ties a deployment to
an organisation. It is passed as an environment variable, which means it belongs in your
orchestrator's secret store rather than in a file you commit.
Docker deployment
Deployment is one command against a Swarm. The images are private, so the registry credential
has to travel with the deploy — that is what --with-registry-auth does, and
leaving it off produces a stack whose tasks never start because no node can pull anything.
docker login
docker stack deploy --with-registry-auth --compose-file docker-cgi.yml eqn
Check it came up, and that TeX answers:
docker stack services eqn
curl "http://localhost/png.image?x^2"
Updating to a new release is the same command with a new tag in the file. Swarm rolls the replicas one at a time, so the service stays up throughout.
docker-cgi.yml
The file we deploy our own estate with, with the credentials removed. Six replicas of the renderer, at most two to a node, is a sensible starting point for a few hundred thousand equations a day; the cache in front of it means most requests never reach TeX at all.
version: "3.9"
services:
cgi:
image: willzyba/eqneditor-cgi:5.9.2.1
deploy:
mode: replicated
replicas: 6
placement:
max_replicas_per_node: 2
restart_policy:
condition: any
delay: 5s
max_attempts: 5
window: 120s
volumes:
- ./eq:/var/www/eq # Cached equation files
- ./usr:/var/www/usr # Usage logs
- ./log:/var/www/log # System logs
- ./settings:/var/www/settings # Settings
- ./file:/var/www/file # Permanent file storage
- type: tmpfs
target: /tmp/ramdisk # TeX scratch space
tty: true
environment:
- EQN_RENDER_URL=https://equations.example.com # Where this service is reachable
- EQN_PARENT_DOMAIN=example.com # The site the equations are for
- EQN_LICENCE=<your licence key>
- EQN_POD_NAME=Docker-{{.Task.ID}}
- EQN_ADMIN_PASSWORD=<choose one>
ports:
- 80:80
healthcheck:
test: wget -qO - http://localhost/health || exit 1
interval: 60s
timeout: 15s
retries: 3
start_period: 15s
html:
image: willzyba/eqneditor-html:5.8.1.44
deploy:
mode: replicated
replicas: 2
placement:
max_replicas_per_node: 1
restart_policy:
condition: any
delay: 5s
max_attempts: 5
window: 500s
volumes:
- ./eq:/var/www/html/eq
- ./log:/var/www/log
tty: true
environment:
- EQN_RENDER_URL=https://equations.example.com
- EQN_RENDER_SERVICE_URL=http://cgi
ports:
- 5000:80
clean:
image: willzyba/eqneditor-clean:5.8.1.44
deploy:
mode: global
restart_policy:
delay: 30m
volumes:
- ./eq:/var/www/eq
- ./log:/var/www/log
Configuration
| Variable | Meaning |
|---|---|
EQN_LICENCE | Your licence key. Required by cgi. |
EQN_RENDER_URL | The public address this deployment answers on. Used in the URLs the editor and the JSON responses hand back, so it has to be the address a browser can actually reach — not the internal service name. |
EQN_PARENT_DOMAIN | The site the equations belong to. Recorded against usage. |
EQN_RENDER_SERVICE_URL | How the html front end reaches the renderer inside the stack — http://cgi on the Swarm's own overlay network. |
EQN_POD_NAME | Identifies the replica in the logs. {{.Task.ID}} is substituted by Swarm. |
EQN_ADMIN_PASSWORD | Guards the administrative pages. |
Volumes
./eq is the equation cache, and is the reason the service is fast.
An equation that has been rendered once is served as a file thereafter. It is shared between the
cgi, html and clean services, so on a multi-node Swarm it
needs to be shared storage rather than a per-node bind mount.
./settings holds configuration that survives a redeploy. Back it
up.
./usr and ./log are usage records and system logs.
/tmp/ramdisk is deliberately tmpfs. TeX writes a
considerable amount of scratch per equation, all of it disposable, and keeping it off the disk is
worth a measurable amount of latency.
Scaling
Rendering is CPU-bound and each request is independent, so the renderer scales by replica
count and nothing else. max_replicas_per_node keeps one busy node from taking the
whole service down with it. The clean service runs global — one
per node — because each node has its own disk to keep from filling.
More
The URL format, output types, sizes, colours and the JSON interface are all on the
API page. To point the editor or a plugin at your own
deployment instead of ours, set its renderUrl to your
EQN_RENDER_URL.
For licensing, talk to us.
CodeCogs®