I'm using Zappa to deploy a Flask app. It works (site). Obviously I'd like to not have it stuck behind the aws domain and put it on my personal domain.
Everything I'm searching keeps talking about hosting a Lambda site with S3 and API Gateway. Is there no way to just deploy my little app to a custom domain?
Edit
Following #mislav's answer, I was able to get my google domain working with AWS. But when I try to finish by running zappa certify I get an error about the domain existing:
raise error_class(parsed_response, operation_name)
botocore.errorfactory.BadRequestException: An error occurred
(BadRequestException) when calling the CreateDomainName operation: The
domain name you provided already exists.
My zappa_settings.json is
{
"dev": {
"app_function": "ping_app.app",
"aws_region": "us-west-1",
"profile_name": "Breuds",
"project_name": "breuds",
"runtime": "python3.6",
"s3_bucket": "zappa-ping-redshift",
"slim_handler": true,
"certificate_arn": "arn:aws:acm:us-east-1:010174774769:certificate/3a92c204-5788-42fc-bc65-74aaae8c1b3f",
"domain": "breuds.com"
}
}
I am beginning to think I am doing something convoluted on my domain side. I'm using Google Domains (since I have a custom domain for my email, just using that), but that seems to cause a headache trying to get AWS to talk to it.
It’s actually explained in zappa’s readme.
Deploying to a Domain With AWS Certificate Manager
Amazon provides their own free alternative to Let's Encrypt called AWS Certificate Manager (ACM). To use this service with Zappa:
Verify your domain in the AWS Certificate Manager console.
In the console, select the N. Virginia (us-east-1) region and request a certificate for your domain or subdomain (sub.yourdomain.tld), or request a wildcard domain (*.yourdomain.tld).
Copy the entire ARN of that certificate and place it in the Zappa setting certificate_arn.
Set your desired domain in the domain setting.
Call $ zappa certify to create and associate the API Gateway distribution using that certificate.
There are also instructions to use your existing certificate etc.
Don’t let it fool you, the title of the section makes it sound like it’s only about certificates, but there are detailed instructions regarding using you own domain.
Edit:
I’m including my own zappa settings for reference.
{
"common": {
"app_function": "app.__hug_wsgi__",
"aws_region": "eu-central-1",
"s3_bucket": "excuse-generator",
"profile_name": "mislavcimpersak",
"remote_env": "s3://excuse-generator/secrets.json",
"certificate_arn": "arn:aws:acm:us-east-1:500819636056:certificate/3edb9c1c-12c5-4601-89a9-dc42df840fa6"
},
"prod": {
"extends": "common",
"domain": "function.xkcd-excuse.com"
},
"dev": {
"extends": "common",
"debug": true,
"keep_warm": false,
"domain": "function-dev.xkcd-excuse.com"
}
}
Step by step guide for domain bought on namecheap.com and served through cloudflare.com
buy domain on namecheap.com/use existing
register new site on cloudflare.com/use existing
cloudflare will give you (most probably) two nameservers
enter under https://ap.www.namecheap.com/domains/domaincontrolpanel/xkcd-excuse.com/domain DNS - choose "Custom DNS" nameservers given on cloudflare
go to AWS ACM and request a new certificate (certificate must be created in us-east-1 region)
enter if necessary multiple subdomains (foo.example.com & foo-dev.example.com)
make note of ACM ARN given from AWS management console
in zappa_settings.json enter under certificate_arn your ARN
in zappa_settings.json under route53_enabled put false - this is a must
in zappa_settings.json under domain enter domain for each stage ie. foo.example.com and foo-dev.example.com
run zappa certify <stage_name>
it should say: "Created a new domain name with supplied certificate. Please note that it can take up to 40 minutes for this domain to be created and propagated through AWS, but it requires no further work on your part.
Certificate updated!"
go to CloudFlare DNS interface and enter
CNAME: foo - i3jtsjkdeu4wxo.cloudfront.net
CNAME: foo-dev - d2jtsjkdeu4wxo.cloudfront.net
wait for 40 minutes and check your domain(s), they should serve your Lambda function
You might not need API Gateway. It will depend on site functionality. You can host a static website using S3 with a custom domain. You can include client-side javascript(angular/react etc..) API Gateway is really for handling http requests and passing it on to defined resources(Lambda or others).
If your site will require backend capability then you have few options.
1) Build lambda functions and then use API Gateway(REST API) to interact with these functions.
yourhostname.com -> S3 -> API Gateway(aws hostname) -> lambda
2) Use AWS JS SDK to interact with your lambda functions directly.
yourhostname.com -> S3 -> AWS SDK -> lambda
3) Use API Gateway and then forwarding to Lambda or self hosted web server(flask node) using EC2 instance
yourhostname.com -> API Gateway(aws hostname) -> lambda
yourhostname.com -> self hosted web server
Here is a picture that might make it a bit clearer.
Correct me if I am wrong flask is used for backend development to build microservices. To host it you would use either build lambda functions or host it on your own instance.
https://andrich.blog/2017/02/12/first-steps-with-aws-lambda-zappa-flask-and-python/
Let me know if this helps.
Related
I just deployed a CloudFormation solutions from the AWS Solutions. The solutions included a new CloudFront distribution. My challenge is that I want to add a custom domain mysite.example.com to the dxxxxxx.cloudfront.net distribution. I already created an alias and certificate using Certificate Manager. My question is how do I add a new domain to the existing CloudFront.
I understand that we can import an existing distribution using Distribution.fromDistributionAttributes.
for example
const distribution = cloudfront.Distribution.fromDistributionAttributes(this, 'ImportedDist', {
domainName: 'd111111abcdef8.cloudfront.net',
distributionId: '012345ABCDEF',
});
Let's say I have the alias domain name and certificate ARN ready to use.
const domainName = 'mysite.example.com';
const certificateArn = 'arn:aws:acm:us-east-1: 123456789012:certificate/abcdefgh-1234-5678-9012-abcdefghujkl';
Where do I go from here?
Add your domain and certificate by updating your "AWS solutions" CDK app. CDK apps are designed be modified and redeployed.
The Distribution construct accepts the certificate?:ICertificate and domainNames?: string[] as props to the constructor.
Instances also expose a addBehavior(pathPattern, origin, behaviorOptions?), which seems handy.
If the app is in production, be mindful that updates sometimes result in resource replacement or interruption.
The CloudFormation docs note the update behaviour for each service property. In the happy case you will see Update requires: No interruption. Run the cdk diff command to preview the changes
CloudFormation will make to your resources.
What about cloudfront.Distribution.fromDistributionAttributes? Many CDK classes have static from... methods
to get a reference to an existing AWS resource. These methods are handy (or even necessary) when resources are shared between apps, but should be used only when you cannot modify the original CDK construct.
I'm using AWS CloudFormation to create an IoT Thing, Policy and Certificate. My stack creates successfully, however, I can't access the certificate file that CloudFormation creates.
Looking at the aws docs here the only output you can get from the certificate via CloudFormation is the ARN and the Certificate ID. However, there is no way to retrieve your certificate using the ARN or Certificate ID that I can see.
If you upload your certificate signing request (CSR) via the AWS IoT Console, it displays a download link that you can get your certificate file.
Unfortunately I need to use CloudFormation to create the IoT Certificate. However it looks like you can download the certificate after it's been created. Specifically it states:
Certificates can be retrieved at any time
I have been unsuccessfully scouring the docs and web interface to figure out how I can download my certificate "at any time". I'm relatively new to the whole world of certs and private keys so hopefully I missed something easy.
Does anyone know if it is possible to get your certificate from an IoT Certificate created by CloudFormation?
Certificates created using CloudFormation (Via a CSR) can be retrieved via the following ways
Aws IoT webpage
Just navigate to Security - Certificates, click on ... and select Download.
AWS CLI
As you mention the CLI is also an option
aws iot describe-certificate --certificate-id fcd371fcd371fcd371fcd371fcd371fcd371fcd371fcd371fcd371fcd371fcd3
Will return
{
"certificateDescription": {
"certificateArn": "arn:aws:iot:eu-central-1:xxxxxx",
"status": "ACTIVE",
"certificateId": "fcd371fcd371fcd371fcd371fcd371fcd371fcd371fcd371fcd371fcd371fcd3",
"lastModifiedDate": 1519840881.49,
"certificatePem": "-----BEGIN CERTIFICATE-----\nMIIDsTCCApmg.....VsAzFQ==\n-----END CERTIFICATE-----\n",
"transferData": {},
"ownedBy": "123456789",
"creationDate": 1519840820.888
}
Amazon IoT SDK
Can also be used to retrieve the certificate content (PEM format) as a String based on a certificate ID (that you can output via cloudformation)
import com.amazonaws.services.iot.AWSIot;
import com.amazonaws.services.iot.AWSIotClientBuilder;
import com.amazonaws.services.iot.model.DescribeCertificateRequest;
import com.amazonaws.services.iot.model.DescribeCertificateResult;
DescribeCertificateRequest describeCertificateRequest = new DescribeCertificateRequest();
describeCertificateRequest.setCertificateId("fcd371fcd371fcd371fcd371fcd371fcd371fcd371fcd371fcd371fcd371fcd3");
DescribeCertificateResult describeCertificateResult = awsIot.describeCertificate(describeCertificateRequest);
describeCertificateResult.getCertificateDescription().getCertificatePem();
AFAIK it is not possible to output it as a variable within a cloudformation template.
Ah I found a way using the AWS CLI. But there really needs to be a way to get it via CloudFormation :(
http://docs.aws.amazon.com/cli/latest/reference/iot/describe-certificate.html
I'm using this email AWS SES forwarding script on a registered domain in AWS, along with releavant MX and TXT records. Personal emails im testing this with are also authorised as im in sandbox mode. I've set a rule in SES, pushing emails to an s3 bucket. After i call the aformentioned lambda function to redirect emails to anther gmail account.
var defaultConfig = {
fromEmail: "info#domainInRoute53.co.uk",
subjectPrefix: "",
emailBucket: "s3.xxxxx.xxxxx",
emailKeyPrefix: "emails/",
forwardMapping: {
"info#domainInRoute53.co.uk": [
"personal#gmail.com",
"personal#hotmail.co.uk"
]
}
}; ..etc..
It writes to the s3 bucket but i cant seem to get it to forward to the personal email addresses.
I've tried numerous edits on the inline and managed policies in the IAM roles for the lamdba function to select, as suggested in the link I'm following above on step 2. Any ideas why this is failing?
I have a fresh AWS account with no certificates connected to it.
This is what it looks like when I try to request a certificate for a domain through the Amazon Certificate Manager:
Trying the aws acm request-certificate command from the command line gives me:
An error occurred (LimitExceededException) when calling the
RequestCertificate operation: Cannot request more certificates in this account.
Contact Customer Service for details
The documentation mention limits, but I have no certificates so I shouldn't have exceeded it.
Any ideas what the problem might be?
One thing that is not on most answers here. When you create an account and/or haven't used it much (the representative from aws' answer was unclear as to what constitutes a proper usage of the account in the beginning) your limit is actually 0.
So your choices here are request a limit increase or wait until it reaches some sort of adequate usage as required by AWS.
This was solved by AWS support, not sure what the actual issue was.
If certs don't show on "aws acm list-certificates", that's because of the regions thing, most likely. This is the result with my default region:
hannah#Hannah-PC:~$ aws acm list-certificates
{
"CertificateSummaryList": []
}
hannah#Hannah-PC:~$ grep region .aws/config
region = ap-southeast-2
This is the result when I change the region to us-east-1:
hannah#Hannah-PC:~$ aws acm list-certificates --region=us-east-1
{
"CertificateSummaryList": [
{
"CertificateArn": "arn:aws:acm:us-east-1:31234512345:certificate/XXXXXX-XXXX-XXXX-XXXX-XXXXXX",
"DomainName": "whatever.net"
}
]
}
SSL certs have to in us-east-1 specifically for CloudFront to use them.
I followed the instruction on S3 doc to host a static website there. Everything works with the domain name provided by S3. I can access "examplebucket.s3-website-us-east-1.amazonaws.com"
However, when I forward my own custom domain name, the domain name provider added a dot at the very end of my domain, then it's like I'm accessing "examplebucket.s3-website-us-east-1.amazonaws.com.", this won't work because Amazon thinks you're accessing a different address. And then give me 404 error.
Is there any workaround for this? or any place I should set up in S3?
I know this is too late for the original question but there may be more people with the same issues (me last week).
I was having the same issue while trying to create a route in route53 with CloudFormation. I was trying to redirect my domain www.example.com to example-bucket.s3-website-eu-west-1.amazonaws.com.
It turns out you cannot redirect to an arbitrary bucket. The bucket name must be the same as the domain you're trying to alias. So if you want to redirect www.example.com, your bucket name must be www.example.com and the URL must be www.example.com.s3-website-eu-west-1.amazonaws.com.
Moreover cloudformation has a weird syntax. Cloudformation doesn't need the name of the bucket (it already knows it). It only needs the endpoint.
So instead of using something like
"AliasTarget": {
"DNSName" : "example-bucket.s3-website-eu-west-1.amazonaws.com",
"HostedZoneId" : "<zoneID>"
},
you need
"AliasTarget": {
"DNSName" : "s3-website-eu-west-1.amazonaws.com",
"HostedZoneId" : "<zoneID>"
},
And route53 where to redirect because the name of the route must be the same as the name of the bucket.
Related question https://stackoverflow.com/a/5048129/54256