Skip Navigation
Show nav
Heroku Dev Center
  • Get Started
  • Documentation
  • Changelog
  • Search
  • Get Started
    • Node.js
    • Ruby on Rails
    • Ruby
    • Python
    • Java
    • PHP
    • Go
    • Scala
    • Clojure
  • Documentation
  • Changelog
  • More
    Additional Resources
    • Home
    • Elements
    • Products
    • Pricing
    • Careers
    • Help
    • Status
    • Events
    • Podcasts
    • Compliance Center
    Heroku Blog

    Heroku Blog

    Find out what's new with Heroku on our blog.

    Visit Blog
  • Log inorSign up
View categories

Categories

  • Heroku Architecture
    • Dynos (app containers)
    • Stacks (operating system images)
    • Networking & DNS
    • Platform Policies
    • Platform Principles
  • Command Line
  • Deployment
    • Deploying with Git
    • Deploying with Docker
    • Deployment Integrations
  • Continuous Delivery
    • Continuous Integration
  • Language Support
    • Node.js
    • Ruby
      • Working with Bundler
      • Rails Support
    • Python
      • Background Jobs in Python
      • Working with Django
    • Java
      • Working with Maven
      • Java Database Operations
      • Java Advanced Topics
      • Working with Spring Boot
    • PHP
    • Go
      • Go Dependency Management
    • Scala
    • Clojure
  • Databases & Data Management
    • Heroku Postgres
      • Postgres Basics
      • Postgres Getting Started
      • Postgres Performance
      • Postgres Data Transfer & Preservation
      • Postgres Availability
      • Postgres Special Topics
    • Heroku Data For Redis
    • Apache Kafka on Heroku
    • Other Data Stores
  • Monitoring & Metrics
    • Logging
  • App Performance
  • Add-ons
    • All Add-ons
  • Collaboration
  • Security
    • App Security
    • Identities & Authentication
    • Compliance
  • Heroku Enterprise
    • Private Spaces
      • Infrastructure Networking
    • Enterprise Accounts
    • Enterprise Teams
    • Heroku Connect (Salesforce sync)
      • Heroku Connect Administration
      • Heroku Connect Reference
      • Heroku Connect Troubleshooting
    • Single Sign-on (SSO)
  • Patterns & Best Practices
  • Extending Heroku
    • Platform API
    • App Webhooks
    • Heroku Labs
    • Building Add-ons
      • Add-on Development Tasks
      • Add-on APIs
      • Add-on Guidelines & Requirements
    • Building CLI Plugins
    • Developing Buildpacks
    • Dev Center
  • Accounts & Billing
  • Troubleshooting & Support
  • Integrating with Salesforce
  • Add-ons
  • All Add-ons
  • Edge
Edge

This add-on is operated by Mixable, Inc.

Speed up your app with the AWS CloudFront Content Delivery Network (CDN)

Edge

Last updated January 30, 2022

Table of Contents

  • Provisioning the add-on
  • Custom domain setup
  • Cache control
  • CloudFront configuration
  • Using with the AWS CLI
  • Using with Rails 3.1 and above
  • Using with Python/Django
  • Dashboard
  • Troubleshooting
  • Migrating between plans
  • Removing the add-on
  • Support

Edge is a content delivery network (CDN) add-on for delivering your Heroku app to your users with low latency and high transfer speeds.

Adding a CDN to your application distributes its content across a global network with over 100 points of presence in 24 countries, ensuring high availability, scalability, and performance for your customers all over the world. This speeds up the delivery of static assets (images, style sheets, JavaScript files, etc.) to your users and reduces the load on your app.

The Edge CDN improves your customer experience by enabling HTTP/2, which efficiently parallelizes many requests to your application within a single connection with the customer.

Edge also improves your application security by negotiating SSL/TLS connections with the highest security ciphers and implementing transparent Distributed-Denial-of-Service (DDOS) mitigation for your app.

Edge is powered by Amazon CloudFront, which guarantees that it is a secure, reliable, and performant addition to your application.

The Edge CDN supports applications written in any Heroku-supported language and is managed via the Edge dashboard.

Provisioning the add-on

Edge can be attached to a Heroku application via the CLI:

A list of all plans available can be found here.

$ heroku addons:create edge --domain myapp.mycompany.com
Successfully configured https://d393bns1jna2o2.cloudfront.net
Created edge-animated-30784 as EDGE_AWS_ACCESS_KEY_ID, EDGE_AWS_SECRET_ACCESS_KEY, EDGE_DISTRIBUTION_ID, EDGE_URL
Use heroku addons:docs edge to view documentation

The optional --domain allows you to configure a custom domain name during provisioning. See custom domain setup for more information.

After you provision Edge, the EDGE_URL config var is available in your app’s configuration. It contains a hostname that serves your application through the CDN. You can confirm this via the heroku config:get command:

$ heroku config:get EDGE_URL
https://d393bns1jna2o2.cloudfront.net

You can also confirm that your app is available at the hostname and its content is is served from the CDN (note the x-cache HTTP header):

$ curl -i https://d393bns1jna2o2.cloudfront.net
HTTP/2 200
content-type: text/html; charset=utf-8
server: WEBrick/1.3.1 (Ruby/1.9.2/2014-08-07)
date: Sun, 10 Dec 2017 16:29:10 GMT
via: 1.1 vegur, 1.1 cac0807f4e1bdd7cf57c08992aa341a5.cloudfront.net (CloudFront)
age: 6
x-cache: Hit from cloudfront
x-amz-cf-id: ADlk4cNUe2LVHzExvTM6pn0Nfhhsbnqla9TSvyOHFVmduDuhv0OFJw==
<html>
...

It may initially take up to 10 minutes to configure the CDN and deploy your content globally before your app is available at the EDGE_URL.

If you are using a custom domain, you need to configure a DNS CNAME to the EDGE_URL. See custom domain setup for more information.

Custom domain setup

You often don’t want to use the https://d393bns1jna2o2.cloudfront.net hostname directly for your app. Edge allows you to configure a custom domain (e.g., https://myapp.mycompany.com) that you can use instead.

Setup when installing

You can set an optional custom domain when installing the addon:

$ heroku addons:create edge --domain myapp.mycompany.com

Setup in the dashboard

You can also set or update a custom domain at any time via the Edge dashboard:

  1. Open the Edge dashboard.
  2. Click Edit next to the Custom Domain field.
  3. Enter your custom domain (e.g., myapp.mycompany.com).
  4. Click Save.

You will see that the distribution status is now “In Progress” configuring the custom domain.

DNS CNAME

Now you need to set up a DNS CNAME for your custom domain (e.g., myapp.mycompany.com) to the Edge hostname (e.g., d393bns1jna2o2.cloudfront.net). Consult with your DNS provider for specific instructions to create CNAME records.

You can confirm that your DNS is configured correctly by using the host command, assuming your DNS changes have propagated:

$ host myapp.mycompany.com
myapp.mycompany.com is an alias for d393bns1jna2o2.cloudfront.net.
...

After the DNS CNAME record has propagated, you can access your app on the custom domain:

$ curl -vi https://myapp.mycompany.com
HTTP/2 200
content-type: text/html; charset=utf-8
server: WEBrick/1.3.1 (Ruby/1.9.2/2014-08-07)
date: Sun, 03 Dec 2017 00:38:47 GMT
via: 1.1 vegur, 1.1 022c901b294fedd7074704d46fce9819.cloudfront.net (CloudFront)
age: 88
x-cache: Hit from cloudfront
x-amz-cf-id: ysBQ-8gCY-eWxmjDXMMVjucfBNbLvP650ut28b99HeZqz-8vlIEt6g==
<html>
...

## Disable HTTPS validation to see content over HTTPS
$ curl -k https://myapp.mycompany.com
<html>
...

HTTPS / SSL

When you access your custom domain over HTTPS (e.g. https://myapp.mycompany.com), you will see a security warning that the SSL certificate is for *.cloudfront.net. To fix this, you need to approve a free SSL certificate for your custom domain, then apply it to your distribution.

Certificate Request

When you set a custom domain name, Edge sends a certificate request email. Emails are sent to domain owners listed in whois as well as special email addresses like admin@mycompany.com.

You can see your progress toward the approval process and apply the certificate through the Edge dashboard:

  1. Open the Edge dashboard.
  2. See “Pending Validation” next in the “Custom Cert” field.
  3. Find the “Certificate Approval” email in your (or the domain owner’s) inbox.
  4. Click the “Amazon Certificate Approvals” link.
  5. Click I Approve.
  6. Return to the Edge dashboard and see “Issued” in the “Custom Cert” field.
  7. Click Apply.

You will see that the distribution status is now “In Progress” configuring the custom certificate.

## HTTPS works as expected
$ curl https://myapp.mycompany.com
<html>
...

If you did not receive the email, check your domain and email settings, then click Resend in the Edge dashboard.

For more information, see the AWS Certificate Manager Email Validation FAQ.

Cache control

By default, objects stay cached for 24 hours. This duration results in better performance for your users because your content is more likely to be served directly from the edge cache. It also reduces load on your Heroku app.

You can control this duration from your app with the Cache-Control headers.

To set a shorter duration, say one hour, respond with the header Cache-Control: max-age=3600.

To set a longer duration, say a year, respond with the header Cache-Control: max-age=31536000.

To bypass caching altogether respond with Cache-Control: no-cache.

For more information read the Using Headers to Control Cache Duration for Individual Objects CloudFront doc.

CloudFront configuration

For reference, the CloudFront cache behavior settings are:

Setting Value
Viewer Protocol Policy Redirect HTTP to HTTPS
Allowed HTTP Methods GET, HEAD, OPTIONS, PUT, POST, PATCH, DELETE
Cached HTTP Methods GET, HEAD
Cache Based on Selected Request Headers None (Improves caching)
Object Caching Use Origin Cache Headers
Minimum TTL 0
Maximum TTL 31536000
Default TTL 86400
Forward Cookies None (Improves caching)
Query String Forwarding and Caching None (Improves caching)
Compress Objects Automatically Yes

You can update these settings with the AWS CLI or opening a support ticket.

Using with the AWS CLI

You can update the Edge config or create an invalidation via the aws CLI. This entails installing the aws CLI, and configuring it with EDGE_AWS_ACCESS_KEY_ID, etc.

If you have… Install with…
Mac OS X brew install awscli
Windows Python / PIP instructions
Ubuntu Linux apt-get install awscli
Other Python / PIP instructions

Configure and activate an AWS CLI Profile

Configure a new edge profile with your addon AWS credentials:

$ heroku config --app edgeapp
EDGE_AWS_ACCESS_KEY_ID:     AKIA...
EDGE_AWS_SECRET_ACCESS_KEY: JRHH...
EDGE_DISTRIBUTION_ID:       EJM2O0DPZ8B2Y
EDGE_URL:                   https://d1unsc88mkka3m.cloudfront.net

$ aws configure --profile edge
AWS Access Key ID [None]: AKIA...
AWS Secret Access Key [None]: JRHH...
Default region name [None]: us-east-1
Default output format [None]: json

Activate the profile:

$ export AWS_DEFAULT_PROFILE=edge

Use the CLI to inspect your distribution

Test the CLI. You can get your configuration:

$ export AWS_DEFAULT_PROFILE=edge
$ export DISTRIBUTION_ID=EJM2O0DPZ8B2Y

$ aws cloudfront get-distribution --id $DISTRIBUTION_ID
{
    "ETag": "E1H92KNENJ9W16",
    "Distribution": {
        "Id": "EJM2O0DPZ8B2Y",
        ...
    }
}

But you can not update it:

$ aws cloudfront create-invalidation --distribution-id $DISTRIBUTION_ID --paths '/*'
An error occurred (AccessDenied) when calling the CreateInvalidation operation: User is not authorized to perform: cloudfront:CreateInvalidation

Install AWS CLI plugin with pip

Install the AWS CLI Execute API plugin. The plugin lets you send all CloudFront Update API requests to an endpoint scoped to your Heroku addon.

If you installed awscli with Homebrew, use its bundled Python and note the site-package directory with pip show awscli-plugin-execute-api:

$ /opt/homebrew/Cellar/awscli/2.4.7/libexec/bin/pip install --upgrade awscli-plugin-execute-api
Successfully installed awscli-plugin-execute-api-0.2.1

$ /opt/homebrew/Cellar/awscli/2.4.7/libexec/bin/pip show awscli-plugin-execute-api
Name: awscli-plugin-execute-api
Location: /opt/homebrew/Cellar/awscli/2.4.7/libexec/lib/python3.9/site-packages

If you installed awscli with pip, use your system Python and note the site-package directory with pip show awscli-plugin-execute-api:

$ pip install --upgrade awscli-plugin-execute-api

$ pip show awscli-plugin-execute-api
Name: awscli-plugin-execute-api
Location: /Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/site-packages

Configure the plugin

$ export AWS_DEFAULT_PROFILE=edge

## use the location of site-packages from `pip show`
$ aws configure set plugins.cli_legacy_plugin_path /opt/homebrew/Cellar/awscli/2.4.7/libexec/lib/python3.9/site-packages

## configure configure the plugin and endpoints
$ aws configure set plugins.execute-api awscli_plugin_execute_api
$ aws configure set cloudfront.update-distribution https://api.edge.mixable.net/cloudfront
$ aws configure set cloudfront.create-invalidation https://api.edge.mixable.net/cloudfront

You can verify its config in ~/.aws/config:

[profile edge]
region = us-east-1
output = json
cloudfront =
    update-distribution = https://api.edge.mixable.net/cloudfront
    create-invalidation = https://api.edge.mixable.net/cloudfront

[plugins]
execute-api = awscli_plugin_execute_api
cli_legacy_plugin_path = /opt/homebrew/Cellar/awscli/2.4.7/libexec/lib/python3.9/site-packages

Use the CLI to update your distribution

Command to create an invalidation:

$ aws cloudfront create-invalidation --distribution-id $DISTRIBUTION_ID --paths '/*'

Example response:

{
    "Location": "https://cloudfront.amazonaws.com/2018-11-05/distribution/EQ0A1ULE1WVTI/invalidation/ILN6EOUA0GR8R",
    "Invalidation": {
        "Id": "ILN6EOUA0GR8R",
        "Status": "InProgress",
        "CreateTime": "2019-06-19T15:45:39Z",
        "InvalidationBatch": {
            "Paths": {
                "Quantity": 1,
                "Items": [
                    "/*"
                ]
            },
            "CallerReference": "cli-1560959138-179155"
        }
    }
}

Command to get config:

$ aws cloudfront get-distribution-config --id $DISTRIBUTION_ID --query 'DistributionConfig' > config.json

Now update config.json to add behaviors, etc.

Command to update config:

$ ETAG=$(aws cloudfront get-distribution --id $DISTRIBUTION_ID --output text --query 'ETag')
$ aws cloudfront update-distribution --id $DISTRIBUTION_ID --if-match $ETAG --distribution-config file://config.json

Example output:

{
    "ETag": "E2ZJ47QDF7LPIS",
    "Distribution": {
        "Id": "EQ0A1ULE1WVTI",
        "ARN": "arn:aws:cloudfront::615670401552:distribution/EQ0A1ULE1WVTI",
        "Status": "InProgress",
        ...
    }
}

Using with Rails 3.1 and above

Rails 3.1 introduced an asset pipeline for building static assets like CSS, HTML and JavaScript files with pre-processors such as Sass or ERB.

Using Edge to distribute these assets is a one-line change. In config/environments/production.rb, set:

config.action_controller.asset_host = ENV['EDGE_URL']

This tells Rails to use your Edge endpoint as the hostname for static assets.

If you are using a custom domain, you should use that hostname instead of the EDGE_URL cloudfront.com hostname.

Note that you do not have to use the discouraged Asset Sync gem to copy assets to S3. Your Rails app can serve assets directly and the CDN will cache the contents for fast delivery to end users.

For more information, see:

  • Ruby on Rails The Asset Pipeline CDNs guide
  • Heroku Dev Center Using Amazon CloudFront CDN doc
  • AWS Caching the Rails Asset Pipeline with Amazon CloudFront blog

Using with Python/Django

Django 2.0 has a “static files” app that collects CSS, images and JavaScript into a single location to be served in production.

Using Edge to distribute these assets is simple to configure. In settings.py, add:

INSTALLED_APPS = [
    'django.contrib.staticfiles',
]
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
STATIC_URL = os.environ.get('EDGE_URL', '') + '/static/'

Now you can use the collectstatic tool to collect the apps static files in into the ./static directory:

$ python manage.py collectstatic

And you can use the static helper in your templates:

{% load static %}
<link rel="stylesheet" href="{% static "style.css" %}" type="text/css" media="screen" />

Note that you do not have to use the S3Storage backend to copy static files to S3. Your Django app can serve the assets directly and the CDN will cache the contents for fast delivery to end users.

For more information, see:

  • Django Managing Static Files howto
  • Django staticfiles app reference

Dashboard

The Edge dashboard allows you to configure a custom domain name, apply a custom SSL certificate, and invalidate the distribution contents.

You can access the dashboard via the CLI:

$ heroku addons:open edge
Opening https://addons-sso.heroku.com/apps/...

or by visiting the Heroku Dashboard and selecting the application in question. Select Edge from the Add-ons menu.

Troubleshooting

If you do not see a certificate approval email, you might not be a registered owner of the domain name. You can look at WHOIS for the domain name to see contact information, and ask one of the owners to approve the certificate for you.

Migrating between plans

Use the heroku addons:upgrade command to migrate to a new plan.

$ heroku addons:upgrade edge:newplan
-----> Upgrading edge:newplan to sharp-mountain-4005... done, v18 ($49/mo)
       Your plan has been updated to: edge:newplan

Removing the add-on

You can remove Edge via the CLI:

This will disable the CDN hostname and cannot be undone!

$ heroku addons:destroy edge
-----> Removing edge from sharp-mountain-4005... done, v20 (free)

Before removing Edge, you should make sure your users are not accessing your app through the CDN.

Support

All Edge support and runtime issues should be submitted via one of the Heroku Support channels. Any non-support related issues or product feedback is welcome at noah@mixable.net.

Keep reading

  • All Add-ons

Feedback

Log in to submit feedback.

Ziggeo Einstein Platform Services

Information & Support

  • Getting Started
  • Documentation
  • Changelog
  • Compliance Center
  • Training & Education
  • Blog
  • Podcasts
  • Support Channels
  • Status

Language Reference

  • Node.js
  • Ruby
  • Java
  • PHP
  • Python
  • Go
  • Scala
  • Clojure

Other Resources

  • Careers
  • Elements
  • Products
  • Pricing

Subscribe to our monthly newsletter

Your email address:

  • RSS
    • Dev Center Articles
    • Dev Center Changelog
    • Heroku Blog
    • Heroku News Blog
    • Heroku Engineering Blog
  • Heroku Podcasts
  • Twitter
    • Dev Center Articles
    • Dev Center Changelog
    • Heroku
    • Heroku Status
  • Facebook
  • Instagram
  • Github
  • LinkedIn
  • YouTube
Heroku is acompany

 © Salesforce.com

  • heroku.com
  • Terms of Service
  • Privacy
  • Cookies
  • Cookie Preferences