Zappa icon indicating copy to clipboard operation
Zappa copied to clipboard

Got `example.com` certified and working. Now how to make `www.example.com` work as well?

Open sscarduzio opened this issue 7 years ago • 22 comments

Problem

As of title, I have no problem with my website running on my naked domain example.com. But now need to get www.example.com working: i.e. redirecting to the naked domain.

Resolution Attempts

At this stage I'm using Route 53 and trying to add www as a CNAME, my alias list is empty. I also tried adding www.example.com -> example.com as a non-alias CNAME, but it does not work.

sscarduzio avatar Dec 05 '16 06:12 sscarduzio

Howdy. There's not a way to do this natively with Zappa. There's a couple of different things you could do:

1.) Use a standard CNAME (not an ALIAS record) to point to example.com for the www.example.com entry.

2.) Create a bucket in S3 that's named www.example.com and use the static website hosting section of the properties to redirect all traffic to example.com. Then in Route 53, create an ALIAS record for www.example.com pointing to the S3 bucket.

Hope this helps.

chromakey avatar Dec 05 '16 14:12 chromakey

how would that work? Shouldn't I need a certificate also for www.example.com?

sscarduzio avatar Dec 05 '16 16:12 sscarduzio

Here's where it can get tricky. Let me outline the different scenarios.

1.) You do option 1 (CNAME to example.com). This will just point to your API Gateway endpoint and try to render the page as www.example.com which is not a valid endpoint yet. To remedy this, you can add an additional profile to your zappa_settings.json, deploy, and certify it separately. This becomes a pain because now you're managing two deployments for the same thing. If you application is not big, you automate your deployments, and/or you have an application level redirect to the preferred URL, this is not a big deal.

2.) You do option 2 (S3 bucket redirect). This will force all traffic going to www.example.com to go to example.com instead where you have a valid endpoint. Here are the cases where it works as you would expect and doesn't work as expected:

Scenario 1 - http://www.example.com -> https://example.com: OK! Scenario 2 - https://www.example.com -> https://example.com: FAILS!

S3 doesn't do direct HTTPS forwarding which is a common complaint, but there's architectural reasons for that. The only way to get seamless coverage for both scenarios is to do Option 1 with an application redirect to the URL you want to be standard or set up your own reverse proxy and own SSL certificates to do the redirection correctly.

If someone else has some thoughts, I'd appreciate them since this is an issue I deal with regularly (we opt for option 2 since manually typing https://example.com is so exceedingly rare that we can live with the consequences).

chromakey avatar Dec 05 '16 16:12 chromakey

This is something I'd certainly like to address as well!

I am of the opinion that a domain should exist at either the apex or the www., preferring the Apex, and that one should resolve to the other. If there are both, then they should be separate Lambda functions.

HTTPS S3 forwarding not working sucks! A hack there could be to use an HTML page to perform the redirect but I don't know how spiderbots will like that.

Miserlou avatar Dec 05 '16 20:12 Miserlou

Can we have Zappa adding two entries (and two certificates) into the "custom domain name" feature of API gateway? This way the redirect would be optional, and managed at the application level.

sscarduzio avatar Dec 05 '16 23:12 sscarduzio

Yeah, I think that should be doable. It seems like you can point to the same function twice now.

Miserlou avatar Dec 05 '16 23:12 Miserlou

@Miserlou amazing 👍 Where about in the roadmap would you put this?

sscarduzio avatar Dec 06 '16 04:12 sscarduzio

Whenever you submit the PR :)

Miserlou avatar Dec 06 '16 04:12 Miserlou

@Miserlou, I'd love to. But I'm not great at python or have time to become better, so I attempted creating a separate Zappa project for the www (containing a simple redirect to the non-www).

Epic fail:

Calling certify for environment dev..
Certifying domain www.readonlyrest.com..
Setting DNS challenge..
Waiting for DNS to propagate..
Deleting DNS challenge..
An error occurred (InvalidChangeBatch) when calling the ChangeResourceRecordSets operation: RRSet of type CNAME with DNS name www.readonlyrest.com. is not permitted as it conflicts with other records with the same DNS name in zone readonlyrest.com.
Failed to generate or install certificate! :(

The issue is that - of course - I have already the zone "readonlyrest.com".

So I think this is a broader issue: it's apparently impossible to have two websites under the same domain and the same AWS account, say: this.domain.com and that.domain.com.

How to handle this? New issue?

sscarduzio avatar Jan 26 '17 08:01 sscarduzio

I think it should be fairly easy to support multiple domains. I do this in production for my sites. I just have multiple domains setup to point to the same API Gateway at the same path/stage. This allows me to run www.example.com and example.com at the same time. Each domain uses their own certificate_arn (though i suppose one could use a single wildcard cert as well).

I would imagine the settings file could reflect this, something like this:

    domains:
      - name: example.com
        certificate_arn: us-east-1-arn
      - name: www.example.com
        certificate: ...
        certificate_key: ...
        certificate_chain:  ...
         
      # Example for lets encrypt
      - name: example.com
        lets_encrypt_key: womp

Would be happy to take a stab at it.

bxm156 avatar Oct 13 '17 19:10 bxm156

Yep, that's the solution I'd imagine as well. Want to submit a PR, BMX? :D :D :D #

Miserlou avatar Oct 13 '17 19:10 Miserlou

Alas, this should be easy. However AWS's API Gateway API limits itself to 2 Create Domain API requests per min. :(

It can still be done, if a user tries to add too many domains, the cli will create what it can and then fail. The user can than run certify a second time (after a few minutes) to cert the next domain.

Maybe another option would be to instead ask the user to use the domain name they want to certify in the command line, like: zappa certify dev example.com. This would allow the user to choose which domain in the list to certify, and the user will just have run the command multiple times (once for each domain) with a few minutes in-between, so that the API limit isn't an issue.

Thoughts?

It might look something like this:

> zappa certify dev
Due to AWS APIGateway limitations, please run certify for each domain.
> zappa certify dev example.com
> sleep 60
> zappa certify dev www.example.com

bxm156 avatar Oct 16 '17 05:10 bxm156

Making some decent progress on this. I have manually tested my change with the cert_arn and Lets Encrpyt.

Todo:

  • Manual test manual cert files
  • Cleanup
  • Update tests

bxm156 avatar Oct 20 '17 20:10 bxm156

I also discovered that we are not updating Route53 DNS routes in the Let's Encrypt stuff. I fixed it in my branch.

bxm156 avatar Oct 22 '17 19:10 bxm156

My branch should fix #762 ,#934, #1141, which are all duplicates.

bxm156 avatar Oct 26 '17 02:10 bxm156

Is there a way to get zappa to set up a LE certificate for a static files domain connected to an S3 bucket too?

jgroszko avatar Oct 29 '17 16:10 jgroszko

@jgroszko I don't believe, so, LE functionality right now is tied to the API Gateway's custom domain. The functionality just uses LE and generate a certificate body and key, and then uploads it to Lambda, true it could be extended to support s3 resources, but I think that might go out of the scope of lambda. AWS Resource management might be better served by something like Terraform.

bxm156 avatar Oct 29 '17 22:10 bxm156

Hi, I have a WWW redirect working using a combination of CloudFront and S3. This successfully does a www.domain.com -> domain.com redirect as well as HTTP -> HTTPS. So http://www.domain.com becomes https://domain.com.

Route 53 (WWW entry) points to a dedicated CloudFront distribution with an S3 WWW redirect bucket (of the type mentioned above), and the CloudFront distribution settings have a "Redirect HTTP to HTTPS" viewer protocol policy.

I'll try and write up a blog post with every detail in the future.

isaac-jordan avatar May 24 '18 06:05 isaac-jordan

Hi there, you can simply navigate to Amazon API Gateway > Custom Domain Names and click Create Custom Domain Name.

Select HTTP and enter your domain name, www.[domain name]... Select TLS 1.0 and Edge optimized. Then select the certificate for your exisiting domain and click save.

Click update base path mappings, you will need to enter in the path which is most likely /, and the destination. If you get an error about your domain name including www does not exist on the certificate, navigate to Amazon Certificate Manager and create a new certificate for the www domain.

Once your certificate has been issued, go back and repeat the steps. Select this newly created certificate. Your site should be live at https://www.domain.... Hope this helps!

JimiPedros avatar Jul 18 '19 07:07 JimiPedros

Hi, I have a WWW redirect working using a combination of CloudFront and S3. This successfully does a www.domain.com -> domain.com redirect as well as HTTP -> HTTPS. So http://www.domain.com becomes https://domain.com.

Route 53 (WWW entry) points to a dedicated CloudFront distribution with an S3 WWW redirect bucket (of the type mentioned above), and the CloudFront distribution settings have a "Redirect HTTP to HTTPS" viewer protocol policy.

I'll try and write up a blog post with every detail in the future.

Hi sheepzez. Any chance that you already published a blog post on this topic?

cubocicloide avatar Dec 27 '19 20:12 cubocicloide

not sure if anyone is still looking for solution for this problem, but this is how I solved it:

  • request for a domain cert and additional domain name *.domainname.ext
  • Zappa certify for domainname.ext
  • manually add custom domain on api gateway for the *.domainname.ext and (rest and edge optimized, select new *.domainname.ext cert) map it to the same api gateway and stage
  • on route 53 create alias A record and point to cloudfront url from the new api custom domain

that should do it

nabazm avatar Jan 15 '20 19:01 nabazm

not sure if anyone is still looking for solution for this problem, but this is how I solved it:

  • request for a domain cert and additional domain name *.domainname.ext
  • Zappa certify for domainname.ext
  • manually add custom domain on api gateway for the *.domainname.ext and (rest and edge optimized, select new *.domainname.ext cert) map it to the same api gateway and stage
  • on route 53 create alias A record and point to cloudfront url from the new api custom domain

that should do it

Thank you @nabazm. For anyone who might be interested, this also works fine the other way round (using the www. in Zappa settings and following the above steps for domainname.ext). In my case if someone visits domainname.ext I just redirect them to www.domainname.ext in the code of my app.

Alex-Mackie avatar Dec 13 '20 15:12 Alex-Mackie