> For the complete documentation index, see [llms.txt](https://overleaf-pro.ayaka.space/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://overleaf-pro.ayaka.space/on-premises/zh-tw/she-ding/overleaf-toolkit/sandboxed-compiles.md).

# Sandboxed Compiles

Overleaf Pro 提供可在受保護沙箱環境中執行編譯的選項，以符合企業安全需求。其作法是讓每個專案都在各自受保護的 Docker 環境中執行。

### 安全性提升

沙箱化編譯是 Server Pro 的建議做法，因為許多 LaTeX 文件需要／能夠在 PDF 編譯過程中執行任意 shell 命令。若您使用沙箱化編譯，每次編譯都會在一個獨立的 Docker 容器中執行，該容器具有限制的能力，且不與任何其他使用者或專案共享，也無法存取外部資源，例如主機網路。

{% hint style="warning" %}
如果您嘗試執行 Overleaf Pro **而未** 使用沙箱化編譯，編譯會在主 Docker 容器中與其他同時進行的編譯一同執行，使用者在執行 LaTeX 編譯時可完整讀寫 `sharelatex` 容器資源（檔案系統、網路與環境變數）。
{% endhint %}

### 更 آسان的套件管理

為了避免手動安裝套件，我們建議啟用沙箱化編譯。這是 Server Pro 中可設定的選項，會讓您的使用者可存取與 overleaf.com 相同的 TeX Live 環境，但位於您自己的內部部署安裝中。沙箱化編譯所使用的 TeX Live 映像包含我們在 gallery 範本中測試過的最常用套件與字型，可確保與內部部署專案達到最大的相容性。

啟用沙箱化編譯後，您可以設定使用者可在其專案中選擇的 TeX Live 版本，並為新專案設定預設的 TeX Live 映像版本。

{% hint style="info" %}
如果您嘗試執行 Overleaf Pro 而未使用沙箱化編譯，您的執行個體將預設使用基本方案版本的 TeX Live 進行編譯。這個基本版本較輕量，只包含非常有限的 LaTeX 套件子集合，因此很可能會導致使用者缺少套件的錯誤，尤其是當他們嘗試使用預先建置的範本時。
{% endhint %}

由於 Overleaf Pro 的架構設計可離線運作，因此沒有自動化方式可將 overleaf.com 的 gallery 範本整合到您的內部部署安裝中；不過，可以針對每個範本手動執行。若要了解其運作方式，請參閱我們的從 overleaf.com 轉移範本指南： [/pages/17e98813f59d6ed57c0dfa0721b9c99628ebfc60#transferring-templates-from-overleaf.com](https://overleaf-pro.ayaka.space/on-premises/zh-tw/she-ding/overleaf-toolkit/pages/17e98813f59d6ed57c0dfa0721b9c99628ebfc60#transferring-templates-from-overleaf.com "mention").

{% hint style="info" %}
沙箱化編譯需要 `sharelatex` 容器可透過繫結掛載（bind mount）存取主機上的 Docker socket，以便管理這些同層編譯容器。
{% endhint %}

## 運作方式

啟用沙箱化編譯後，Docker socket 會從主機掛載到 `sharelatex` 容器中，讓容器內的編譯服務可在主機上建立新的 Docker 容器。接著在每個專案的每次編譯中，LaTeX 編譯服務（CLSI）會執行以下操作：

* 將專案檔案寫入 `OVERLEAF_DATA_PATH`.
* 使用已掛載的 Docker socket 建立一個新的 `texlive` 容器用於本次編譯。
* 讓 `texlive` 容器從 `OVERLEAF_DATA_PATH`.
* 在 `texlive` 容器內的 .log 檔案。

### 啟用沙箱化編譯&#xD;

#### 適用於 Toolkit 使用者

若要啟用沙箱化編譯（也稱為同層容器），請在 `overleaf-toolkit/config/overleaf.rc`:

{% code title="config/overleaf.rc" %}

```dotenv
SERVER_PRO=true
SIBLING_CONTAINERS_ENABLED=true
```

{% endcode %}

#### 適用於 Docker Compose 使用者 <a href="#docker-compose-example" id="docker-compose-example"></a>

{% hint style="danger" %}
自 Overleaf CE/Server Pro `5.0.3` 環境變數已重新命名，自 `SHARELATEX_*` 到 `OVERLEAF_*`.
{% endhint %}

如果您使用的是 `4.x` 版本（或更早版本）開始，請確保變數有相應的前綴（例如 `SHARELATEX_MONGO_URL` 而不是 `OVERLEAF_MONGO_URL`).

<pre class="language-yml"><code class="lang-yml">version: '2'
services:
    sharelatex:
        #...
        volumes:
            - /data/overleaf_data:/var/lib/overleaf
<strong>            - /var/run/docker.sock:/var/run/docker.sock
</strong>        environment:
            #...
<strong>            DOCKER_RUNNER: "true"
</strong><strong>            SANDBOXED_COMPILES: "true"
</strong><strong>            SANDBOXED_COMPILES_HOST_DIR: "/data/overleaf_data/data/compiles"
</strong>            #...
        #...
</code></pre>

### 變更 TexLive 映像

{% hint style="info" %}
對於中國大陸使用者，您可以使用 `ghcr.nju.edu.cn` 來加速您的下載。&#x20;
{% endhint %}

Overleaf Pro 使用三個環境變數來決定沙箱化編譯要使用哪些 TeX Live 映像：

* `TEX_LIVE_DOCKER_IMAGE` **（必要），** 用於編譯新專案的預設 TeX Live 映像。此映像必須包含在 `ALL_TEX_LIVE_DOCKER_IMAGES`.
* `ALL_TEX_LIVE_DOCKER_IMAGE_NAMES` **（必要），** 以逗號分隔的友善名稱清單，供前端選項使用。
* `ALL_TEX_LIVE_DOCKER_IMAGES` **（必要），** 要使用的 TeX Live 映像的逗號分隔清單。如果使用 Overleaf Toolkit 部署，這些映像將會被下載或更新。若要略過下載，請設定 `SIBLING_CONTAINERS_PULL=false` 在 `config/overleaf.rc`.

當您使用 `bin/up` 命令啟動 Overleaf Pro 執行個體時，Toolkit 會自動拉取 `ALL_TEX_LIVE_DOCKER_IMAGES`.

以下是範例：我們將新專案預設為 TeX Live 2025，並讓現有專案繼續使用 2024。

{% code title="config/variables.env" overflow="wrap" %}

```dotenv
ALL_TEX_LIVE_DOCKER_IMAGES=ghcr.io/ayaka-notes/texlive-full:2025.1, ghcr.io/ayaka-notes/texlive-full:2024.1
ALL_TEX_LIVE_DOCKER_IMAGE_NAMES=Texlive 2025, Texlive 2024
TEX_LIVE_DOCKER_IMAGE=ghcr.io/ayaka-notes/texlive-full:2025.1
```

{% endcode %}

{% hint style="danger" %}
強烈建議設定 **至少 2 個 texlive-full 映像**。詳細原因請參見 [#known-issues](#known-issues "mention")
{% endhint %}

### 可用的 TeX Live 映像

這是一系列針對 Overleaf 特別最佳化的 TeX Live 映像，也可加入到 `TEX_LIVE_DOCKER_IMAGE` 以及 `ALL_TEX_LIVE_DOCKER_IMAGES`:&#x20;

* `ghcr.io/ayaka-notes/texlive-full:2025.1` （亦為 `latest` 標籤）
* `ghcr.io/ayaka-notes/texlive-full:2024.1`
* `ghcr.io/ayaka-notes/texlive-full:2023.1`
* `ghcr.io/ayaka-notes/texlive-full:2022.1`
* `ghcr.io/ayaka-notes/texlive-full:2021.1`
* `ghcr.io/ayaka-notes/texlive-full:2020.1`

{% hint style="warning" %}
關於映像 **必須** 的標記方式有嚴格的結構規範（適用以下 regex `^[0-9]+.[0-9]+`，其中第一個數字決定 TeX Live 的年份，第二個數字決定修補版本）。
{% endhint %}

### 我可以使用其他映像登錄庫嗎

> 有些人可能會想，我是否可以將 `ghcr.io` 換成其他鏡像站，或把 texlive 改用 docker hub 上的其他映像？

不，我們不建議這麼做，因為設定相對複雜。如果您是從鏡像站下載，您可以將映像重新命名為 `ghcr.io/ayaka-notes/texlive-full`.

但是，如果您真的想使用自己的映像登錄庫，請加入：

{% code title="config/variables.env" overflow="wrap" %}

```dotenv
IMAGE_ROOT=hub.your.com/your-repo
```

{% endcode %}

接著，您需要確保所有 texlive 的映像都位於 `your-repo`，例如

* `hub.your.com/your-repo/texlive-full:2025.1`
* `hub.your.com/your-repo/texlive-full:2024.1`

詳細資訊請閱讀下方原始碼，以了解我們如何解析您的環境變數：

{% code title="sandboxed-compiles/index.mjs" overflow="wrap" expandable="true" %}

```mjs
if (process.env.SANDBOXED_COMPILES === 'true') {
  // 如果未提供，則設定預設映像根目錄
  let imageRootPath = process.env.IMAGE_ROOT || "ghcr.io/ayaka-notes";
  // 將 imageRoot 匯出到 Settings
  Settings.imageRoot = imageRootPath

  // allowedImageNames 應該為：
  // [
  //  { imageName: "texlive-2023:latest", imageDesc: "TeX Live 2023" },
  //  { imageName: "texlive-2022:latest", imageDesc: "TeX Live 2022" },
  // ]
  Settings.allowedImageNames = parseTextExtensions(process.env.ALL_TEX_LIVE_DOCKER_IMAGES)
    .map((texImage, index) => ({
      imageName: texImage.split("/")[texImage.split("/").length - 1],
      imageDesc: parseTextExtensions(process.env.ALL_TEX_LIVE_DOCKER_IMAGE_NAMES)[index]
        || texImage.split(':')[1],
    }))
  
  // 最後，imageName 會與 imageRoot 組合成完整的映像路徑
  // 完整名稱會像這樣：ghcr.io/ayaka-notes/texlive-2023:latest

  // 如果未提供，則設定預設映像名稱
  if(!process.env.TEX_LIVE_DOCKER_IMAGE) {
    process.env.TEX_LIVE_DOCKER_IMAGE = imageRootPath + "/" + Settings.allowedImageNames[0].imageName
  }

  // 將 currentImageName 匯出到 Settings
  // 這是新建立專案的映像名稱
  Settings.currentImageName = process.env.TEX_LIVE_DOCKER_IMAGE
}
```

{% endcode %}

### 已知問題

> 使用 `6.0.1-ext-v3.3`，我有以下設定在 `variables.env`:
>
> ```dotenv
> TEX_LIVE_DOCKER_IMAGE=texlive/texlive:latest-full
> ALL_TEX_LIVE_DOCKER_IMAGES=texlive/texlive:latest-full
> ```
>
> 這在使用 `texlive/texlive:latest-full`時運作正常。不過，我另外拉取了另一個 texlive 映像 `danteev/texlive:2025-10-15` 並將這兩個變數都改成新的映像名稱，但無法運作：
>
> ```dotenv
> TEX_LIVE_DOCKER_IMAGE=danteev/texlive:2025-10-15
> ALL_TEX_LIVE_DOCKER_IMAGES=danteev/texlive:2025-10-15
> ```
>
> 在日誌中，我看到以下內容：
>
> {% code overflow="wrap" %}
>
> ```
> {"name":"clsi","level":50,"err":{"message":"(HTTP code 404) 沒有此容器 - 沒有此映像：texlive/texlive:latest-full ","name":"Error","stack":"Error: (HTTP code 404) 沒有此容器 - 沒有此映像：texlive/texlive:latest-full ... 
> ```
>
> {% endcode %}
>
> 似乎 `variables.env` 中的更新設定沒有生效。編譯仍然嘗試執行 `texlive/texlive:latest-full` 映像，而不是新的映像。
>
> 我試過重新啟動、刪除容器並重新執行，但問題仍然一樣。
>
> 有什麼解決方案嗎？

由於一些技術限制，如果您只設定了一個 Docker TeXLive 映像，例如 `texlive-fullA:latest`&#x20;

```
ALL_TEX_LIVE_DOCKER_IMAGES=texlive/texliveA:latest-full
ALL_TEX_LIVE_DOCKER_IMAGE_NAMES=TeXLiveA
TEX_LIVE_DOCKER_IMAGE=texlive/texliveA:latest-full
```

在 Overleaf 執行一段時間後，您可能會想將 TeXLive 映像修改為 `texlive-fullB:latest`。接著，您會發現使用者無法編譯所有專案。

```
ALL_TEX_LIVE_DOCKER_IMAGES=texlive/texliveA:latest-full
ALL_TEX_LIVE_DOCKER_IMAGE_NAMES=TeXLiveA
TEX_LIVE_DOCKER_IMAGE=texlive/texliveA:latest-full
```

這是因為每個專案中 TeXLive-Full 映像（用於沙箱編譯）的名稱會持久保存於資料庫中。 *只有當使用者切換其專案的 TeXLive 版本時，例如從 2024 切換到 2025，資料庫中的映像名稱才會變更*.

當 CLSI 編譯專案時，它會直接使用資料庫中找到的容器映像名稱來編譯該專案。

如果您只提供一個 Docker 映像，使用者將無法修改用於編譯專案的映像。在這種情況下，您需要撰寫腳本來 **手動修改** MongoDB 中所有使用者專案的 TeXLive 映像。

### 偵錯

執行下列命令以從 toolkit 檢查 clsi 日誌：

{% code overflow="wrap" %}

```bash
bin/logs clsi
```

{% endcode %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://overleaf-pro.ayaka.space/on-premises/zh-tw/she-ding/overleaf-toolkit/sandboxed-compiles.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
