RRSet of type CNAME with DNS name foo.com. is not permitted at apex in zone bar.com - amazon-web-services

I own foo.com and bar.com. I am managing both in Route53. foo.com hosts my site, and I'd like to direct traffic from bar.com to foo.com. I tried to set up a CNAME record for bar.com pointing to foo.com, but I got the error message:
RRSet of type CNAME with DNS name foo.com. is not permitted at apex in zone bar.com.
Why doesn't this work, and what can I do instead?

As per RFC1912 section 2.4:
A CNAME record is not allowed to coexist with any other data. In
other words, if suzy.podunk.xx is an alias for sue.podunk.xx, you
can't also have an MX record for suzy.podunk.edu, or an A record, or
even a TXT record. Especially do not try to combine CNAMEs and NS
records like this!:
podunk.xx. IN NS ns1
IN NS ns2
IN CNAME mary
mary IN A
The RFC makes perfect sense as the nameserver wouldn't know whether it needs to follow the CNAME or answer with the actual record the CNAME overlaps with. bar.com is a zone therefore it implicitly has an SOA record for the bar.com name. You can't have both a SOA record and a CNAME with the same name.
However, given that SOA records are generally used only for zone maintenance, these situations where you want to provide a CNAME at the zone's apex are quite common. Even though the RFC prohibits it, many engineers would like a behaviour such as: "follow the CNAME unless the query explicitly asks for the SOA record". That's why Route 53 provides alias records. These are a Route 53 specific feature which offer the exact functionality you require. Have a look at http://docs.aws.amazon.com/Route53/latest/DeveloperGuide/CreatingAliasRRSets.html

Create an S3 Bucket called bar.com. (The name must be the same as the domain you want to redirect from in order for this to work!)
In the bar.com S3 Bucket go to Properties > Static Website Hosting, select Redirect all requests to another host name and enter foo.com in the text box.
Back in Route 53, in your Hosted Zone for bar.com, click Create Record Set. Select A - IPv4 address for type. Click Yes for Alias. Click the text box for Alias Target. bar.com should be listed under -- S3 Website Endpoints --. Save the record. Wait a few minutes and you should have a redirect setup to redirect requests from bar.com to foo.com.
You can use this same method to redirect a naked domain to a subdomain (like www). I use this in cases where www.foo.com has to be a CNAME so I redirect from foo.com to www.foo.com with this same method. If foo.com is an A record, you can use this technique to redirect from www.foo.com to foo.com.
NOTE: this method will forward with the full path. i.e. http://bar.com/test will forward to http://foo.com/test.

On Route53, You need to create an A record NOT a CNAME record, and create an alias under that.
From #ewalshe's comment on Alexandru Cucu's answer,
if you came here trying to setup API Gateway with a custom domain name and have a Cloudfront distribution url.

Jonathan answer is correct. If you still confuse with his answer please take a look of this example.

tldr; You have to pass in an FQDN as the ResourceRecordSet name.
I had this same problem using this statement c# snip:
private static void RegisterHostWithDns(IAmazonRoute53 ec2,SynoviaImage image)
{
var changeBatch = new ChangeBatch();
var rRs = new ResourceRecordSet(image.Name, RRType.CNAME) {TTL=60,ResourceRecords = new List<ResourceRecord>() { new ResourceRecord(image.PublicDns)} };
var change = new Change(ChangeAction.UPSERT, rRs);
changeBatch.Changes.Add(change);
var request = new ChangeResourceRecordSetsRequest(ConfigurationManager.AppSettings["DnsZoneId"], changeBatch);
var response = ec2.ChangeResourceRecordSets(request);
Console.WriteLine("Updated CNAME For {0} setting {1}",image.Name,image.PublicDns);
}
In this case image.Name == "Listener"
Once I changed it to:
private static void RegisterHostWithDns(IAmazonRoute53 ec2,SynoviaImage image)
{
var changeBatch = new ChangeBatch();
var rRs = new ResourceRecordSet(string.Format("{0}.{1}",image.Name, "testing.foo.bar.com"), RRType.CNAME) {TTL=60,ResourceRecords = new List<ResourceRecord>() { new ResourceRecord(image.PublicDns)} };
var change = new Change(ChangeAction.UPSERT, rRs);
changeBatch.Changes.Add(change);
var request = new ChangeResourceRecordSetsRequest(ConfigurationManager.AppSettings["DnsZoneId"], changeBatch);
var response = ec2.ChangeResourceRecordSets(request);
Console.WriteLine("Updated CNAME For {0} setting {1}",image.Name,image.PublicDns);
}
now the value being passed in is: "Listener.fully.qualified.com"
It works now.

Please note that this error can happen if you forgot to enter something in the 'Record Name' field.
That is, it may expect www, and if you forgot that, you'll see the error, even if everything else is correct.
It's a small chance, but if you forgot to enter www in the 'Record Name' field, go and do that, and everything should work.

You should use the DNAME instead of a CNAME.
A CNAME record is only able to redirect the label to another label.
When you talk about redirecting domain names instead of labels, you should use DNAME
$ORIGIN bar.com
IN DNAME foo.com
This also means that every A, NS and any more records should be deleted. This have to be configured in the foo.com domain.

Related

Allowing users to point their domain names to my service

I am giving my services to my users via client.example.com and there are pages like
client.mysite.com/blog
client.mysite.com/blog/content/
client.mysite.com/docs/
etc.
I want to allow users to allow their domains to point to this subdomain.
so they can choose between any of the 1 option below :
client.com -> client.example.com
sub.client.com -> client.example.com
client.com/sub/ -> client.example.com
and pages should work automatically like
client.com/blog -> client.example.com/blog
sub.client.com/blog -> client.example.com/blog
client.com/sub/blog -> client.example.com/blog
Also, I use Elastic Beanstalk in Amazon to deploy my React application with nginx (Docker image ). Before I start I want to know if this is possible.I also don't want to give fixed IP address to my clients, just in case if I lose that IP. How are the big players like blogger.com, wordpress.com etc doing it?
As far as I researched I know cname is possible to allow clients subdomains and we need IP address for named domain. nowhere it mentioned about the folder. And for SSL, I can use LetsEncrypt.
I am OK with anything like CloudFlare / Route53 method.
Cloudflare for SaaS is designed for this use case. You would just go to Cloudflare Dashboard > You Domain (example.com) -> SSL -> Custom Hostnames. Add a fallback hostname to which you client will link to, e.g. ssl.example.com.
Then client then would need to add his or her custom hostname in your app, then link and verify his custom domain by adding a CNAME (pointing to ssl.example.com) and TXT record via his own DNS provider. The verification and issuing a new SSL would take a few minutes, completely handled by Cloudflare and from there on, your clients may access your service via custom hostname (e.g. client.com, sub.client.com, client.com/blog etc.)
If you need to manipulate the HTTP response as it goes through the customer's hostname, it's also possible to route these request through a CLoudflare Worker script (linked to */* — all hostnames/URLs).
Here is an example, of how to create a custom hostname programmatically:
import * as Cloudlfare from "cloudflare-client";
// Initialize custom hostnames client for Cloudlfare
const customHostnames = Cloudflare.customHostnames({
zoneId: process.env.CLOUDFLARE_ZONE_ID,
accessToken: process.env.CLOUDFLARE_API_TOKEN,
});
// Add the client's custom hostname record to Cloudflare
const record = await customHostnames.create(
hostname: "www.client.com",
ssl: {
method: "txt",
type: "dv",
settings: {
min_tls_version: "1.0",
},
}
);
// Fetch the status of the custom hostname
const status = await customHostnames.get(record.id);
// => { id: "xxx", status: "pending", ... } including TXT records
Pricing
CF for SaaS is free for 100 hostnames and $0.10/hostname/mo after (source).
Path-based URL forwarding
If you need to forward HTTP traffic to different endpoints, e.g. www.client.com/* (customer domain) to web.example.com (SaaS endpoint); www.client.com/blog/* to blog.example.com, etc.
You can achieve that by creating a Cloudfalre Worker script with a route handling */* requests (all customer hostnames, and all URL paths), that would look similar to this:
export default {
fetch(req, env, ctx) {
const url = new URL(req.url);
const { pathname, search } = url;
if (url.pathname === "/blog" || url.pathname.startsWith("/blog/")) {
return fetch(`https://blog.example.com${pathname}${search}`, req);
}
return fetch(`https://web.example.com${pathname}${search}`;
}
}
References
https://developers.cloudflare.com/cloudflare-for-saas/
https://github.com/kriasoft/cloudflare-client
https://github.com/kriasoft/cloudflare-starter-kit
The simplest approach to this, which I’ve implemented at scale (10,000+ clients), is to:
DNS
Have your clients create a CNAME record to either a specific client.example.com or general clients.example.com. This applies to both root (set the ALIAS record instead) and subdomains—an IP address is not required, nor recommended as it does not scale.
Create a database entry that registers/links that explicitly links their domain/subdomain to their account.
Have logic in the backend controller will that associates the hostname in the request to a specific client (security measure) to serve relevant content.
The above fulfills the first two use cases—it allows the client to link a root domain or subdomain to your service.
To achieve the third use case, you could allow the client to specify an arbitrary root path for your service to run within. If the client chooses this, you also need to handle redirects to other services that they have on their domain. This is a lot of responsibility for your app, however.
You could just leverage their registrar, most registrars have the ability to do path redirects—this is the simplest approach that requires the least amount of responsibility/maintenance on your end.
I also recommend having an option for redirecting all entry points (ie: root domain, subdomain, root domain+path, subdomain+path) to a primary entry point (ie: root domain + path), for SEO purposes.
Note: You may also use a service, such as wwwizer, that redirects to the www specified if the ALIAS option on the root domain of your client isn't available.
SSL
I recommend using Let's Encrypt's ACMEv2 API to enable SSL for any domain that is setup on your service. There are libraries available that you should be able.
What is worth mentioning is the challenge — which can occur via DNS or HTTP. When the library you decide on makes a request for a new certificate Let's Encrypt will respond by making a request to ensure that you control the domain (by checking DNS record for a predetermined unique hash) or that you control the server it points to (by checking HTTP path for a predetermined unique hash). What that means is that you need to ensure that your client either includes a hash in their DNS that you specify or you expose a route that adheres to the ACME v2 challenge response protocol (handled by the library you choose).
Here is an example library that you could use if the service you are building is based on python, which supports all features mentioned above and also includes a cli: https://github.com/komuw/sewer .
References
https://help.ns1.com/hc/en-us/articles/360017511293-What-is-the-difference-between-CNAME-and-ALIAS-records-
https://letsencrypt.org/docs/client-options/
https://datatracker.ietf.org/doc/html/rfc8555
http://wwwizer.com
I think what you are asking is how to have the client have their own domain, which they own, have a subdomain which points to your website, with a matching certificate somehow. But just from a security standpoint there is no safe way to do this IMO. Here are the ways off the top of my head you can do this:
You Manage DNS of Subdomain
Your customer could create a NS record to a public Route53 distribution which you own. Then that subdomain would effectively be yours, and you can create DNS records in their subdomain, and certificates in ACM which you can use in a Cloudfront Distribution. You can have multiple FQDN in the one certificate so you won't have to have multiple distributions. You will need to add the domains to the aliases in your distribution as well.
Client Manages own DNS but you tell them what to do
I'm not sure this works as I haven't tried it, but in the DNS validation of a ACM certificate you can see the records you need to create, you would tell the client the CNAME record which they need to create for AWS to issue a certificate for the given domain i.e. sub.client.com, and they would also need to create CNAMEs to point to your website. This way the client still manages their own DNS.
Import Certificate
You could get your client to create a cert for you can then you could import it. They would also need to create the CNAME records to point to your website. And again they would need to create a CNAME to point to your site. Probably least secure, and certs will require manual rotation.
Cloudfront
Your client can use your website as an origin in their own Cloudfront Distribution, bit hacky but would work. I don't think this scales with growing customers.
Summary
IMO I don't like any of those solutions, they are all messy, most likely non-compliant with security standards, and hard to automate if at all. Not to say there aren't situations where you might do this. I would suggest you create subdomains for your own domain, or otherwise consider yourself a hosting company and then you would own/manage your client's domains on their behalf then this easier. But IMO it does not make sense to own a domain, and then give out control to it, or transfer certificates. You'll run into trouble with customers who need to hold certain certifications, or need you to hold those, such as SOC2 for example.

Route 53 site doesn't work unless www is present

I have migrated my domains from another provider to Route53.
Everything is working OK except when I try to navigate to my website without the www's. I get a DNS error. I'm sure it's something elementary I've missed (Extra alias, cname entry etc.)
For clarity's sake - www.domain.com works and domain.com does not.
It sounds like you're missing an A record for the route.

Route53 WWW Subdomain Not Working

I've looked around trying to fix my website App Opps (appopps.com) to have a www subdomain. I've looked around on Stackoverflow but could not find anything to help me. I tried setting up a redirecting Alias Record Set pointing from www.appopps.com to appopps.com but that hasn't worked.
Error Message:
Record Set setup
Redirect setup
I'm sure I'm missing something super simple here and sorry for the basic question in advance!
EDIT
The www should use the same alias as the primary .com record (presumably your load balancer)
First of all, there's no such thing as a redirecting alias record.
With DNS records you can only achieve a behaviour that both www and apex domain will point to the same location. Any redirection from www to non-www (or vice-versa) is going to happen on a server of some kind. You don't have to provision that server though.
You could for example set a redirect on an S3 bucket (and also distribute it as a CloudFront distribution) to redirect to the desirable domain. Then you'd use the url of the bucket (or distribution) as the target for your Route53 record.
As always with DNS, you have to keep in mind that any changes made to your configuration may take some time to propagate (several hours).

How to avoid .s3-website-us-east-1.amazonaws.com/ in the URL?

I'm using static site generator cactusformac.com and I just hit deploy and I was hoping the url would be ONLY beccashayne.com but instead it is http://beccashayne.com.s3-website-us-east-1.amazonaws.com/.
How do I get rid of the .s3-website-us-east-1.amazonaws.com/ and have just beccashayne.com? Or do I need to manually upload all of the content to an FTP thing like cyberduck?
Any advice for a super not advanced developer is helpful I have no idea what I'm doing and all of the docs in AWS are really heavy.
Use Route53 and register your domain beccashyne.com then in the Route53 then the following step:
DNS management click on your Hosted zones, click on your domain name
Click on Create Record Set
In the "Create Record Set" leave your Name blank; Type A - IPv4 address; Alias = Yes; Alias Target: select your S3 Endpoint should be something like "s3-website-us-east-1.amazonaws.com" and that's it!

How can I set the CNAME record on network solutions for my heroku app?

I bought a domain name on network solutions. I have a working app at blooming-summer-8571.herokuapp.com. I want my domain name on network solutions to point to this app. So in the CNAME records. It has a box for alias, ttl, and a drop down menu for # (none) or www . Then there is another option you can check (instead of the drop down menu) to fill out an other host name.
So which is the alias? Should I check other host name and put in the heroku app's url? This is all done under my DNS settings for the domain I purchased so I assume that I don't have to fill it out anywhere? The online resources I have found are rather unhelpful.
I just went through the same thing.
Log in to Network Solutions (Select manage my domains when you log in)
Click "Manage" on the domain you want to point to Heroku
Click "Edit Advanced DNS Records"
Click "Edit A Records" and clear the IP addresses for "www" and "* (All Others)". Put 205.178.189.129 in for "# (None)" then click continue
Click "Edit CName Records"
put "www" in for the Alias. And "YOURAPP.herokuapp.com" in for the "Other Host" field. Make sure the radio button for "Other Host" is selected. Then click continue.
IF you get an error claiming you already have an A record for www then log out of Network Solutions, log back in, and try again.
This will point www.YOURDOMAIN.com to YOURAPP.herokuapp.com
To make sure it worked (give it some time before checking) open up a terminal window and type :
host www.YOURDOMAIN.com
It should respond with something like ..
www.YOURDOMAIN.com is an alias for YOURAPP.herokuapp.com.
Resources:
https://devcenter.heroku.com/articles/custom-domains#domain-precedence
http://www.networksolutions.com/support/how-to-forward-your-network-solutions-domain-name-to-a-free-blog-service/
Just discovered that this page is extremely helpful for this:
http://www.networksolutions.com/support/how-to-forward-your-network-solutions-domain-name-to-a-free-blog-service/
Basically you just need to delete all your A records, and point the # one to the IP 205.178.189.129. Then, as long as you have a valid CNAME record for 'www' (in the case of Heroku, it'd point to your app's heroku URL), Network Solutions will correctly forward all traffic to your www CNAME.
A CNAME (Canonical Name) record is only for domains that you can control and points the canonical name to the correct domain name. What you need to do is point your domain to your Heroku app by following the steps in the following: https://devcenter.heroku.com/articles/custom-domains
The article does state to use CNAME to point to blooming-summer-8571.herokuapp.com (cedar server)