Skip to content

Commit

Permalink
Add optional custom domain name
Browse files Browse the repository at this point in the history
  • Loading branch information
e-mit committed Jun 15, 2024
1 parent 5121eae commit eedbbd0
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 16 deletions.
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,26 @@ Add extra website files with:
Run ```/stack.sh $STACK_NAME delete $WEB_BUCKET_NAME```

This will also delete the S3 bucket contents.


## Optional: Use a Custom Domain Name

### Certificate setup: manual process

1. Sign in to the AWS Certificate Manager console **and set the region to us-east-1**.
2. Choose "Request a certificate".
3. Enter the custom domain name for the API in "Domain name".
4. Choose "Review, request and confirm".
5. In AWS Certificate Manager, copy the CNAME name/values of the pending certificate and paste into the domain provider's system as a new CNAME record. The certificate will remain pending until the DNS updates (up to 48 hours).
6. Copy the certificate ARN for later use.

### Stack creation

1. Run ```source setup.sh``` as usual, but set ```USE_CUSTOM_DOMAIN=true``` and provide the domain name and certificate ARN.
2. An intermediate (cloudfront) URL is created by AWS. Obtain this URL and use it to create a new CNAME record (for a subdomain) or a new ALIAS record (for the root domain) in the domain provider's system.
3. Wait for the DNS to update.

### Important notes

- This process disables the usual API Gateway URL, so the website can only be accessed via the custom domain name.
- The intermediate cloudfront URL **can** be accessed directly, as a test, **but must have the request ```Host``` header set to the custom domain**. Therefore it cannot be tested with simple web browser use.
56 changes: 42 additions & 14 deletions setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,15 @@
# Run this script to deploy the project on AWS

export AWS_REGION=eu-west-3
export STACK_NAME=webtest1
export STACK_NAME=webtest2

export STAGE_NAME=v1

# Optional: custom domain settings.
# Must then update the custom DNS records with the new cloudfront URL.
export USE_CUSTOM_DOMAIN=false
export DOMAIN_NAME=mtest.dev
export DOMAIN_CERT_ARN="define this"

##################################################################

Expand All @@ -14,26 +22,46 @@ export WEB_BUCKET_NAME="${STACK_NAME}-bucket-${RAND_ID}"
# Prevent terminal output waiting:
export AWS_PAGER=""

source stack.sh $STACK_NAME create $WEB_BUCKET_NAME
if [ "$USE_CUSTOM_DOMAIN" == "true" ]; then
source stack.sh $STACK_NAME create $WEB_BUCKET_NAME "stageName=$STAGE_NAME enableCustomDomainName=true domainName=$DOMAIN_NAME certificateArn=$DOMAIN_CERT_ARN"
else
source stack.sh $STACK_NAME create $WEB_BUCKET_NAME stageName=$STAGE_NAME
fi

echo ""
echo "Waiting for stack creation..."

GATEWAY_ID=
while [[ -z $GATEWAY_ID ]]; do
export GATEWAY_ID=$(aws apigateway get-rest-apis --no-paginate | \
python3 -c \
if [ "$USE_CUSTOM_DOMAIN" != "true" ]; then
GATEWAY_ID=
while [[ -z $GATEWAY_ID ]]; do
export GATEWAY_ID=$(aws apigateway get-rest-apis --no-paginate | \
python3 -c \
"import sys, json
for item in json.load(sys.stdin)['items']:
if item['name'] == '$STACK_NAME-api-gateway':
print(item['id'])")
sleep 1
done
sleep 1
done

export GATEWAY_URL="https://${GATEWAY_ID}.execute-api.${AWS_REGION}.amazonaws.com/"
export WEBSITE_URL="https://${GATEWAY_ID}.execute-api.${AWS_REGION}.amazonaws.com/${STAGE_NAME}"
echo ""
echo "The website URL is:"
echo $WEBSITE_URL
echo ""
else
CLOUDFRONT_URL=
while [[ -z $CLOUDFRONT_URL ]]; do
export CLOUDFRONT_URL=$(aws apigateway get-domain-names --no-paginate | \
python3 -c \
"import sys, json
for item in json.load(sys.stdin)['items']:
if item['domainName'] == '$DOMAIN_NAME':
print(item['distributionDomainName'])")
sleep 1
done

echo ""
echo "The API Gateway URL is:"
echo $GATEWAY_URL
echo ""
# Note: must go to GATEWAY_URL/<stage (e.g. v1)> to access the actual website
echo ""
echo "The CloudFront URL is:"
echo $CLOUDFRONT_URL
echo ""
fi
8 changes: 7 additions & 1 deletion stack.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,17 @@ entryFuncs=("delete" "create")
# "create": Create the stack. An error occurs if a stack already
# exists with the provided name, and no update occurs.

# For command=create, the optional 4th argument is a space-separated list
# of parameter-overrides to pass to cloudformation deploy,
# which become template parameters.

############################################################

STACK_NAME=$1
WEB_BUCKET_NAME=$3

ARG4=$4

if [[ -z $STACK_NAME ]]; then
echo ERROR: Please set STACK_NAME
return 1
Expand Down Expand Up @@ -87,7 +93,7 @@ create() {
--template-file out.yml \
--stack-name $STACK_NAME \
--capabilities CAPABILITY_NAMED_IAM \
--parameter-overrides stackName=$STACK_NAME bucketName=$WEB_BUCKET_NAME
--parameter-overrides stackName=$STACK_NAME bucketName=$WEB_BUCKET_NAME $ARG4

if [[ "$?" -ne 0 ]]; then
aws cloudformation describe-stack-events \
Expand Down
47 changes: 46 additions & 1 deletion template.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,30 @@ Parameters:
MinLength: 1
MaxLength: 50
Default: v1
enableCustomDomainName:
Description: Whether to use the custom domain name
Default: false
Type: String
AllowedValues:
- true
- false
domainName:
Description: The custom domain name
Type: String
MinLength: 1
MaxLength: 50
Default: "x"
certificateArn:
Description: The ARN of the DNS certificate for the custom domain name
Type: String
MinLength: 1
MaxLength: 100
Default: "x"

Conditions:
useCustomDomain: !Equals
- !Ref enableCustomDomainName
- true

Resources:

Expand Down Expand Up @@ -78,7 +102,7 @@ Resources:
Properties:
BinaryMediaTypes:
- "*/*"
DisableExecuteApiEndpoint: false
DisableExecuteApiEndpoint: !Ref enableCustomDomainName
EndpointConfiguration:
Types:
- "EDGE"
Expand Down Expand Up @@ -276,3 +300,24 @@ Resources:
Action: lambda:InvokeFunction
FunctionName: !Ref theLambda
Principal: apigateway.amazonaws.com

customDomain:
Type: AWS::ApiGateway::DomainName
Condition: useCustomDomain
Properties:
DomainName: !Ref domainName
CertificateArn: !Ref certificateArn
SecurityPolicy: TLS_1_2
EndpointConfiguration:
Types:
- EDGE

basePathMapping:
Type: AWS::ApiGateway::BasePathMapping
Condition: useCustomDomain
DependsOn:
- customDomain
Properties:
DomainName: !Ref domainName
RestApiId: !GetAtt apiGateway.RestApiId
Stage: !Ref stageName

0 comments on commit eedbbd0

Please sign in to comment.