Hosting a website and email on one domain with AWS
I registered ubertech.info with GoDaddy and wanted two things on it: a fast HTTPS website and real email. By the end of the evening the site was served from S3 through CloudFront, DNS lived in Route 53, and Microsoft 365 handled mail. Here's the path, including the places I tripped.
The setup
- Route 53 hosts DNS. GoDaddy stays the registrar, with its nameservers pointed at the four Route 53 servers.
- ACM issues a free certificate for the domain and a wildcard, validated through a DNS record.
- S3 holds the pages in a private bucket.
- CloudFront serves them over HTTPS and reads the bucket through Origin Access Control.
- Microsoft 365 handles email, with MX, SPF and autodiscover records in Route 53.
Things that caught me out
The certificate must be in us-east-1. CloudFront only accepts ACM certificates from that region, wherever the rest of your stack lives. Also leave the new export option disabled: exportable public certificates are billed, while the standard ones used with CloudFront are free.
@ is not a record name in Route 53. GoDaddy uses @ for the root domain. In Route 53 you leave the name blank; typing @ creates a subdomain literally called @.ubertech.info, and Microsoft's verification never finds it.
A private bucket returns AccessDenied until two things are right. The bucket policy has to allow the CloudFront service principal for your distribution, and the distribution needs a default root object of index.html. Without the second, a request for / asks S3 for an empty key and gets refused.
"Doesn't exist" gets cached too. I looked up the domain before creating its records, and my resolver remembered the negative answer. Querying the authoritative server directly proved the records were fine:
dig A ubertech.info @ns-201.awsdns-25.com +short
One TXT record per name. The Microsoft verification value and the SPF policy both live at the root, so they go in one record as two quoted lines rather than two records.
A missing space breaks SPF. include:secureserver.net-all is read as a domain that doesn't exist. With the space before -all, Gmail stopped showing the unverified-sender question mark on my mail.
Publishing changes
Updates are two commands: sync the files, then tell CloudFront to fetch fresh copies.
aws s3 sync ./site s3://ubertech-info-website/ --delete
aws cloudfront create-invalidation --distribution-id EH6M7KZVG3RRQ --paths "/*"
Next
Everything here was built by hand in the console. The next step is importing it into Terraform so the whole setup is reviewable code, which will be the next post.
All posts