Welcome to our Middleman-AWS-Prismic-CircleCi open source project! We've used this setup to create high-traffic crowdfunding sites for Rainfactory clients (e.g. LunaSleep, Swypcard, Fove ) at Monsoon. The following provides step-by-step instructions for generating a static site with Middleman, Amazon Web Services, CircleCI and Prismic.
- Middleman
- Middleman gems Middleman S3 Sync and Middleman Cloudfront
- AWS S3 and AWS Cloudfront
- CircleCI as a continuous integration platform for deployment to AWS and for automated testing
- Prismic for Content Management
- Running the local web server
- Create a new Middleman Site
- Set permissions and download AWS access keys in AWS Identity & Access Management (IAM)
- Setup an AWS S3 Bucket
- Create an AWS Cloudfront Distribution
- Add Middleman s3 sync gem and configuration
- Add Middleman cloudfront gem and configuration
- Pushing assets to AWS from your console as a first test
- CircleCI for continuous deployment
- Set Environmental Variables in CircleCi
- Prismic Content Management
- Launch in AWS
If you're pulling down this repo and want to get it running, do the following:
-
Bundle Gems
bundle install
-
Compile files
bundle exec middleman build
-
Start a local web server running at: http://localhost:4567/
bundle exec middleman
- Follow steps to install Middleman and start a new site
- After an AWS account has been setup, go to AWS IAM to set permission and download AWS keys (AWS access key id and AWS secret key). You can set specific permissions to Users or Groups as needed (read more about it here). Here's a basic example of adding AdministratorAccess to a User (see below). You'll need to save your AWS Keys for setting environmental variables in CircleCi (AWS_ACCESS_KEY_ID, AWS_SECRET_KEY).
Download User Security Credentials
-
Create an AWS S3 Bucket
Go to Services > S3. Create a Bucket in S3, add a meaningful name (e.g. myappname-production) and region option, e.g. Northern California).
Once you choose a region, search region codes here: http://www.bucketexplorer.com/documentation/amazon-s3--amazon-s3-buckets-and-regions.html
You will need to add your region property in config.rb in the Setup an AWS S3 Bucket step.
-
Enable Static Website Hosting
Go to your bucket and click Properties. Under Static Website Hosting, click Enable website hosting and add index.html in Index Document and error.html in Error Document. Save.
-
Add CORS Configuration for loading fonts from an origin other than your web application (e.g. Font Awesome).
-
Create an AWS Cloudfront Distribution
Go to Services > Cloudfront
-
Select "Web" as your delivery method:
- Create Distribution
-
Add your S3 bucket name to the Origin Domain Name field. If you click on the field, a list will automatically appear. It should also autofill your Origin ID. (e.g. example-bucket)
IMPORTANT: Delete the pre-autofilled Origin Domain Name (e.g. middleman-sandbox-production.s3.amazonaws.com). Replace this with the AWS S3 Bucket Static Website Hosting Endpoint (e.g. middleman-sandbox-production.s3-website-us-west-1.amazonaws.com, see image below). This is necessary so your AWS Cloudfront domain (e.g. http://dXXXXXXXXXXX.cloudfront.net/) mirrors the AWS S3 static website hosting endpoint.
![Alt text](README_Images/aws_s3_endpoint.png)
-
Under Default Cache Behavior Settings, click on the Forward Headers options list. Click Whitelist Headers. Add Origin
-
Under Distribution Settings, add 'index.html' to the Default Root Object.
-
Click Create Distribution
- You’ll be brought to a CloudFront Distributions page in which a Cloudfront domain name will be returned to you. (e.g. http://dXXXXXXXXXXX.cloudfront.net/)
Use middeman-s3_sync gem to push assets to your AWS s3 bucket.
Add middleman-s3_sync gem in your Gemfile and follow configuration instructions. See config.rb.
activate :s3_sync do |s3_sync|
# The name of the S3 bucket you are targeting.
s3_sync.bucket = ENV['AWS_S3_BUCKET_NAME']
# The AWS region code for your bucket.
# For region codes: http://www.bucketexplorer.com/documentation/amazon-s3--amazon-s3-buckets-and-regions.html
s3_sync.region = ENV['AWS_REGION']
s3_sync.aws_access_key_id = ENV['AWS_ACCESS_KEY_ID']
s3_sync.aws_secret_access_key = ENV['AWS_SECRET_KEY']
#s3_sync.delete = true # We delete stray files by default.
#s3_sync.after_build = true # We do not chain after the build step by default.
end
We're using middleman-cloudfront for AWS CloudFront cache invalidation.
Add middleman-cloudfront gem and follow configuration instructions. See config.rb.
activate :cloudfront do |cf|
cf.access_key_id = ENV['AWS_ACCESS_KEY_ID']
cf.secret_access_key = ENV['AWS_SECRET_KEY']
cf.distribution_id = ENV['PRODUCTION_CLOUDFRONT_DISTRIBUTION_ID']
cf.filter = /\.html$/i
#cf.after_build = false # default is false
end
after_s3_sync do |files_by_status|
invalidate files_by_status[:updated]
end
You can watch invalidations processing if you go to CloudFront Distributions > Click on Cloudfront distribution ID > Invalidations tab
If you need to experiment with pushing assets to AWS S3 locally, you can do the following:
- Create an aws.yml file at the root of the application. Note that this file will be ignored for security (See .gitignore)
- Add environmental variables from AWS LastPass notes to aws.yml
- Uncomment
ENV = YAML::load(File.open('aws.yml'))
in config.rb
AWS_S3_BUCKET_NAME: ''
AWS_REGION: ''
AWS_ACCESS_KEY_ID: ''
AWS_SECRET_KEY: ''
PRODUCTION_CLOUD_DISTRIBUTION_ID: ''
- Run these commands to push assets to AWS middleman-sandbox-staging bucket
bundle exec middleman build --verbose
bundle exec middleman s3_sync --bucket=your-aws-bucket-name
PRODUCTION_CLOUDFRONT_DISTRIBUTION_ID=XXXXXXXXXXX bundle exec middleman invalidate
CircleCi will run deployment commands only when changes are merged into the branch
specified in circle.yml (e.g. branch:master
).
- Setup your Github account with CircleCi.
- In CircleCi, add your project/repo.
- Create a circle.yml file in the root of your repo.
dependencies:
pre:
- bundle install
# To speed things up, you can also cache directories. Uncomment this and replace this with code above.
# dependencies:
# cache_directories:
# - "~/.rvm/gems/ruby-2.0.0-p451"
deployment:
production:
branch: master
commands:
- bundle exec middleman build --verbose
# Push Middleman build to your AWS S3 bucket
- bundle exec middleman s3_sync --bucket=middleman-sandbox-production
# Invalidate cache in AWS Cloudfront
- PRODUCTION_CLOUDFRONT_DISTRIBUTION_ID= bundle exec middleman invalidate
Add the following AWS environmental variables required for continuous deployment in CircleCi. In this case, we're pushing assets to your AWS S3 bucket and invalidating the cache in AWS Cloudfront.
-
Follow instructions in Prismic to create a Document Mask and create content.
-
See Prismic's documentation for adding the API object and querying your Prismic repository with Ruby. See config.rb as an example.
api = Prismic.api('https://prismic-project-example.prismic.io/api')
response = api
.form('everything')
.query('[[:d = at(document.type, "document-mask-name")]]')
.submit(api.master_ref)
@something_to_put_in_view = response.results
-
Go to your prismic account. Settings > Webhooks.
-
Go to CircleCi and create an API token (Settings > API Tokens). Create a token for the prismic webhook.
- Add a POST request url (see below) from CircleCI in the Webhooks section of Prismic to trigger a build in CircleCi. This will trigger a build targeted at the specified Github branch every time a document is published.
https://circleci.com/api/v1/project/:username/:project/tree/:branch?circle-token=:token
More documentation resources on creating a webhook:
- Introducing prismic.io webhooks: integration with publishing and changes events
- Prismic Webhooks
- CircleCi: Trigger a new build
You may use your own DNS provider (e.g. GoDaddy) vs Amazon's Route 53 DNS manager. Add your official domain name to Alternate Domain Names (CNAMEs) under the General tab in Cloudfront Distributions. Make sure you place the urls on seperate lines.
The MIT License (MIT)
Copyright (c)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.