1

I have an Angular app hosted in AWS S3. The look and feel of my application is based on the client query string.

  • www.example.com?client=test1
  • www.example.com?client=test2

Now what I am trying to do is create a new Route53 record test2.example.com and make it point to my Angular app and inject the query string, so test2.example.com resolve to the same as www.example.com?client=test2.

josephdotca
  • 378
  • 1
  • 4
  • 18

2 Answers2

1

I have a Python app that I do something similar with and use API Gateway with Custom Domains to achieve the desired result. In our case the display/design CSS and JS assets are rather complex and located in various domain and folder paths. Also the html is rendered server side. I might need a little more detail on your use case to perhaps provide a more tailored solution.

Since Angular is all client side I'm thinking you could point Route53 to the same S3/Cloudfront endpoint for all your subdomains and have the Angular app detect the subdomain into a variable or return the subdomain value from a function. Then use that value in the folder paths for your "theme" assets. You could store all theme assets to a separate S3 bucket used just for this purpose.

So something like this to get the subdomain value:

getSubdomain() {
  const domain = window.location.hostname;
  if (domain.indexOf('.') < 0 || 
    domain.split('.')[0] === 'example' || domain.split('.')[0] === 'lvh' || domain.split('.')[0] === 'www') {
    this.subdomain = '';
  } else {
    this.subdomain = domain.split('.')[0];
  }
  console.log('subdomain', this.subdomain);

  return this.subdomain;
}

Taken and modified from How to handle tenant subdomains in Angular 2 (router 3)

Use the subdomain value with something like this:

 loadScripts() {
    const dynamicScripts = [
     'https://my-s3-asset-bucket-url/'+getSubdomain()+'/js/test1.js',
     'https://my-s3-asset-bucket-url/'+getSubdomain()+'/js/test1-more-stuff.js'
    ];
    for (let i = 0; i < dynamicScripts.length; i++) {
      const node = document.createElement('script');
      node.src = dynamicScripts[i];
      node.type = 'text/javascript';
      node.async = false;
      node.charset = 'utf-8';
      document.getElementsByTagName('head')[0].appendChild(node);
    }
  }

 loadCSS() {
    const dynamicLinks = [
     'https://my-s3-asset-bucket-url/'+getSubdomain()+'/css/test1.css',
     'https://my-s3-asset-bucket-url/'+getSubdomain()+'/css/test1-more-stuff.css'
    ];
    for (let i = 0; i < dynamicLinks.length; i++) {
      const node = document.createElement('link');
      node.href = dynamicLinks[i];
      node.type = 'text/css';
      node.rel ='stylesheet';
      document.getElementsByTagName('head')[0].appendChild(node);
    }
  }

Then in your constructor:

constructor() {
    this.loadScripts();
    this.loadCSS();
}

Taken and modified from How to load external scripts dynamically in Angular?

You could also change the my-s3-asset-bucket-url above to a Cloudfront distribution url.

Aaron
  • 1,093
  • 8
  • 13
1

You won't be able to "inject" query strings during DNS resolution. Instead, you need some kind of redirection mechanism. Some ideas:

  1. As the colleague Aaron replied, one idea is to get the subdomain in the front-end (window.location.hostname) and use it to dynamically fetch JS/CSS files from another source. Alternatively, in case you can't organize your assets as "themes" or in case this isn't your use-case, you may simply perform a JS redirect after you get the subdomain, e.g. for test1 subdomain:

    window.location.replace("http://www.example.com?client=test1");
    
  2. Redirect might be performed by your back-end/server code as well, in case you can't change/customize your front-end. AWS has this interesting blog page that uses a simple S3 bucket as redirector, which is a good alternative in case you can't change your back-end. Please note that, in case you're using HTTPS for the testX.example.com domain, some additional steps involving CloudFront might be required: https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/tutorial-redirecting-dns-queries.html

Here's how it works:

  1. A viewer, such as a web browser, submits a request for a domain such as example.com.

  2. Amazon Route 53 routes the request for example.com to an Amazon CloudFront distribution.

  3. Amazon CloudFront forwards the request to an Amazon S3 bucket that you specified as the origin for the distribution. The bucket doesn't contain your content; instead, when you created the bucket, you configured it to redirect requests to another domain name.

  4. Amazon S3 uses HTTPS to return an HTTP 301/302 status code to CloudFront along with the name of the domain that you want to redirect traffic to, such as example.net.

  5. CloudFront returns the redirect to the viewer.

  6. Because the response from S3 uses HTTPS, CloudFront uses HTTPS to return the response to the viewer. AWS Certificate Manager (ACM) provides the SSL/TLS certificate that encrypts communication between CloudFront and the viewer.

  7. The viewer submits a request for example.net.

  8. The DNS service for example.net routes the request to the applicable resource, such as another S3 bucket or an EC2 instance running a web server.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Fabio Manzano
  • 2,847
  • 1
  • 11
  • 23