# 使用 AWS、CloudFront 和 Route 53 配置子目录

{% hint style="info" %}
本指南介绍如何使用 AWS CloudFront 和 Lambda\@Edge 设置子目录。这是 AWS 用户的一种实现方式。如果你的 AWS 架构不同（例如使用运行 NGINX 的 EC2 实例的负载均衡器），你可能需要以不同方式配置反向代理。联系 [支持](https://gitbook.com/docs/help-center/further-help/how-do-i-contact-support) 以获取其他配置的指导。
{% endhint %}

{% stepper %}
{% step %}
**配置你的 GitBook 站点**

在你的 GitBook 组织中，点击侧边栏中的 docs 站点名称，然后点击 **管理站点** 或打开 **设置** 选项卡。打开 **域名和重定向** 部分，在“子目录”下点击 **设置子目录**.

输入你希望托管文档的网站 URL。然后指定用于访问文档的子目录，例如 `example.com/docs`，然后点击 **配置**.

在 **附加配置**，你现在会看到一个代理 URL。下一步配置 Lambda 函数时会用到它。请将其复制到剪贴板。
{% endstep %}

{% step %}
**创建你的 Lambda\@Edge 函数**

登录 AWS 控制台并导航到 **Lambda**.

点击 **创建函数** 按钮。

选择 **从头开始编写**，然后：

* 给你的函数起一个描述性名称，例如 `gitbook-subpath-proxy。`
* 选择 **Node.js** 作为运行时（使用可用的最新版本）。
* 架构和其他设置保持默认值。

点击 **创建函数**.
{% endstep %}

{% step %}
**更新 Lambda 函数代码**

在 Lambda 函数编辑器中，将默认代码替换为以下内容：

{% code lineNumbers="true" %}

```javascript
export const handler = async (event) => {
	const request = event.Records[0].cf.request;
	
	// 如果你的子目录不是 /docs，请更新
	const subdirectory = '/docs';
	
	// 在下面更新为你的代理 URL
	const target = new URL('<从 GitBook 获取的代理 URL>');

	// 重写：/docs* -> proxy.gitbook.site
	if (request.uri.startsWith(subdirectory)) {
		request.uri = target.pathname + request.uri.substring(subdirectory.length);

		// 如果存在，移除尾部斜杠
		if (request.uri.endsWith('/')) {
			request.uri = request.uri.slice(0, -1);
		}

		request.origin = {
			custom: {
				domainName: target.host,
				port: 443,
				protocol: 'https',
				path: '',
				sslProtocols: ['TLSv1.2'],
				readTimeout: 30,
				keepaliveTimeout: 5,
				customHeaders: {},
			},
		};

		request.headers['host'] = [{ key: 'host', value: target.host }];
		request.headers['x-forwarded-host'] = [{ key: 'x-forwarded-host', value: target.host }];
	}
    
	return request;
};
```

{% endcode %}

{% hint style="warning" %}
请务必更新 `target` 第 8 行中的值，替换为你在第一步从 GitBook 获取的代理 URL。它看起来会像 `https://proxy.gitbook.site/sites/site_XXXX`
{% endhint %}

{% hint style="warning" %}
也请务必更新 `subdirectory` 第 5 行中的值，如果你使用的子目录路径不是 `/docs`.
{% endhint %}

点击 **部署** 以保存更改。
{% endstep %}

{% step %}
**为 Lambda\@Edge 配置 Lambda 权限**

在将 Lambda 函数与 CloudFront 一起使用之前，你需要配置执行角色以允许 Lambda\@Edge 代入它。

1. 在你的 Lambda 函数中，点击 **配置** 选项卡
2. 点击 **权限** 在左侧边栏中
3. 在 **执行角色**，点击角色名称以在 IAM 中打开它
4. 点击 **信任关系** 选项卡
5. 点击 **编辑信任策略**
6. 将信任策略替换为以下内容：

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": [
                    "edgelambda.amazonaws.com",
                    "lambda.amazonaws.com"
                ]
            },
            "Action": "sts:AssumeRole"
        }
    ]
}
```

点击 **更新策略** 以保存。
{% endstep %}

{% step %}
**发布你的 Lambda 函数**

Lambda\@Edge 需要已发布的版本（不仅仅是 `$LATEST`).

1. 在你的 Lambda 函数中，点击右上角的 **操作** 下拉菜单
2. 选择 **发布新版本**
3. 可选地添加描述，例如“CloudFront 的初始版本”
4. 点击 **发布**
5. **重要：** 复制页面顶部显示的已发布版本的 ARN（它将在末尾包含版本号，例如 `arn:aws:lambda:us-east-1:123456789:function:gitbook-subpath-proxy:1`)

{% hint style="warning" %}
Lambda\@Edge 函数必须在 **us-east-1** （美国东部（弗吉尼亚北部））区域中创建。如果你在其他区域创建了函数，则需要在 us-east-1 中重新创建。
{% endhint %}
{% endstep %}

{% step %}
**创建你的 CloudFront 分发**

导航到 **CloudFront** 在 AWS 控制台中并点击 **创建分发**.

配置以下设置。未指定的设置保持默认值。

**指定源站**

| 设置        | 值                          |
| --------- | -------------------------- |
| **源站类型**  | 其他                         |
| **自定义源站** | 你的主网站域名（例如， `example.com`) |

**缓存设置**

| 设置         | 值                         |
| ---------- | ------------------------- |
| **缓存策略**   | CachingDisabled           |
| **源站请求策略** | AllViewerExceptHostHeader |

点击 **接下来，** 选择你偏好的安全防护，然后再次点击 **下一步** 。

点击 **创建分发**.

等待分发部署完成（状态将从“进行中”变为“已启用”）。这可能需要几分钟。
{% endstep %}

{% step %}
**将 Lambda\@Edge 关联到 CloudFront**

一旦你的 CloudFront 分发已部署：

1. 点击你的分发 ID 以打开其设置
2. 转到 **行为** 选项卡
3. 选择默认行为并点击 **编辑**
4. 向下滚动到 **函数关联**
5. 在 **源站请求**，选择 **Lambda\@Edge**
6. 在 **Lambda 函数 ARN** 字段，粘贴你已发布的 Lambda 函数 ARN（来自第 5 步）
7. 检查 **包含正文** 以允许函数在需要时访问请求正文
8. 点击 **保存更改**
   {% endstep %}

{% step %}
**配置域名和 DNS 记录**

1. 在 CloudFront 分发的主页上，点击 **常规** 选项卡，并在 **备用域名**下，点击 **添加域名**
2. 输入你正在配置子目录的域名，例如 `example.com` 并点击 **下一步**
3. 选择你现有的 TLS 证书，或者在需要时创建一个新的，然后点击 **下一步** 再次
   {% endstep %}

{% step %}
**从 CloudFront 配置 Route 53 DNS 记录**

如果你使用 Route 53 进行 DNS，你需要创建或更新 DNS 记录，使其指向你的 CloudFront 分发。

1. 在 CloudFront 分发主页上停留的同时，确保你位于 **常规** 选项卡，然后在你已在 **备用域名中配置的 URL 下面，** 点击 **将域名路由到 CloudFront。**
2. 点击 **自动设置路由** 为你的域创建 A 和 AAAA DNS 记录

{% hint style="info" %}
如果你不使用 Route 53，则需要更新 DNS 提供商的设置，使你的域指向 CloudFront 分发域名。你可以在 CloudFront 分发详情中的“分发域名”下找到它。
{% endhint %}
{% endstep %}

{% step %}
**测试你的配置**

一旦所有更改完成传播（这可能需要 10–15 分钟）：

1. 打开浏览器并访问带有子目录路径的你的域名（例如， `https://example.com/docs`)
2. 你应该会看到你的 GitBook 文档站点！

如果站点没有立即加载，请尝试：

* 再等待几分钟，让 DNS 传播完成
* 清除浏览器缓存或尝试无痕窗口
* 运行 `nslookup yourdomain.com` 在终端中验证 DNS 是否正确解析
* 检查 CloudFront 分发状态是否为“已启用”，而不是“进行中”

{% hint style="success" %}
恭喜！你的 GitBook 文档现在可以通过自定义子目录访问了。
{% endhint %}
{% endstep %}
{% endstepper %}

### 故障排除

**Lambda 函数未触发：**

* 确保你已发布 Lambda 函数的版本（不是使用 `$LATEST`)
* 确认 Lambda 函数位于 us-east-1 区域
* 检查信任策略是否包含 `edgelambda.amazonaws.com`

**DNS 未解析：**

* DNS 更改可能需要一些时间才能传播（最长可达 48 小时，尽管通常会快得多）
* 验证你的 Route 53 记录是否指向正确的 CloudFront 分发
* 检查你是否删除了任何旧的冲突 DNS 记录

**SSL 证书错误：**

* 确保 AWS Certificate Manager 中的 SSL 证书包含你的自定义域名
* 用于 CloudFront 的证书必须在 us-east-1 区域中创建

**子目录无法工作：**

* 验证 `SUBDIRECTORY` 你 Lambda 函数中的值是否与你在 GitBook 中配置的一致
* 检查你 Lambda 函数中的 `target` 是否正确
* 查看 CloudFront 日志，确认请求是否到达了分发


---

# Agent Instructions: 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:

```
GET https://gitbook.com/docs/documentation/zh/docs-site/custom-domain/setting-a-custom-subdirectory/configuring-a-subdirectory-with-aws.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
