Architecture help - How can I architect a web app with a custom subdomain and it's own configuration for each customer?

-1

I would like to deploy a multi tenant web application say webapp.com and I would like each customer to have their own subdomain like app.customer1.webapp.com, api.customer1.webapp.com, app.customer2.webapp.com, api.customer2.webapp.com, etc. This was each customer has their own API and Web App URL. I would like all web app urls to go to the same instance of the application but load a different configuration for each customer - each customer has their own cognito userpool. Similarly for API but I would need to authenticate based on Bearer Token and Domain used. For the backend I think I will have a dynamodb table to hold the details of each customer.

The web app is NextJS app so I think I will use a fargate cluster for both the web app and api (I want to avoid API Gateway and lambda). I will also use CDK for all infrastructure so I might also use it to bootstrap each customer using a stack that consists of Route53 configs and other resources like userpool that is unique to each customer. What is the easiest way to achieve this (preferably with CDK) ?

1 Answer
0

If I were doing this, I would take the easiest approach which would be to have a r53 CNAME pointing to an application load balancer:

// ...
 const tenantName = new cdk.CfnParameter(this, "TenantName", {
      type: "String"
    })
    const webAlb = new elb.ApplicationLoadBalancer(this, 'alb', { 
      ...
    })
    const apiAlb = new elb.ApplicationLoadBalancer(this, 'alb', { 
      ...
    })
    const zone = new r53.HostedZone(this, 'zone', { 
      zoneName: 'example.com' 
    })
    new r53.CnameRecord(this, 'webcname', {
      domainName: webAlb.loadBalancerDnsName, 
      zone: zone, 
      recordName: `${tenantName.valueAsString}.example.com`
    })
    new r53.CnameRecord(this, 'apicname', {
      domainName: apiAlb.loadBalancerDnsName, 
      zone: zone, 
      recordName: `api.${tenantName.valueAsString}.example.com`
    })
// ...

then you can also have a Cognito user pool per tenant per the documentation here.

Alternatively, and slightly more complicated would be to use CloudFront to provide CDN capability with R53 in front, also with CNAME entries. With this, you can also provide tenant-specific behavior rules in CloudFront to provide custom branding per tenant for example.

// ...
 const tenantName = new cdk.CfnParameter(this, "TenantName", {
      type: "String"
    })
    
    const webAlb = new elb.ApplicationLoadBalancer(this, 'alb', { 
      ...
    })
    const apiAlb = new elb.ApplicationLoadBalancer(this, 'alb', { 
      ...
    })

    const distro = new cf.Distribution(this, 'distro', {
      defaultBehavior: {origin: new cfo.LoadBalancerV2Origin(webAlb)},
      ...
    })
    const zone = new r53.HostedZone(this, 'zone', { 
      zoneName: 'example.com' 
    })
    new r53.CnameRecord(this, 'webcname', {
      domainName: distro.distributionDomainName, 
      zone: zone, 
      recordName: `${tenantName.valueAsString}.example.com`
    })
    new r53.CnameRecord(this, 'apicname', {
      domainName: apiAlb.loadBalancerDnsName, 
      zone: zone, 
      recordName: `api.${tenantName.valueAsString}.example.com`
    })
// ...

You can read the details of the CDK apis I used here:

https://docs.aws.amazon.com/cdk/api/v1/docs/aws-cloudfront-origins-readme.html https://docs.aws.amazon.com/cdk/api/v1/docs/aws-cloudfront-origins-readme.html https://docs.aws.amazon.com/cdk/api/v1/docs/aws-route53-readme.html

AWS
answered 2 years ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions