

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 設定 OpenSearch UI 應用程式的易記 URL （自助式）
<a name="application-custom-domain"></a>

OpenSearch UI 應用程式具有自動產生的 URLs例如 `https://application-{{name}}-{{id}}.{{Region}}.opensearch.amazonaws.com`。這些 URLs很長且難以記住。您可以設定易記的 URL （例如 `https://prod.example.com`)。此 URL 會重新導向至您的應用程式，因此您可以直接存取儀表板，而無需透過 AWS 管理主控台導覽。

## 運作方式
<a name="application-custom-domain-overview"></a>

此解決方案使用 CloudFront 將請求從易記 URL 重新導向至 OpenSearch UI 應用程式端點。架構包含下列元件：
+ **ACM 憑證** – 為您的易記 URL 提供 HTTPS 加密。
+ **CloudFront KeyValueStore** – 存放子網域名稱和應用程式 URLs之間的映射。
+ **CloudFront 函數** – 讀取 KeyValueStore，並將 302 重新導向傳回正確的應用程式 URL。
+ **CloudFront 分佈** – 使用 TLS 為您的易記 URL 提供服務，並透過 函數路由請求。
+ **Route 53 DNS 記錄** – 將您的易記 URL 指向 CloudFront 分佈。

當您造訪易記的 URL （例如 `https://prod.example.com`) 時，CloudFront 函數會查詢對應的應用程式 URL，並將您的瀏覽器重新導向至該 URL。應用程式會直接處理身分驗證。

## 先決條件
<a name="application-custom-domain-prerequisites"></a>
+ 一或多個 OpenSearch UI 應用程式及其端點 URLs。
+ 您擁有的網域名稱 （例如 `example.com`)。
+ Route 53 中網域的公有託管區域。如果您沒有 ，如需詳細資訊，請參閱 [不使用 Route 53 進行設定 （手動組態）](#application-custom-domain-without-route53)。
+ 存放應用程式 URL 映射檔案的 Amazon S3 儲存貯體。

## 使用 部署 AWS CloudFormation
<a name="application-custom-domain-deploy-cfn"></a>

使用下列程序，使用 CloudFormation 範本部署易記的 URL 重新導向基礎設施。

**為您的 OpenSearch UI 應用程式設定易記的 URL**

1. 建立將您的易記名稱映射至應用程式 URLs JSON 檔案。每個金鑰都會變成子網域 （例如，金鑰`prod`會變成 `https://prod.example.com`)。

   ```
   {
     "data": [
       {"key": "prod", "value": "https://application-prod-abc123.us-west-2.opensearch.amazonaws.com"},
       {"key": "staging", "value": "https://application-staging-def456.us-east-1.opensearch.amazonaws.com"},
       {"key": "analytics", "value": "https://application-analytics-ghi789.eu-west-1.opensearch.amazonaws.com"}
     ]
   }
   ```

   將此檔案儲存為 `opensearch-ui-friendly-url-app-mappings-v1.json`。`v1` 尾碼會將此識別為映射的第一個版本。當您更新映射時，會遞增此版本。

1. 將映射檔案上傳至您帳戶中的 Amazon S3 儲存貯體：

   ```
   aws s3 cp opensearch-ui-friendly-url-app-mappings-v1.json \
     s3://{{your-bucket-name}}/opensearch-ui-friendly-url-app-mappings-v1.json
   ```

1. 新增儲存貯體政策，授予 CloudFront 讀取映射檔案的許可。將 {{your-bucket-name}} 和 {{your-account-id}} 取代為您的值：

   ```
   aws s3api put-bucket-policy \
     --bucket {{your-bucket-name}} \
     --policy '{
       "Version": "2012-10-17",
       "Statement": [{
         "Sid": "AllowCloudFrontKVSImport",
         "Effect": "Allow",
         "Principal": {"Service": "cloudfront.amazonaws.com"},
         "Action": "s3:GetObject",
         "Resource": "arn:aws:s3:::{{your-bucket-name}}/*",
         "Condition": {"StringEquals": {"aws:SourceAccount": "{{your-account-id}}"}}
       }]
     }'
   ```
**注意**  
此儲存貯體政策允許 CloudFront 在建立 KeyValueStore 期間讀取映射檔案。如果沒有它，堆疊部署會失敗，並出現「SourceARN 無法存取」錯誤。

1. 使用下列其中一個選項部署 CloudFormation 堆疊：

   **選項 1：啟動堆疊 （建議）**

   複製下列 URL 並貼到您的瀏覽器，以開啟預先載入範本的 AWS CloudFormation 快速建立頁面。填寫參數，然後選擇**建立堆疊**。

   ```
   https://us-east-1.console.aws.amazon.com/cloudformation/home?region=us-east-1#/stacks/quickcreate?templateURL=https://opensearch-ui-quickstart-sample-cfn-templates.s3.us-west-2.amazonaws.com/opensearch-ui-friendly-url/main.yaml&stackName=opensearch-ui-friendly-url&param_MappingsVersion=v1
   ```

   **選項 2： AWS CLI**

   將預留位置值取代為您自己的值：

   ```
   aws cloudformation create-stack \
     --stack-name opensearch-ui-friendly-url \
     --template-url https://opensearch-ui-quickstart-sample-cfn-templates.s3.us-west-2.amazonaws.com/opensearch-ui-friendly-url/main.yaml \
     --parameters \
       ParameterKey=DomainName,ParameterValue={{your-domain.com}} \
       ParameterKey=HostedZoneId,ParameterValue={{Z0123456789ABCDEFG}} \
       ParameterKey=MappingsBucket,ParameterValue={{your-bucket-name}} \
       ParameterKey=MappingsKey,ParameterValue=opensearch-ui-friendly-url-app-mappings-v1.json \
       ParameterKey=MappingsVersion,ParameterValue=v1 \
     --region us-east-1
   ```

1. 如果您使用 AWS CLI （選項 2)，請在 `us-east-1`區域中部署堆疊。CloudFront 要求 ACM 憑證在 中`us-east-1`。您的 OpenSearch UI 應用程式可以位於 [ OpenSearch UI 的任何支援區域和配額](https://docs.aws.amazon.com/opensearch-service/latest/developerguide/opensearch-ui-endpoints-quotas.html)中。

1. 等待堆疊完成 （約 15 分鐘）。您可以監控進度：

   ```
   aws cloudformation wait stack-create-complete \
     --stack-name opensearch-ui-friendly-url \
     --region us-east-1
   ```

1. 測試重新導向。開啟您的瀏覽器並導覽至 `https://{{prod}}.{{your-domain.com}}`。您應該重新導向至 OpenSearch UI 應用程式。

   您也可以使用 驗證`curl`：

   ```
   curl -I https://{{prod}}.{{your-domain.com}}
   # Expected: HTTP/2 302
   # location: https://application-prod-abc123.us-west-2.opensearch.amazonaws.com
   ```

### CloudFormation 範本來源
<a name="application-custom-domain-template-source"></a>

以下是上述啟動堆疊連結和 CLI 命令所使用的完整 CloudFormation 範本。您也可以直接從 下載`https://opensearch-ui-quickstart-sample-cfn-templates.s3.us-west-2.amazonaws.com/opensearch-ui-friendly-url/main.yaml`。

```
AWSTemplateFormatVersion: '2010-09-09'
Metadata:
  TemplateVersion: '1.0.0'
  LastUpdated: '2026-08-05'
  Author: 'OpenSearch UI Team'
Description: >
  OpenSearch UI Friendly URL - Creates a CloudFront distribution with a CloudFront Function
  that redirects friendly subdomain URLs to OpenSearch Application endpoints.
  Deploy this template in us-east-1 (required for ACM certificates used with CloudFront).

Parameters:
  DomainName:
    Type: String
    Description: "Your domain name (e.g., example.com or subdomain.example.com)"
    AllowedPattern: "^[a-zA-Z0-9][a-zA-Z0-9-]*(\\.[a-zA-Z0-9][a-zA-Z0-9-]*)+$"
  HostedZoneId:
    Type: AWS::Route53::HostedZone::Id
    Description: "Route 53 Hosted Zone ID for your domain"
  MappingsBucket:
    Type: String
    Description: "S3 bucket name containing your app mappings JSON file"
  MappingsKey:
    Type: String
    Description: "S3 key (path) to your app mappings JSON file"
    Default: "opensearch-ui-friendly-url-app-mappings.json"
  MappingsVersion:
    Type: String
    Description: "Version identifier for your mappings (change this when updating mappings, e.g., v1, v2, v3)"
    Default: "v1"
    AllowedPattern: "^[a-zA-Z0-9-]+$"

Resources:
  # 1. Wildcard TLS Certificate (DNS validated via Route 53)
  Certificate:
    Type: AWS::CertificateManager::Certificate
    Properties:
      DomainName: !Sub "*.${DomainName}"
      ValidationMethod: DNS
      DomainValidationOptions:
        - DomainName: !Sub "*.${DomainName}"
          HostedZoneId: !Ref HostedZoneId

  # 2. CloudFront KeyValueStore with S3 import for app mappings
  AppMappingStore:
    Type: AWS::CloudFront::KeyValueStore
    Properties:
      Name: !Sub "${AWS::StackName}-kvs-${MappingsVersion}"
      Comment: !Sub "OpenSearch UI app mappings ${MappingsVersion} for ${DomainName}"
      ImportSource:
        SourceType: S3
        SourceArn: !Sub "arn:aws:s3:::${MappingsBucket}/${MappingsKey}"

  # 3. CloudFront Function (reads KVS, returns 302 redirect)
  RedirectFunction:
    Type: AWS::CloudFront::Function
    Properties:
      Name: !Sub "${AWS::StackName}-fn"
      AutoPublish: true
      FunctionConfig:
        Comment: !Sub "Redirects friendly URLs to OpenSearch Application endpoints (${MappingsVersion})"
        Runtime: cloudfront-js-2.0
        KeyValueStoreAssociations:
          - KeyValueStoreARN: !GetAtt AppMappingStore.Arn
      FunctionCode: !Sub |
        import cf from 'cloudfront';

        const kvsHandle = cf.kvs("${AppMappingStore.Id}");

        async function handler(event) {
          var request = event.request;
          var host = request.headers.host.value;
          
          // Extract subdomain prefix (e.g., "app1" from "app1.example.com")
          var subdomain = host.split('.')[0];
          
          try {
            var targetUrl = await kvsHandle.get(subdomain);
            return {
              statusCode: 302,
              statusDescription: 'Found',
              headers: {
                'location': { value: targetUrl },
                'cache-control': { value: 'no-cache, no-store, must-revalidate' }
              }
            };
          } catch (e) {
            // Key not found - return 404
            return {
              statusCode: 404,
              statusDescription: 'Not Found',
              headers: {
                'content-type': { value: 'text/html' }
              },
              body: {
                encoding: 'text',
                data: '<html><body><h1>Application Not Found</h1><p>No OpenSearch application is mapped to the requested subdomain.</p></body></html>'
              }
            };
          }
        }

  # 4. CloudFront Distribution
  Distribution:
    Type: AWS::CloudFront::Distribution
    DependsOn: Certificate
    Properties:
      DistributionConfig:
        Enabled: true
        Comment: !Sub "OpenSearch UI Friendly URL for ${DomainName}"
        Aliases:
          - !Sub "*.${DomainName}"
        ViewerCertificate:
          AcmCertificateArn: !Ref Certificate
          SslSupportMethod: sni-only
          MinimumProtocolVersion: TLSv1.2_2021
        DefaultCacheBehavior:
          ViewerProtocolPolicy: redirect-to-https
          AllowedMethods:
            - GET
            - HEAD
          CachedMethods:
            - GET
            - HEAD
          CachePolicyId: "4135ea2d-6df8-44a3-9df3-4b5a84be39ad"  # AWS managed CachingDisabled policy
          TargetOriginId: dummy-origin
          FunctionAssociations:
            - EventType: viewer-request
              FunctionARN: !GetAtt RedirectFunction.FunctionMetadata.FunctionARN
        Origins:
          - Id: dummy-origin
            DomainName: "example.com"
            CustomOriginConfig:
              OriginProtocolPolicy: https-only
        HttpVersion: http2and3
        IPV6Enabled: true
        PriceClass: PriceClass_All

  # 5. Wildcard DNS record pointing to CloudFront
  WildcardDnsRecord:
    Type: AWS::Route53::RecordSet
    Properties:
      HostedZoneId: !Ref HostedZoneId
      Name: !Sub "*.${DomainName}"
      Type: A
      AliasTarget:
        HostedZoneId: Z2FDTNDATAQYW2  # CloudFront's fixed hosted zone ID (constant for all distributions)
        DNSName: !GetAtt Distribution.DomainName
        EvaluateTargetHealth: false

Outputs:
  CloudFrontDomain:
    Description: "CloudFront distribution domain name"
    Value: !GetAtt Distribution.DomainName
  CertificateArn:
    Description: "ACM Certificate ARN"
    Value: !Ref Certificate
  KeyValueStoreArn:
    Description: "CloudFront KeyValueStore ARN"
    Value: !GetAtt AppMappingStore.Arn
  ExampleUrl:
    Description: "Example friendly URL"
    Value: !Sub "https://prod.${DomainName}"
  MappingsFileLocation:
    Description: "S3 location of your app mappings file"
    Value: !Sub "s3://${MappingsBucket}/${MappingsKey}"
  CurrentMappingsVersion:
    Description: "Current mappings version deployed"
    Value: !Ref MappingsVersion
  TemplateVersion:
    Description: "Template version and last updated date"
    Value: "1.0.0 (2026-08-05)"
```

### 新增或移除應用程式
<a name="application-custom-domain-add-apps"></a>

若要新增、更新或移除應用程式映射，請建立新的 S3 映射檔案版本，並使用新版本更新堆疊。版本控制方法會將 S3 檔案保留為事實來源，並可讓您隨時轉傳至新的組態或轉返至先前的版本。

1. 編輯映射檔案以新增或移除項目。使用遞增的版本尾碼 （例如 ) 儲存它`opensearch-ui-friendly-url-app-mappings-v2.json`。

1. 將新版本上傳至 S3：

   ```
   aws s3 cp opensearch-ui-friendly-url-app-mappings-v2.json \
     s3://{{your-bucket-name}}/opensearch-ui-friendly-url-app-mappings-v2.json
   ```

1. 使用新的 `MappingsKey`和 更新堆疊`MappingsVersion`：

   **使用主控台：**開啟[CloudFormation 主控台](https://console.aws.amazon.com/cloudformation/)，選取堆疊，選擇**更新**，選取**使用目前範本**，然後使用新值更新 `MappingsKey`和 `MappingsVersion` 參數。

   **使用 AWS CLI：**

   ```
   aws cloudformation update-stack \
     --stack-name opensearch-ui-friendly-url \
     --use-previous-template \
     --parameters \
       ParameterKey=DomainName,UsePreviousValue=true \
       ParameterKey=HostedZoneId,UsePreviousValue=true \
       ParameterKey=MappingsBucket,UsePreviousValue=true \
       ParameterKey=MappingsKey,ParameterValue=opensearch-ui-friendly-url-app-mappings-v2.json \
       ParameterKey=MappingsVersion,ParameterValue=v2 \
     --region us-east-1
   ```

**重要**  
每次更新映射時，您必須變更 `MappingsVersion` 參數。版本會驅動 KeyValueStore 名稱，這會觸發 CloudFormation 以更新的資料取代 KeyValueStore。為了清楚起見，請保持`MappingsKey`檔案名稱 和 `MappingsVersion` 同步 （例如，`...-v2.json`使用 `MappingsVersion=v2`)。

若要復原至先前的版本，請更新指向先前檔案和版本的堆疊。

**使用主控台：**開啟[CloudFormation 主控台](https://console.aws.amazon.com/cloudformation/)，選取堆疊，選擇**更新**，選取**使用目前範本**，然後設定 `MappingsKey` 並`MappingsVersion`返回先前的值 （例如 `v1`)。

**使用 AWS CLI：**

```
aws cloudformation update-stack \
  --stack-name opensearch-ui-friendly-url \
  --use-previous-template \
  --parameters \
    ParameterKey=DomainName,UsePreviousValue=true \
    ParameterKey=HostedZoneId,UsePreviousValue=true \
    ParameterKey=MappingsBucket,UsePreviousValue=true \
    ParameterKey=MappingsKey,ParameterValue=opensearch-ui-friendly-url-app-mappings-v1.json \
    ParameterKey=MappingsVersion,ParameterValue=v1 \
  --region us-east-1
```

此版本控制方法可讓您完全控制視需要轉返或轉返應用程式映射，同時將您的 S3 檔案保留為每個組態版本的最終記錄。

## 不使用 Route 53 進行設定 （手動組態）
<a name="application-custom-domain-without-route53"></a>

如果您的網域是由 Route 53 以外的 DNS 供應商管理，您可以在 AWS 管理主控台中手動設定易記的 URL 重新導向。此方法不會使用 Amazon S3 進行映射，您可以直接在 CloudFront 主控台中管理鍵/值對。

**設定不含 Route 53 的易記 URL 重新導向**

1. 

**在 ACM 中請求憑證**

   1. 在 `us-east-1`區域中開啟位於 https：//[https://console.aws.amazon.com/acm/](https://console.aws.amazon.com/acm/) 的 ACM 主控台。

   1. 選擇**請求憑證**。

   1. 針對**網域名稱**，輸入 `*.{{your-domain.com}}`（萬用字元憑證）。

   1. 針對**驗證方法**，選擇 **DNS 驗證**。

   1. 選擇**請求**。

   1. 在憑證詳細資訊頁面上，記下**網域驗證**下的 CNAME 記錄名稱和值。在您的 DNS 供應商建立此 CNAME 記錄，以驗證網域擁有權。

   1. 等待憑證狀態變更為**已發行** （通常在 DNS 記錄建立後 5 到 30 分鐘）。

1. 

**建立 CloudFront KeyValueStore**

   1. 在 [ https://console.aws.amazon.com/cloudfront/](https://console.aws.amazon.com/cloudfront/) 開啟 CloudFront 主控台。

   1. 在導覽視窗中，選擇**函數**。然後選擇 **KeyValueStores** 標籤。

   1. 選擇**建立 KeyValueStore**。

   1. 輸入名稱 （例如 `opensearch-ui-friendly-url-app-mappings-store`)。

   1. 選擇**建立**。

   1. 建立後，選擇**編輯**以新增鍵/值對。對於每個應用程式，新增金鑰 （子網域名稱，例如 `prod`) 和值 （完整的 OpenSearch UI 應用程式 URL)。

1. 

**建立 CloudFront 函數**

   1. 在 [ https://console.aws.amazon.com/cloudfront/](https://console.aws.amazon.com/cloudfront/) 開啟 CloudFront 主控台。

   1. 在導覽視窗中，選擇**函數**。

   1. 在**函數**索引標籤上，選擇**建立函數**。

   1. 輸入函數的名稱 （例如 `opensearch-ui-friendly-url-redirect-function`)。

   1. 針對**執行期**，選擇 **cloudfront-js-2.0。**

   1. 將函數程式碼取代為下列項目：

      ```
      import cf from 'cloudfront';
      
      const kvsHandle = cf.kvs("{{YOUR_KVS_ID}}");
      
      async function handler(event) {
        var request = event.request;
        var host = request.headers.host.value;
        var subdomain = host.split('.')[0];
      
        try {
          var targetUrl = await kvsHandle.get(subdomain);
          return {
            statusCode: 302,
            statusDescription: 'Found',
            headers: {
              'location': { value: targetUrl },
              'cache-control': { value: 'no-cache, no-store, must-revalidate' }
            }
          };
        } catch (e) {
          return {
            statusCode: 404,
            statusDescription: 'Not Found',
            headers: { 'content-type': { value: 'text/html' } },
            body: {
              encoding: 'text',
              data: '<html><body><h1>Application Not Found</h1><p>No OpenSearch application is mapped to the requested subdomain.</p></body></html>'
            }
          };
        }
      }
      ```

      將 {{YOUR\_KVS\_ID}} 取代為您建立的 KeyValueStore 的 ID （可在 KeyValueStore 詳細資訊頁面上看到）。

   1. 在 **KeyValueStore 關聯**中，關聯您建立的 KeyValueStore。

   1. 選擇**儲存變更**，然後選擇**發佈函數**。

1. 

**建立 CloudFront 分佈**

   1. 在 CloudFront 主控台中，選擇**建立分佈**。

   1. 針對**原始網域**，輸入任何有效的網域 （例如 `example.com`)。永遠不會聯絡原始伺服器，因為函數會在到達回應之前傳回回應。

   1. 在**預設快取行為**下，針對**檢視器通訊協定政策**，選擇將 **HTTP 重新導向至 HTTPS**。

   1. 針對**快取政策**，選擇 **CachingDisabled**。

   1. 在**函數關聯**下，針對**檢視器請求**，選取您的 CloudFront 函數。

   1. 在**設定**下，針對**備用網域名稱 CNAMEs)**，輸入 `*.{{your-domain.com}}`。

   1. 針對**自訂 SSL 憑證**，選取您在 ACM 中建立的憑證。

   1. 選擇 **Create Distribution (建立分佈)**。

   1. 請記下分佈網域名稱 （例如 `d1234abcdef8.cloudfront.net`)。

1. 

**在您的供應商設定 DNS**

   在您的 DNS 供應商，建立`*.{{your-domain.com}}`指向 CloudFront 分佈網域名稱的 CNAME 記錄 （例如 `d1234abcdef8.cloudfront.net`)。
**注意**  
有些 DNS 供應商不支援萬用字元 CNAME 記錄。在這種情況下，請為您要使用的每個子網域建立個別 CNAME 記錄 （例如，`prod.your-domain.com`、`staging.your-domain.com`)。

### 手動新增應用程式映射
<a name="application-custom-domain-manual-add-apps"></a>

若要在初始手動設定之後新增應用程式映射：

1. 在 [ https://console.aws.amazon.com/cloudfront/](https://console.aws.amazon.com/cloudfront/) 開啟 CloudFront 主控台。

1. 在導覽視窗中，選擇**函數**。然後選擇 **KeyValueStores** 標籤。

1. 選擇您的 KeyValueStore 名稱 （例如 `opensearch-ui-friendly-url-app-mappings-store`)。

1. 選擇**編輯**。

1. 選擇**新增配對**。輸入子網域名稱作為索引鍵，並輸入完整的 OpenSearch UI 應用程式 URL 作為值。

1. 選擇**儲存變更**。

儲存後，即可立即使用新的易記 URL。

## 清除
<a name="application-custom-domain-cleanup"></a>

若要移除易記的 URL 重新導向基礎設施，請執行下列命令：

```
aws cloudformation delete-stack \
  --stack-name opensearch-ui-friendly-url \
  --region us-east-1
```

此命令會移除 CloudFront 分佈、函數、KeyValueStore、ACM 憑證和 DNS 記錄。它不會影響您的 OpenSearch UI 應用程式。

## 疑難排解
<a name="application-custom-domain-troubleshooting"></a>

ACM 憑證保留在 `Pending validation`  
確定您網域的 DNS 已正確委派給 Route 53 （或您在 DNS 供應商建立驗證 CNAME)。使用 `dig {{your-domain}} NS`來驗證名稱伺服器。

瀏覽器顯示憑證錯誤  
確認 ACM 憑證以萬用字元 () 的形式涵蓋您的網域`*.your-domain.com`。憑證必須位於 `us-east-1`區域。

找不到 404 應用程式  
您嘗試存取的子網域在 KeyValueStore 中沒有映射。驗證映射檔案中存在的金鑰，並確認您在上次變更後已更新堆疊 （或手動新增配對）。

CloudFront 分佈會顯示超過 15 分鐘`Deploying`的狀態  
CloudFront 分佈最多可能需要 15 分鐘才能全域部署。如果部署需要更長的時間，請檢查 CloudFront 主控台以取得錯誤詳細資訊。

SourceARN 在堆疊建立期間是無法存取的錯誤  
確保 S3 儲存貯體政策授予讀取映射檔案的`cloudfront.amazonaws.com`許可。同時確認部署堆疊的 IAM 角色在儲存貯體上有 `s3:GetObject`、 `s3:HeadObject`和 `s3:GetBucketLocation`許可。