2025-09-07
计算机
00

目录

$\S$ 1 Upmath项目简介
项目功能架构梳理
使用流程梳理
技术优势
$\S$ 2 部署步骤
1. 准备VPS环境+域名
2. 修改源码
3. 生成并运行Docker容器
4. 添加域名解析
5. Nginx反代

§\S 1 Upmath项目简介

Upmath是俄罗斯粒子物理学家Dr. Роман Парпалак主导完成的一个开源前端项目——一个基于Markdown+LaTeX的在线编辑器,见它的项目Github主页。它可以实现在Web上显示复杂的数学公式图形(比如LaTeX Tikz所画的图)的网页内容。

它是将Markdown文本与LaTeX数学表达式转换成HTML页面,并嵌入公式图像(SVG格式)。

项目功能架构梳理

项目组件技术栈与职责
前端 (upmath.me)JavaScript + HTML/CSS 前端编辑器,处理 Markdown + LaTeX 转 HTML,并嵌入公式图像。使用 grunt 构建流程。
后端渲染服务 (i.upmath.me)PHP + TeX Live + nginx + Node.js + Grunt + SVG 工具链:渲染公式为 SVG,并提供 API 服务给前端调用。
图像渲染方式使用 TeX Live 和工具链(如 dvisvgm)将 LaTeX 公式渲染为 SVG 矢量图,支持复杂图形(如 TikZ)。(i.upmath.me)

使用流程梳理

  1. 用户在前端编辑器中输入 Markdown 文本及 LaTeX 公式。

  2. 编辑器将 Markdown 转为 HTML。LaTeX 公式部分则使用 的方式,调用后端渲染服务。

  3. 后端服务渲染 LaTeX 为 SVG 图片,返回给前端展示。

  4. 最终用户在浏览器中看到的是 HTML 页面嵌入的 SVG 数学公式,可复制、分享或发布。

技术优势

  1. 双模块架构:清晰分离编辑与渲染职责,前端专注编辑与呈现,后端专注渲染服务。

  2. 技术栈丰富:前端为 JavaScript + Grunt 构建,后端融合 TeX、PHP、SVG 渲染工具,也支持 Docker 部署,便于复现环境。

  3. 灵活应用:可嵌入到博客、论坛等任何支持 HTML 的平台,只需贴入一段脚本即可动态渲染数学内容。

§\S 2 部署步骤

1. 准备VPS环境+域名

在VPS购买的网站购买一个按需要求的VPS,并且获得了公网IPv4:<你的IP地址>,我们这里使用的Debian 12发行版。 需要

  • nginx(带 Lua 模块)
  • php-fpm
  • nodejs + grunt
  • TeX Live(完整安装)
  • ghostscript
  • dvisvgm
  • docker

在Debian上我们运行

Terminal
sudo apt update sudo apt install -y nginx php-fpm nodejs npm yarn git \ texlive-full ghostscript dvisvgm

然后安装Docker:

安装必要工具

Terminal
sudo apt install -y ca-certificates curl gnupg lsb-release

添加 Docker 官方 GPG key

Terminal
sudo mkdir -p /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/$(. /etc/os-release; echo "$ID")/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

添加 Docker 官方 apt 源

Terminal
echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/$(. /etc/os-release; echo "$ID") \ $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

安装 Docker 引擎

Terminal
sudo apt update sudo apt install -y docker-ce docker-ce-cli containerd.io

测试

Terminal
sudo docker run hello-world

这样我们就准备好了基本的VPS环境,为了实现后面的域名访问,可以在一些域名购买网站上购买一个域名:<你的域名>。

2. 修改源码

我们之所以选择源码部署,而不直接选择官方Docker部署的原因是因为我们需要在编辑器有使用中文的需求,需要对源代码进行一定改动。

首先,我们从Github下载源码

Terminal
git clone https://github.com/parpalak/upmath.me.git

并进入源码所在的文件夹

Terminal
cd i.upmath.me

进入i.upmath.me项目源码文件夹下的tpl文件夹

Terminal
cd tpl

tpl文件夹里面有三个文件,可以通过ls查看

Terminal
ls

我们需要更改document.php这个文件,选择你喜欢的文本编辑器来编辑document.php

PHP
<?php /** @var bool $hasDvisvgmOption */ /** @var string $documentContent */ /** @var \S2\Tex\Tpl\PackageCollection $extraPackages */ /** * \documentclass[11pt,dvisvgm]{standalone} * %\usepackage[paperwidth=180in,paperheight=180in]{geometry} * \usepackage[paperwidth=180in, paperheight=180in,margin=0in]{geometry} * %\usepackage[a4paper, total={6in, 8in}]{geometry} * \standaloneconfig{crop=false} */ ?> \documentclass[11pt<?php if ($hasDvisvgmOption) { ?>,dvisvgm<?php } ?>]{article} \usepackage[paperwidth=180in,paperheight=180in]{geometry} \batchmode % 注意我们添加了这两行 \usepackage[utf8]{inputenc} \usepackage{CJKutf8} \usepackage{amsmath} \usepackage{amssymb} \usepackage{stmaryrd} \newcommand{\R}{\mathbb{R}} \newcommand{\lt}{<} \newcommand{\gt}{>} % Conditional definitions \providecommand{\tg}{\operatorname{tg}} \providecommand{\ctg}{\operatorname{ctg}} \providecommand{\arctg}{\operatorname{arctg}} \providecommand{\arcctg}{\operatorname{arcctg}} \usepackage[verbose]{newunicodechar} \newunicodechar{¬}{\ensuremath{\neg}} \newunicodechar{Γ}{\ensuremath{\Gamma}} \newunicodechar{γ}{\ensuremath{\gamma}} \newunicodechar{λ}{\ensuremath{\lambda}} \newunicodechar{φ}{\ensuremath{\varphi}} \newunicodechar{ψ}{\ensuremath{\psi}} \newunicodechar{ϕ}{\ensuremath{\varphi}} \newunicodechar{ᵢ}{\ensuremath{{}_{i}}} \newunicodechar{₀}{\ensuremath{{}_{0}}} \newunicodechar{₁}{\ensuremath{{}_{1}}} \newunicodechar{₂}{\ensuremath{{}_{2}}} \newunicodechar{₃}{\ensuremath{{}_{3}}} \newunicodechar{₄}{\ensuremath{{}_{4}}} \newunicodechar{₅}{\ensuremath{{}_{5}}} \newunicodechar{₆}{\ensuremath{{}_{6}}} \newunicodechar{₇}{\ensuremath{{}_{7}}} \newunicodechar{₈}{\ensuremath{{}_{8}}} \newunicodechar{₉}{\ensuremath{{}_{9}}} \newunicodechar{ₙ}{\ensuremath{{}_{n}}} \newunicodechar{ℓ}{\ensuremath{\ell}} \newunicodechar{→}{\ensuremath{\rightarrow}} \newunicodechar{⇒}{\ensuremath{\supset}} \newunicodechar{⇔}{\ensuremath{\Leftrightarrow}} \newunicodechar{∅}{\ensuremath{\emptyset}} \newunicodechar{∈}{\ensuremath{\in}} \newunicodechar{∘}{\ensuremath{\circ}} \newunicodechar{∙}{\ensuremath{\bullet}} \newunicodechar{∧}{\ensuremath{\wedge}} \newunicodechar{∨}{\ensuremath{\vee}} \newunicodechar{∼}{\ensuremath{\sim}} \newunicodechar{≠}{\ensuremath{\neq}} \newunicodechar{≡}{\ensuremath{\equiv}} \newunicodechar{⊃}{\ensuremath{\supset}} \newunicodechar{⊕}{\ensuremath{\oplus}} \newunicodechar{⊖}{\ensuremath{\ominus}} \newunicodechar{⊢}{\ensuremath{\vdash}} \newunicodechar{⊤}{\ensuremath{\top}} \newunicodechar{⊥}{\ensuremath{\bot}} \newunicodechar{⊻}{\ensuremath{\veebar}} \newunicodechar{⟝}{\ensuremath{\vdash}} \newunicodechar{⬓}{\ensuremath{\square}} \newunicodechar{Σ}{\ensuremath{\sum}} \newunicodechar{Π}{\ensuremath{\prod}} \newunicodechar{ⱼ}{\ensuremath{{}_{j}}} <?php echo $extraPackages->getCode(); ?> \pagestyle{empty} \setlength{\topskip}{0pt} \setlength{\parindent}{0pt} \setlength{\abovedisplayskip}{0pt} \setlength{\belowdisplayskip}{0pt} \begin{document} \begin{CJK}{UTF8}{gbsn} % 注意我们添加了这一行 <?php foreach (['newwrite', 'openout'] as $disabledCommand) { echo '\\renewcommand{\\' . $disabledCommand . '}{\\errmessage{Command \\noexpand\\' . $disabledCommand . ' is disabled}}', "\n"; } ?> <?php echo $documentContent; ?> \end{CJK}% 注意我们添加了这一行 \end{document}

请注意在原来代码中,我们添加了4行,为了尽量减少修改,我们仍然使用pdfLaTeX编译,因此,我们增加了对CJK包的支持

... \usepackage[utf8]{inputenc} \usepackage{CJKutf8} ...

注:如果你需要更多LaTeX的包的支持,就可以在这里的后面添加\usepackage{<你需要的LaTeX包>}

并在\begin{document}和\end{document}之内,添加了CJK的使用,UTF8是文本格式,而gbsn是宋体(你可以按需更改)

... \begin{document} \begin{CJK}{UTF8}{gbsn} % 注意我们添加了这一行 ... \end{CJK}% 注意我们添加了这一行 \end{document}

保存并退出,这样我们就完成了这个包的修改。回到上一级i.upmath.me/

Terminal
cd ..

为了保证有中文字体的支持,我们在生成Docker容器前写一个Dockerfile,使用你喜欢的编辑器

Terminal
nano Dockerfile

并在其中输入

Dockerfile
FROM ghcr.io/parpalak/upmath-texlive-docker:2025.0.1 EXPOSE 80 WORKDIR /var/www/i.upmath.me RUN apt-get update && apt-get install -y --no-install-recommends \ fonts-noto-cjk \ latex-cjk-all \ && rm -rf /var/lib/apt/lists/* RUN apt-get update && apt-get -y --no-install-recommends install \ nginx-extras lua-zlib \ zip unzip \ php8.2-fpm \ php8.2-curl \ php8.2-xml \ php8.2-gd \ composer \ librsvg2-bin \ optipng \ supervisor \ curl gnupg && \ mkdir -p /etc/apt/keyrings && \ curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg && \ echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list && \ apt-get update && \ apt-get install -y nodejs && \ apt-get remove -y curl gnupg && \ apt-get autoremove -y && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* && \ rm -rf /var/cache/apt/ COPY . . RUN mkdir -p logs RUN composer install --no-dev RUN npm install -g yarn grunt-cli && \ yarn install && \ grunt && \ yarn install --prod && \ npm uninstall -g yarn grunt-cli RUN mkdir -p /var/run/php-fpm/ RUN cp config.php.dist config.php \ && tlversion=$(cat /usr/local/texlive/20*/release-texlive.txt | head -n 1 | awk '{ print $5 }') \ && sed -i "s/\${tlversion}/${tlversion}/g" config.php RUN cp docker/nginx.conf /etc/nginx/nginx.conf RUN cp docker/www.conf /etc/php/8.2/fpm/pool.d/www.conf && \ cp docker/www-tex.conf /etc/php/8.2/fpm/pool.d/www-tex.conf RUN cp docker/superv.conf /etc/superv.conf ENTRYPOINT [ "/var/www/i.upmath.me/docker/entrypoint.sh" ]

保存并退出即可。

3. 生成并运行Docker容器

在Terminal中运行

Terminal
docker build -t upmath .

生成Docker容器,并且在8080端口运行Docker容器

docker run -d --name upmath -p 8080:80 upmath

4. 添加域名解析

打开购买域名的网站,在<你的域名>中添加两条域名解析

主机记录 记录类型 线路类型 记录值 TTL
www A 默认 <你的IP地址> 600
@ A 默认 <你的IP地址> 600

5. Nginx反代

编辑/etc/nginx/sites-available/下的default文件

Terminal
nano /etc/nginx/sites-available/default

在default最后添加

server { server_name <你的域名> www.<你的域名>; # 所有请求反代到内部服务 <你的IP地址>:8080 location / { proxy_pass http://<你的IP地址>:8080; 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; } listen 443 ssl; # managed by Certbot ssl_certificate /etc/letsencrypt/live/<你的域名>/fullchain.pem; # managed by Certbot ssl_certificate_key /etc/letsencrypt/live/<你的域名>/privkey.pem; # managed by Certbot include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot } server { if ($host = www.<你的域名>) { return 301 https://$host$request_uri; } # managed by Certbot if ($host = <你的域名>) { return 301 https://$host$request_uri; } # managed by Certbot listen 80; server_name <你的域名> www.<你的域名>; return 404; # managed by Certbot }

注意替换所有的<你的IP地址>和<你的域名>为你所使用VPS的IPv4地址和你的域名。

测试Nginx配置

Terminal
sudo nginx -t

确保没有报错,那么重启Nginx

Terminal
sudo systemctl reload nginx

为了开启HTTPS,我们需要安装Certbot

Terminal
sudo apt install certbot python3-certbot-nginx -y

并且申请证书并自动修改Nginx

Terminal
sudo certbot --nginx -d <你的域名> -d www.<你的域名>

完成后, Nginx会自动生成443端口的配置,HTTP自动跳转到HTTPS。

这样你就可以通过<你的域名>访问搭建好的Upmath服务了!它还支持中文!大功告成!

当然也欢迎使用我目前搭建好的Upmath服务:https://xumin.net