同じフロントエンドにポイントを複数のサブドメイン


This article was first published on bahr.dev.
Signup for the mailing list and get new articles straight to your inbox!


2019年に私はスポーツクラブのためのオンラインTicketshopを構築した.そのコアでは、ショップは、支払いを処理し、電子メールを介してPDFを送信するwebappだった.カスタマイズに来たとき、物事はトリッキーになった:各クラブは、別の名前、別の写真、そして時々彼らが顧客に依頼したい別の質問があった.各クラブのカスタマイズされた経験を与えるために、私たちは自分のサブドメインを使用してそれぞれを提供します.結局、6つの異なるフロントエンド展開、複数の分岐とコードベースが分岐し始めました.最近では、あるドメインの下のすべてのリクエストを同じフロントエンドにルーティングするためにDNSレコードを使用できることを知りました.ありがとう
この記事では、DNSレコードと静的なウェブサイトを作成することによって、複数のサブドメインを同じフロントエンド展開に向ける方法を説明しますAWS Cloud Development Kit (CDK) . これは、1つのフロントエンドの展開をしながら、お客様のそれぞれのカスタマイズされた経験を与えることができます.

ショートカット:コードとしてインフラストラクチャを必要としない場合は*.yourdomain.com 既存のCloudFrontディストリビューションには、同じ結果が得られます.
マジックは、“ワイルドカードルーティング”の章にあります.Check out the full source code on GitHub .

必要条件


この記事のソリューションを展開するには、AWSアカウントとAWS CDK . また、Amazonルート53に登録されていないドメインを持っているのも良いですが、他のプロバイダと使用ドメインを使用する方法を学びます.
この記事はcdk version 1.60.0を使用します.何か新しいバージョンで何かが壊れたら教えてください!
実行してcdkのアカウントをブートストラップしてくださいcdk bootstrap . 我々は、これを必要とするDnsValidatedCertificate .
自由選択:Understanding how DNS and especially nameservers work は、潜在的なルーティングの問題をトラブルシューティングすると多くの場合に役立ちます.

解決策


私たちを顧客靴に入れて解決策を見つけましょう.私は顧客として行きたいbear.picture.bahr.dev or forest.picture.bahr.dev または他の形式のアドレス*.picture.bahr.dev そして、初めに単語のための絵を見てください.開発者として、私は複雑さの最小量を可能にしたい.複数フロントエンド展開が複雑さを増す
リクエストフローは次のようになります.

上のドメインの変更だけを見ることができますが、他に何もありません.解決の中核で、我々は特定の目標へのどんなサブドメインのためにもルートトラフィックを聞かせたワイルドカードarecordです.ウェブサイトは、URLを取ることができますサブドメインを抽出し、右の画像を求める.次の章では、各部分を詳しく見ていきます.

ホストゾーンを作成する


AWSでDNSレコードを登録するにはcreate a Hosted Zone in Route 53 . Each Hosted Zone costs $0.50 per month .
Hostゾーンは、ルート53で管理されているドメインを持っていて、まだ何のためにも使用しない場合に設定するのが最も簡単です.
他の目的(例えばあなたのブログ)のためにあなたのルート53ドメインを使用しているならば、あるいは、そのドメインがルート53より異なるプロバイダによって管理されるならば、あなたはあなたがあなたのホストしている地帯をセットアップすることができる方法を見ます.
誰があなたのドメイン(例えばルート53またはGodaddy)を管理するかによって、そして、あなたがすでに他のウェブサイトのためにapexドメインを使うならば、あなたは少し解決を微調整しなければなりません.私の例では、私はすでにapexドメインを使いますbahr.dev 私のブログのために、Godaddyによって管理されるドメインを持ってください.以下の章で正しいレコードを指定する方法を見ます.
警告:ホストゾーンを削除する前に、ルートホストゾーンまたはサードパーティのプロバイダのすべての関連レコードを削除してください.危険なCNNameとNS記録はallow an attacker to serve content in your name .

1.1 .ルート53で管理されるフレッシュドメイン


これは最も簡単な経路です.我々が必要とするすべては、我々のドメインのためのホストされた地帯です.
import { HostedZone } from '@aws-cdk/aws-route53';

...
const domain = `bahr.dev`;

const hostedZone = new HostedZone(this, "HostedZone", {
    zoneName: domain
});
経路53は現在、そのドメインのDNSレコードを提供することができます.

1.2 .ルート53で管理される中古ドメイン


これは、すでにあなたの頂点ドメインのためのホストされたゾーンを持っていると仮定します.頂点ドメインはあなたのトップレベルドメインです.bahr.dev or google.com .
私たちは、サブドメインに関する情報が別のホストされたゾーンにあるDNSサーバに伝えなければなりませんZoneDelegationRecord .
import { HostedZone } from '@aws-cdk/aws-route53';

...

// bahr.dev is already in use, so we'll start 
// at the subdomain picture.bahr.dev
const apexDomain = 'bahr.dev';
const domain = `picture.${apexDomain}`;

// as above we create a hostedzone for the subdomain
const hostedZone = new HostedZone(this, "HostedZone", {
    zoneName: domain
});
// add a ZoneDelegationRecord so that requests for *.picture.bahr.dev 
// and picture.bahr.dev are handled by our newly created HostedZone
const nameServers: string[] = hostedZone.hostedZoneNameServers!;    
const rootZone = HostedZone.fromLookup(this, 'Zone', { 
  domainName: apexDomain 
});
new ZoneDelegationRecord(this, "Delegation", {
    recordName: domain,
    nameServers,
    zone: rootZone,
    ttl: Duration.minutes(1)
});
DNSキャッシュがより速く期限切れになるので、ライブ(TTL)に対する短い時間はより速い試行とエラーを考慮に入れます.あなたが生産の準備をするように、これを増やす必要があります.
私たちは後でARECOREを加えますpicture.bahr.dev and *.picture.bahr.dev 同じクラウドフロントディストリビューションに移動します.bahr.dev は影響を受けない.

1.3 .ドメインはAWS以外のプロバイダによって管理されます


また、ルート53のホストゾーンを作成しますが、今回はホストゾーンのネームサーバをDNSプロバイダに登録するためのマニュアル作業が必要です.開始するには、まずAWSコンソールを介してホストゾーンを作成します.

これは、ネームサーバ(NS)と権威の開始(SOA)のために2つのエントリーをもつホストされた地帯を与えます.私たちは権威あるネームサーバをコピーし、我々のDNSプロバイダにAWSのホストゾーンに対する要求を委任するよう指示します.

SOAレコードから正式なネームサーバをコピーし、DNSプロバイダに行ってネームサーバーレコードを作成しますName and Value :
Type: NS
Name: picture
Value: ns-1332.awsdns-38.org
特定の値を使用するpicture サブドメインで起動したい場合*.picture.bahr.dev または使用@ あなたのようなapexドメインを使用する場合*.bahr.dev .

次に、手動で作成したホストゾーンをインポートするには、次のCDKスニペットを使用します.
import { HostedZone } from '@aws-cdk/aws-route53';

...

const domain = `picture.bahr.dev`;

const hostedZone = HostedZone.fromLookup(this, 'HostedZone', { 
  domainName: domain 
});

証明書


DNSルーティングが設定されたので、証明書をリクエストして検証することができます.私たちはHTTPSを使用して当社のウェブサイトに役立つこの証明書が必要です.
CDKを使えば、一つのコマンドで証明書を作成し、検証できます.
import { DnsValidatedCertificate, ValidationMethod } from "@aws-cdk/aws-certificatemanager";

...

const certificate = new DnsValidatedCertificate(this, "Certificate", {
    region: 'us-east-1',
    hostedZone: hostedZone,
    domainName: this.domain,
    subjectAlternativeNames: [`*.${this.domain}`],
    validationDomains: {
        [this.domain]: this.domain,
        [`*.${this.domain}`]: this.domain
    },
    validationMethod: ValidationMethod.DNS,
});
ここでたくさんのことがあるので、それを壊しましょう.
まず地域を設定しますus-east-1 , だってCloudFront requires certificates to be in us-east-1 .
次に、CDKの構造を使用しますDnsValidatedCertificate ルート53にcnameレコードを登録するための証明書要求とラムダ関数を生成する.このレコードは、実際にドメインを所有していることを検証するために使用されます.
パラメータhostedZone 認証されたゾーンを指定します.これは以前作成したホストゾーンです.domainName and subjectAlternativeNames 証明書が有効なドメインを指定します.残りのパラメータは検証プロセスを構成します.

フロントエンド展開


適所に証明書で、我々はS 3とCloudfrontを通して一つのページ・アプリケーション(SPA)配備をつくることができます.NPMパッケージを使用していますcdk-spa-deploy S 3バケットを設定し、CloudFrontディストリビューションを接続するために必要なコードの量を短縮します.
import { SPADeploy } from 'cdk-spa-deploy';

...

const deployment = new SPADeploy(this, 'spaDeployment')
    .createSiteWithCloudfront({
        indexDoc: 'index.html', 
        websiteFolder: './website', 
        certificateARN: certificate.certificateArn, 
        cfAliases: [this.domain, `*.${this.domain}`]
    });
The index.html HTMLファイルとして<p>Hello world!</p> とフォルダに格納する必要があります./website .
ブラウザでは、サブドメインを得るためにJavaScriptを使用することができます.下のコードの行はURLを分割しますice.picture.bahr.dev 配列に['ice', 'picture', 'bahr', 'dev'] そうすると、最初の要素'ice' .
const subdomain = window.location.host.split('.')[0];
その情報を使用して、ウェブサイトは、あなたの顧客のための適切な資産を得るためにCMSに連絡することができます.

ワイルドカードルーティング


そして最後にワイルドカードルーティングのための時間です.以下のCDKコードでは、*.picture.bahr.dev and picture.bahr.dev を設定します.
import { CloudFrontTarget } from "@aws-cdk/aws-route53-targets";
import { ARecord, RecordTarget } from '@aws-cdk/aws-route53';

...

const cloudfrontTarget = RecordTarget.fromAlias(new CloudFrontTarget(deployment.distribution));

new ARecord(this, "ARecord", {
    zone: hostedZone,
    recordName: `${this.domain}`,
    target: cloudfrontTarget
});

new ARecord(this, "WildCardARecord", {
    zone: hostedZone,
    recordName: `*.${this.domain}`,
    target: cloudfrontTarget
});
すべてのDNSレコードが伝播したら、設定をテストできます.全体のソリューションを展開することが時々10分から15分かかることに注意してください.

自分で試してみて


あなたが既存のCDKコードベースにコピーすることができる完全なCDKコードは、ここにあります.
あなたにstart with checking out the source code ドメインを調整し、必要なゾーンにホストします.加えるZoneDelegationRecord あなたがそれを必要とするならば.必ず実行するcdk bootstrap あなたがまだそれをしていないならば.
import * as cdk from '@aws-cdk/core';
import { SPADeploy } from 'cdk-spa-deploy';
import { DnsValidatedCertificate, ValidationMethod } from "@aws-cdk/aws-certificatemanager";
import { CloudFrontTarget } from "@aws-cdk/aws-route53-targets";
import { HostedZone, ARecord, RecordTarget } from '@aws-cdk/aws-route53';

export class WildcardSubdomainsStack extends cdk.Stack {

  private readonly domain: string;

  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const domain = `picture.bahr.dev`;

    const hostedZone = new HostedZone(this, "HostedZone", {
      zoneName: domain
    });

    const certificate = new DnsValidatedCertificate(this, "Certificate", {
      hostedZone,
      domainName: this.domain,
      subjectAlternativeNames: [`*.${this.domain}`],
      validationDomains: {
        [this.domain]: this.domain,
        [`*.${this.domain}`]: this.domain
      },
      validationMethod: ValidationMethod.DNS
    });

    const deployment = new SPADeploy(this, 'spaDeployment')
        .createSiteWithCloudfront({
            indexDoc: 'index.html', 
            websiteFolder: './website', 
            certificateARN: certificate.certificateArn, 
            cfAliases: [this.domain, `*.${this.domain}`]
        });

    const cloudfrontTarget = RecordTarget
        .fromAlias(new CloudFrontTarget(deployment.distribution));

    new ARecord(this, "ARecord", {
      zone: hostedZone,
      recordName: `${this.domain}`,
      target: cloudfrontTarget
    });

    new ARecord(this, "WildCardARecord", {
      zone: hostedZone,
      recordName: `*.${this.domain}`,
      target: cloudfrontTarget
    });
  }
}
今すぐ実行AWS_PROFILE=myProfile npm run deploy ソリューションを配備するには.置換myProfile あなたがAWSのために使っているどんなプロフィールででも.Here's more about AWS profiles .
展開は、10~15分の間のどこかにかかるかもしれません.コーヒーをつかむとCDKはそのことを行うことができます.問題が発生した場合は、以下のトラブルシューティングのセクションを参照してください.
展開が完了すると、指定したドメインのサブドメインを参照することができます.bear.picture.bahr.dev ドメイン名picture.bahr.dev ) そして、あなたのウェブサイトを見てください.

トラブルシューティング


The DNS routing doesn't work.


DNSレコードのライブ(TTL)への高い時間は、変更をテストすることを難しくすることができます.TTLをできるだけ低くしてください.
あなたのドメインが経路53によって管理されないならば、あなたのDNSプロバイダーからのDNSルーティングが正しく設定されることを確認してください.
あなたがapexドメインを何か他のもののために使うならば、AをセットアップしてくださいZoneDelegationRecord それはあなたの新しいドメインのためのトラフィックをあなたの新しいホストされたゾーンに向けます.

The deployment failed to clean up.


展開が失敗するステップに応じて、すべてのリソースをクリーンアップすることはできません.これは、cnameレコードによって、DnsValidatedCertificate 作成.ホストゾーンに移動し、cnameレコードを削除し、実行してスタックを削除しますcdk destroy またはAWSコンソールのCloudformationサービスを通して削除します.

Failed to create resource. Cannot read property 'Name' of undefined


スタックをクリーンアップし、削除して再配備します.私は、そのエラーがどこから来るかについて、わかりません、しかし、再試行は私のためにそれを固定しました.

The certificate validation times out.


必要なcnameレコードがDNSサーバに表示されるように、正しいアプローチを使用していることを確認してください.あなたのドメインを使用した場合は、右側を設定する前にZoneDelegationRecord . これは少しトリッキーなので、自由に感じることができます.

次の手順


Check out the full source code それを試してみてください!あなたが貢献したいならばcdk patterns おそらく良い考えです.

更なる読書

  • What is DNS?
  • Host a static website with CloudFront and S3
  • AWS profiles
  • cdk-spa-deploy on GitHub