Infrastructure
Currently, our configured sites are available at:
URL | Function |
---|---|
https://d2knj5ocbd6xdl.cloudfront.net | Staging Site |
https://d3ni409s7fq6ur.cloudfront.net | Production Site |
Our site is hosted on Amazon AWS, and served by Amazon CloudFront edge nodes. To set this up we need to:
- Create an S3 bucket to host our source
- Create a CloudFront Distribution to serve our source
- Create Amazon Lambda functions to mutate some of our request / responses for security reasons, and to handle cache control (see
https://github.com/gatsbyjs/gatsby/blob/master/docs/docs/caching.md
andhttps://www.ximedes.com/2018-04-23/deploying-gatsby-on-s3-and-cloudfront/
).
AWS S3 Bucket Creation / Configuration
- Login to Amazon AWS, select your hosting region (in our case we host in
eu-west-2
, ie. London). - Select
S3
under theServices -> Storage
menu and clickCreate Bucket
. - Enter a DNS compliant bucket name, relevant to the DNS you will be assigning the content. For example
www.komododigital.co.uk
. - Ensure the region is correct, and click next.
- Select the options as you would like on the next page. Our standard config is entirely default (no changes are made).
- On the next screen, when prompted to Set permissions, leave all as default (i.e. No public access).
- Confirm creation of the bucket.
AWS CloudFront Distribution Creation / Configuration
- Login to Amazon AWS, select your hosting region (in our case we host in
eu-west-2
, ie. London). - Select
CloudFront
under theServices -> Networking & Content Delivery
menu and clickCreate Distribution
. - Under the
Web
heading, clickGet Started
. - On the
Create Distribution
page, apply the following settings:
Origin Domain Name: www.komododigital.co.uk.s3.amazonaws.com (or whatever name you gave to your S3 bucket).
Origin Path: <empty>
Origin ID: <autogenerated/default>
Restrict Bucket Access: No
Origin Custom Headers: <autogenerated/default>
Path Pattern: <autogenerated/default>
Viewer Protocol Policy: <Redirect HTTP to HTTPS>
Allowed HTTP Methods: Get, Head
Field-level Encryption Config: <autogenerated/default>
Cached HTTP Methods: Get, Head
Cache Based on Selected Request Headers: <autogenerated/default>
Object Caching: Use Origin Cache Headers
Minimum TTL: 0
Maximum TTL: 31536000
Default TTL: 86400
Forward Cookies: <autogenerated/default>
Query String Forwarding and Caching: <autogenerated/default>
Smooth Streaming: No
Restrict Viewer Access: No
Compress Objects Automatically: No
Lambda Function Associations: <empty>
Price Class: Use Only U.S., Canada and Europe
AWS WAF Web ACL: None
Alternate Domain Names: www.komododigital.co.uk (or whatever domain this will sit on)
SSL Certificate: Custom SSL Certificate (providing SSL for the domain above)
Supported HTTP Versions: HTTP/2 HTTP/1.1 HTTP/1.0
Default Root Object: <empty>
Logging: On (You need to setup and choose as you like)
Bucket for Logs: www.komododigital.co.uk-site-logs (You need to setup and choose as you like)
Log Prefix: <empty>
Cookie Loggin: Off
Enable IPV6: Yes
Comment: <empty>
Distribution state: Enabled.
- Once created, your site should now be available at the domain of choice. We need to do some extra work (see AWS Lambda below).
AWS Lambda / CloudFront Extended Configuration
After configuring CloudFront as above, there are some extra steps to complete.
- Go to
AWS Lambda
. - Important: Switch AWS region to
US East (N. Virginia)
. This is required for the correct configuration options in CloudFront. - Create a new function with the following settings:
Name: CacheControl
Runtime: NodeJs 8.10
Role: <This will be "Create a new role from one or more templates" if you haven't done this before, OR it will be your previously created role>
Policy Template: Basic Lambda@Edge permissions (For CloudFront trigger)
- Edit the function code to be the following:
'use strict';
exports.handler = (event, context, callback) => {
const request = event.Records[0].cf.request;
const response = event.Records[0].cf.response;
const headers = response.headers;
if (request.uri.startsWith('/static/')) {
headers['cache-control'] = [
{
key: 'Cache-Control',
value: 'public, max-age=31536000, immutable'
}
];
} else {
headers['cache-control'] = [
{
key: 'Cache-Control',
value: 'public, max-age=0, must-revalidate'
}
];
}
callback(null, response);
};
- Publish a new version, and then note the ARN in the top right corner (we need that in a bit).
- Create a new function with the following settings:
Name: IndexRedirect
Runtime: NodeJs 8.10
Role: <This will be your previously created role>
- Edit the function code to be the following:
exports.handler = (event, context, callback) => {
const request = event.Records[0].cf.request;
const uri = request.uri;
if (uri.endsWith('/')) {
request.uri += 'index.html';
} else if (!uri.includes('.')) {
request.uri += '/index.html';
}
callback(null, request);
};
- Publish a new version, and then note the ARN in the top right corner (we need that in a bit).
- Go to your AWS CloudFront distribution
- Select the
Behaviours
tab. - Edit the
Default
behaviour. - Add an
Origin Request
underLambda Function Associations
and paste the ARN (recorded above) for yourIndexRedirect
function. - Add an
Origin Response
underLambda Function Associations
and paste the ARN (recorded above) for yourCacheControl
function. - Hit
Yes, Edit
. Your CloudFront distribution should now be configured correctly.
Redirects
If you need to add redirects, do the following:
- Go to
AWS Lambda
. - Important: Switch AWS region to
US East (N. Virginia)
. This is required for the correct configuration options in CloudFront. - Create a new function with the following settings:
Name: SiteRedirects
Runtime: NodeJs 8.10
Role: <This will be "Create a new role from one or more templates" if you haven't done this before, OR it will be your previously created role>
Policy Template: Basic Lambda@Edge permissions (For CloudFront trigger)
- Edit the function code to be the following (adding your redirects in the
routes
object):
'use strict';
exports.handler = (event, context, callback) => {
const request = event.Records[0].cf.request;
const uri = event.Records[0].cf.request.uri;
const routes = {
"/source": "/destination",
}
if (uri in routes) {
const locationRedirect = routes[uri];
const response = {
status: '302',
statusDescription: 'Found',
headers: {
location: [{
key: 'Location',
value: locationRedirect,
}],
},
};
callback(null, response);
}
else {
callback(null, request);
}
};
- Publish a new version, and then note the ARN in the top right corner (we need that in a bit).
- Go to your AWS CloudFront distribution
- Select the
Behaviours
tab. - Edit the
Default
behaviour. - Add an
Viewer Request
underLambda Function Associations
and paste the ARN (recorded above) for yourSiteRedirects
function. - Hit
Yes, Edit
. Your CloudFront distribution should now be configured correctly and start redirecting.
Codeship Deployment Creation / Configuration
Follow the usual project creation steps on Codeship, until you’re at the point of setting up the pipeline. Configure as below under Project Settings
:
Test [Setup Commands]
npm install --global gatsby-cli
npm install
npm run build
Test [Pipelines]
npm test
npm run coverage
### Deploy
- Setup on the branch you wish to trigger the deployment - e.g.
master
. - Select
Amazon S3
. - Provide the following settings:
AWS Access Key ID: <Like Im Pasting That Here. Nice Try Though>
AWS Secret Access Key: <Like Im Pasting That Here. Nice Try Though>
Region: eu-west-2 (or whichever S3 region you have configured above)
Local Path: ./public
S3 Bucket: www.komododigital.co.uk (or whatever you named your S3 bucket name)
ACL: public-read
- Once the above is configured, add a second step of
Custom Script
. - In the script block enter the following:
npm run cloudfront-invalidate
Environment
Add the following environment variables to the project:
CODECOV_TOKEN <This is from https://codecov.io>
DISTRIBUTION_ID <This is from AWS CloudFront>
AWS_ACCESS_KEY_ID <This is from AWS IAM>
AWS_SECRET_ACCESS_KEY <This is from AWS IAM>