Overleaf是一個線上的latex協作編輯平臺。這裡介紹Sharelatex—一個和overleaf有相同功能的工具,在伺服器上用docker部署的方式。

1. 重新打包sharelatex的docker映像

sharelatex現在已經改名叫做overleaf,官方推薦用overleaf toolkit來安裝。overleaf toolkit要修改linux環境,比較繁瑣。這裡用docker來部署,降低對原來linux環境的影響。

參考官方給出的docker-compose.yaml檔案

但是直接docker-compose,並不能排版中文,主要原因是缺少xelatex相關包。由於是在docker容器中,操作並不方便。這裡直接以原始sharelatex的docker映像為基礎生成新的docker映像。

在新的docker映像中,將會安裝texlive的更新,並且將xelatex相關包新增到環境變數中去。對應的Dockerfile如下:

Dockerfile
FROM sharelatex/sharelatex
RUN tlmgr option repository https://mirrors.tuna.tsinghua.edu.cn/CTAN/systems/texlive/tlnet
RUN tlmgr update --self --all
RUN tlmgr install scheme-full
WORKDIR /
ENTRYPOINT ["/sbin/my_init"]

在儲存Dockerfile的資料夾下,生成新的docker映像:

docker build --tag chinglin/sharelatex:latest --progress=plain . 2>&1 | tee build.log

2. 解決mongodb問題

需要在mongodb下面再加一個映像,初始化mongodb

mongoinit:
  restart: "no"
  image: mongo:4.4
  depends_on:
    mongo:
      condition: service_healthy
  entrypoint:
    [
      "mongo",
      "--host",
      "mongo:27017",
      "--eval",
      'rs.initiate({ _id: "overleaf", members: [ { _id: 0, host: "mongo:27017" } ] })',
    ]

3. docker-compose 執行

參考官方給出的docker-compose.yaml檔案,加上我們上面的魔改:

docker-compose.yaml
version: '2.2'
services:
    sharelatex:
        restart: always
        # Server Pro users:
        # image: quay.io/sharelatex/sharelatex-pro
        image: chinglin/sharelatex
        container_name: sharelatex
        depends_on:
            mongo:
                condition: service_healthy
            redis:
                condition: service_started
        ports:
            - 8089:80
        links:
            - mongo
            - redis
        stop_grace_period: 60s
        volumes:
            - ./data/sharelatex_data:/var/lib/sharelatex
            # - ./data/sharelatex_texlive:/texlive
            ########################################################################
            ####  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:

            SHARELATEX_APP_NAME: Overleaf Community Edition
            SHARELATEX_MONGO_URL: mongodb://mongo/sharelatex

            # Same property, unfortunately with different names in
            # different locations
            SHARELATEX_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'

            # temporary fix for LuaLaTex compiles
            # see https://github.com/overleaf/overleaf/issues/695
            TEXMFVAR: /var/lib/sharelatex/tmp/texmf-var

            ## Set for SSL via nginx-proxy
            #VIRTUAL_HOST: 103.112.212.22

            # SHARELATEX_SITE_URL: http://sharelatex.mydomain.com
            # SHARELATEX_NAV_TITLE: Our ShareLaTeX Instance
            # SHARELATEX_HEADER_IMAGE_URL: http://somewhere.com/mylogo.png
            # SHARELATEX_ADMIN_EMAIL: [email protected]

            # SHARELATEX_LEFT_FOOTER: '[{"text": "Powered by <a href=\"https://www.sharelatex.com\">ShareLaTeX</a> 2016"},{"text": "Another page I want to link to can be found <a href=\"here\">here</a>"} ]'
            # SHARELATEX_RIGHT_FOOTER: '[{"text": "Hello I am on the Right"} ]'

            # SHARELATEX_EMAIL_FROM_ADDRESS: "[email protected]"

            # SHARELATEX_EMAIL_AWS_SES_ACCESS_KEY_ID:
            # SHARELATEX_EMAIL_AWS_SES_SECRET_KEY:

            # SHARELATEX_EMAIL_SMTP_HOST: smtp.mydomain.com
            # SHARELATEX_EMAIL_SMTP_PORT: 587
            # SHARELATEX_EMAIL_SMTP_SECURE: false
            # SHARELATEX_EMAIL_SMTP_USER:
            # SHARELATEX_EMAIL_SMTP_PASS:
            # SHARELATEX_EMAIL_SMTP_TLS_REJECT_UNAUTH: true
            # SHARELATEX_EMAIL_SMTP_IGNORE_TLS: false
            # SHARELATEX_EMAIL_SMTP_NAME: '127.0.0.1'
            # SHARELATEX_EMAIL_SMTP_LOGGER: true
            # SHARELATEX_CUSTOM_EMAIL_FOOTER: "This system is run by department x"

            # ENABLE_CRON_RESOURCE_DELETION: true

            ################
            ## Server Pro ##
            ################

            # SANDBOXED_COMPILES: 'true'

            # SANDBOXED_COMPILES_SIBLING_CONTAINERS: 'true'
            # SANDBOXED_COMPILES_HOST_DIR: '/var/sharelatex_data/data/compiles'

            # DOCKER_RUNNER: 'false'

            # Works with test LDAP server shown at bottom of docker compose
            # SHARELATEX_LDAP_URL: 'ldap://ldap:389'
            # SHARELATEX_LDAP_SEARCH_BASE: 'ou=people,dc=planetexpress,dc=com'
            # SHARELATEX_LDAP_SEARCH_FILTER: '(uid={{username}})'
            # SHARELATEX_LDAP_BIND_DN: 'cn=admin,dc=planetexpress,dc=com'
            # SHARELATEX_LDAP_BIND_CREDENTIALS: 'GoodNewsEveryone'
            # SHARELATEX_LDAP_EMAIL_ATT: 'mail'
            # SHARELATEX_LDAP_NAME_ATT: 'cn'
            # SHARELATEX_LDAP_LAST_NAME_ATT: 'sn'
            # SHARELATEX_LDAP_UPDATE_USER_DETAILS_ON_LOGIN: 'true'
            # SHARELATEX_TEMPLATES_USER_ID: "578773160210479700917ee5"
            # SHARELATEX_NEW_PROJECT_TEMPLATE_LINKS: '[ {"name":"All Templates","url":"/templates/all"}]'
            # SHARELATEX_PROXY_LEARN: "true"

    mongo:
        restart: always
        image: mongo:4.4
        container_name: mongo
        command: "--replSet overleaf"
        expose:
            - 27017
        volumes:
            - ./data/mongo_data:/data/db
        healthcheck:
            test: echo 'db.stats().ok' | mongo localhost:27017/test --quiet
            interval: 10s
            timeout: 10s
            retries: 5

    mongoinit:
        restart: "no"
        image: mongo:4.4
        depends_on:
          mongo:
            condition: service_healthy
        entrypoint:
          [
            "mongo",
            "--host",
            "mongo:27017",
            "--eval",
            'rs.initiate({ _id: "overleaf", members: [ { _id: 0, host: "mongo:27017" } ] })',
          ]

    redis:
        restart: always
        image: redis:6.2
        container_name: redis
        expose:
            - 6379
        volumes:
            - ./data/redis_data:/data

    # ldap:
    #    restart: always
    #    image: rroemhild/test-openldap
    #    container_name: ldap
    #    expose:
    #        - 389

    # 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/sharelatex/tmp:/etc/nginx/certs

執行docker-compose:

docker-compose up -d

為了能夠讓搭建好的服務在其它機器上能夠訪問,還需要開啟伺服器上對應埠,這裡是8090埠。

4. 新增使用者

前面已經通過docker-compose啟動了sharelatex,此時還需要進入docker容器新增賬戶,需要在伺服器上執行:

docker exec -i -t sharelatex /bin/bash
grunt user:create-admin --email [email protected]

此時出現一個網址。請把網址的localhost部分換成伺服器的網址,在瀏覽器中輸入賬戶和密碼則可以登陸。此時就可以進行愉快的寫作了。

5. 使用感受

好處:

  1. 開箱即用,無需每臺電腦上都安裝設定texlive。
  2. 可以共享,便於協作。
  3. 資料部署在自己伺服器中(表面上看起來會更加安全)。

缺點:

  1. 網頁前端的編輯器功能太naive,畢竟不能做一個好的編輯器。
  2. 還是編輯器前端的問題,似乎沒有辦法利用目前大語言模型自動生成程式碼的功能。

5. 總結

本文介紹了在伺服器上搭建sharelatex的方式,通過重新打包的方式解決了sharelatex無法中文編譯的問題,通過修改官方docker-compose.yaml檔案修復了mongodb的問題。