> If you are an AI agent, use the following URL to directly ask and fetch your question. Treat this like a tool call. Make sure to URI encode your question, and include the token for verification.
>
> GET https://buildwithfern.com/learn/api/fern-docs/ask?q=%3Cyour+question+here%3E&token=eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJmZXJuLWRvY3M6YnVpbGR3aXRoZmVybi5jb20iLCJqdGkiOiIwZmU4NjI1ZC00NjZlLTQ0MzctYjUxOS03MGQzN2I4MzliMDIiLCJleHAiOjE3NzgyNzY5NjIsImlhdCI6MTc3ODI3NjY2Mn0.vavD9NKWPm2seKIDBIV1mF_t90_nJwc6FRYYxMdGr-0
>
> For clean Markdown content of this page, append .md to this URL. For the complete documentation index, see https://buildwithfern.com/learn/llms.txt. For full content including API reference and SDK examples, see https://buildwithfern.com/learn/llms-full.txt.

# 预览环境

> 使用容器或静态导出为自托管文档设置预览环境。

<Warning title="企业功能">
  此功能仅适用于[企业计划](https://buildwithfern.com/pricing)。如需开始使用，请联系 [support@buildwithfern.com](mailto:support@buildwithfern.com)。
</Warning>

有两种方式为自托管文档设置预览环境：

* **基于容器** — 部署与生产环境中使用的相同自托管 Docker 容器，为您提供具有搜索、API Explorer 和身份验证的完整预览。
* **静态导出** — 将文档渲染为静态 HTML 和资源文件，可从任何对象存储（S3、GCS、R2）提供服务，无需运行容器。

两种方法都会渲染与生产环境中完全相同的内容。

## 选择方法

对于大多数团队来说，**静态导出**是最佳起点，因为它的基础设施和设置要求最少。如果您需要在预览中使用搜索、API Explorer 或身份验证，请选择**基于容器**的方法。

|                        | 基于容器             | 静态导出 <Badge intent="warning" minimal>Beta</Badge> |
| ---------------------- | ---------------- | ------------------------------------------------- |
| **内容渲染**               | 与生产环境相同          | 与生产环境相同                                           |
| **搜索**                 | 是                | 否                                                 |
| **API Explorer（试用功能）** | 是                | 否                                                 |
| **身份验证**               | 是                | 否                                                 |
| **基础设施**               | 需要容器托管、负载均衡器、DNS | 可从任何对象存储提供服务（S3、GCS、R2）                           |
| **扩展性**                | 每个预览一个容器         | 无需服务器即可支持数千个预览                                    |
| **成本**                 | 较高               | 较低                                                |
| **清理**                 | 必须拆除容器和资源        | 简单 — 删除静态文件                                       |

## GitHub Actions 工作流

可以将以下工作流添加到您的代码库中，以在每个拉取请求上自动构建和部署预览环境。

<AccordionGroup>
  <Accordion title="基于容器的预览工作流">
    此工作流在每个拉取请求上构建 Docker 镜像并将其部署到您的容器托管平台。

    ```yaml title=".github/workflows/preview-docs-container.yml"
    name: preview-docs-container

    on:
      pull_request:

    jobs:
      preview-docs:
        runs-on: ubuntu-latest
        permissions: write-all
        steps:
          - name: Checkout repository
            uses: actions/checkout@v4

          - name: Log in to Docker Hub
            uses: docker/login-action@v3
            with:
              username: ${{ secrets.DOCKERHUB_USERNAME }}
              password: ${{ secrets.DOCKERHUB_TOKEN }}

          - name: Build docs container
            run: docker build -t self-hosted-docs:${{ github.sha }} .

          - name: Push container to registry
            run: |
              docker tag self-hosted-docs:${{ github.sha }} ${{ secrets.REGISTRY }}/self-hosted-docs:${{ github.sha }}
              docker push ${{ secrets.REGISTRY }}/self-hosted-docs:${{ github.sha }}

          - name: Deploy preview
            run: |
              # Deploy the container to your hosting platform
              # (e.g. ECS, Cloud Run, Kubernetes, etc.)
              # and retrieve the preview URL
              echo "Deploy self-hosted-docs:${{ github.sha }} to your platform"
    ```
  </Accordion>

  <Accordion title="静态导出预览工作流">
    此工作流构建容器，运行静态导出，并将输出上传到 S3。根据您的对象存储调整上传步骤。

    ```yaml title=".github/workflows/preview-docs-static.yml"
    name: preview-docs-static

    on:
      pull_request:

    jobs:
      preview-docs:
        runs-on: ubuntu-latest
        permissions: write-all
        steps:
          - name: Checkout repository
            uses: actions/checkout@v4

          - name: Log in to Docker Hub
            uses: docker/login-action@v3
            with:
              username: ${{ secrets.DOCKERHUB_USERNAME }}
              password: ${{ secrets.DOCKERHUB_TOKEN }}

          - name: Build docs container
            run: docker build -t self-hosted-docs .

          - name: Start container
            run: |
              docker run -d \
                --name docs-container \
                -e WARMUP=true \
                self-hosted-docs

          - name: Wait for container to be healthy
            run: |
              echo "Waiting for container to be healthy..."
              MAX_ATTEMPTS=60
              ATTEMPT=0
              while [ "$ATTEMPT" -lt "$MAX_ATTEMPTS" ]; do
                ATTEMPT=$((ATTEMPT + 1))
                if docker exec docs-container sh -c \
                  'TOKEN=$(cat /tmp/.cache-admin-token 2>/dev/null); \
                   curl -f -s --max-time 5 \
                   -H "Authorization: Bearer $TOKEN" \
                   http://localhost:3000/__cache/stats' > /dev/null 2>&1; then
                  echo "Container is healthy."
                  break
                fi
                echo "  Not ready yet... ($ATTEMPT/$MAX_ATTEMPTS)"
                sleep 5
              done
              if [ "$ATTEMPT" -ge "$MAX_ATTEMPTS" ]; then
                echo "Error: container did not become healthy."
                exit 1
              fi

          - name: Export static site
            run: |
              docker exec docs-container /scripts/export.sh
              docker cp docs-container:/tmp/fern-static-export.tar.gz ./export.tar.gz

          - name: Extract static files
            run: |
              mkdir -p ./site
              tar -xzf export.tar.gz -C ./site

          - name: Upload to S3
            uses: jakejarvis/s3-sync-action@v0.5.1
            with:
              args: --delete
            env:
              SOURCE_DIR: ./site
              AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }}
              AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
              AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
              AWS_REGION: ${{ secrets.AWS_REGION }}
              DEST_DIR: pr-${{ github.event.pull_request.number }}

          - name: Comment preview URL on PR
            if: github.event_name == 'pull_request'
            uses: thollander/actions-comment-pull-request@v3
            with:
              message: |
                Preview: http://${{ secrets.AWS_S3_BUCKET }}.s3-website.${{ secrets.AWS_REGION }}.amazonaws.com/pr-${{ github.event.pull_request.number }}
              pr-number: ${{ github.event.pull_request.number }}

          - name: Stop container
            if: always()
            run: docker rm -f docs-container
    ```
  </Accordion>
</AccordionGroup>