How to add a custom domain to an AppSync API

Domain setup for a user-friendly GraphQL endpoint

Author's image
Tamás Sallai
5 mins

Custom domain with AppSync

By default, AppSync creates a domain at https://<api id>.appsync-api.<region>.amazonaws.com/graphql. This is good if the API endpoint is an "implementation detail", such as when it's only used by a webapp or a mobile app and users don't see this value.

But when users need to interact with the API directly, it's a best practice to use a domain you own for two reasons.

The first one is branding. Users see a nice URL with your name instead of a long generated one.

The second is lock-in: if you own the domain, you can point it to wherever you wish, such as a different API, also in a different AWS account, or you can even launch an Apollo GraphQL server in your basement and point the endpoint there. Also, if you accidentally delete the API, you can recreate it and users won't need to change their configs.

Up until recently, AppSync didn't support custom domains. Now it's possible to configure it, only in a very unintuitive way. In this article, we'll look into what you need to have an AppSync API on a custom domain and how to set it up.

We'll do several steps:

  • set up the domain
  • request an ACM certificate
  • create an AppSync custom domain
  • associate the domain with the API
  • setup DNS

Domain setup

The first thing you'll need is a domain. In this article, I'll use a Route53 Hosted Zone with a subdomain:

For this to work, I added NS records to point to the Hosted Zone:

Using Route53 to manage the domain is the easiest as it's well integrated with other AWS services. On the other hand if you want to use a different provider, you can set up everything by hand and that should work also.

ACM certificate

AppSync requires an ACM certificate in the us-east-1 (N. Virginia) region:

To validate ownership, add a CNAME record to the Hosted Zone:

With this setup, the certificate will be issued in a few seconds and is ready to use with AppSync.

AppSync custom domain

Next, go to the AppSync console and create a custom domain there:

This allocates a domain for AppSync that we'll need to redirect traffic:

You see cloudfront in its name, and that is not a coincidence: under the hood, AppSync creates a CloudFront distribution and points that to the AppSync endpoint.

This detail brings the usual problems of CloudFront: it comes with a domain name only and no IP addresses, which is problematic on the DNS level. For browsers to find the server for a domain, they need the A/AAAA records. CNAME records are sort-of pointers that forwards the query to another hostname, which works great with CloudFront but it's not supported on the apex (example.com) only on subdomains (api.example.com). Some services, such as Cloudflare and Route53 support a feature called "CNAME flattening" that allows using CNAMEs on the apex, but not all. This can be a problem, depending on your DNS setup.

Association

With the custom domain setup, associate the API with the domain:

It takes a while, but when it's finished the AppSync API is available on the CloudFront domain.

DNS records

Then the last step is to add a record to the domain that tells clients where they can find the API endpoint. If you use a subdomain then you can use a CNAME record, but Route53 also supports an ALIAS for A/AAAA records:

With this, the API is available on the custom domain and ready to handle requests:

curl \
	-XPOST \
	-H "Content-Type:application/graphql" \
	-H "x-api-key:da2-thpd3va3uzh7dmlxl2pawf7yfu" \
	-d '{ "query": "query { test }" }' \
	https://test.appsynctest.cloudns.cl/graphql

Realtime endpoint

Setting up a custom domain also change the realtime endpoint. By default, it is on a different host: wss://<api id>.appsync-realtime-api.<region>.amazonaws.com/graphql. With a custom domain, it is moved under the primary hostname: wss://<custom domain>/graphql/realtime.

The Amplify client library automatically handles this with some magic, but if you use something else you'll need to point to the right place.

Custom CloudFront distribution

When I saw that AppSync custom domains are just CloudFront distributions, my first thought was that I could configure that distribution myself. That would allow me greater control over the paths on the custom domain, such as configuring:

  • /graphql => AppSync
  • / => S3 bucket

This would make the frontend configuration easier, as the GraphQL endpoint is relative to the frontend. With AppSync custom domains, this is not possible.

I spent some time experimenting with it, and it doesn't seem to be supported. The problem is how real-time data is implemented. It requires the host and that can't be a custom CloudFront distribution, only an AppSync-provided host (either the default endpoint or a custom domain). Theoretically, it should be possible to define a different host for the authorization but then it's hard to configure for the client libraries. So, at this moment, there is no easy way to do it.

May 24, 2022
In this article