Docs

Amazon CloudFront

Serve video files from a private S3 bucket through CloudFront.

Use Amazon CloudFront to deliver the video files Chunkify writes to your S3 bucket. This guide keeps the bucket private and gives CloudFront read access to your output prefix. Viewers use the CloudFront URL to access those outputs.

Start with an Amazon S3 storage connection. The examples use the output prefix chunkify/ and the viewing website https://app.example.com. Replace them with your own values.

Create a CloudFront distribution

In the CloudFront console, select Create distribution. Name it, choose Single website or app, and select Amazon S3 as the origin type.

Select your existing bucket with Browse S3. Use the recommended origin settings to configure origin access control (OAC), then finish creating the distribution. Review its origin settings:

Setting Value
Origin domain Your bucket's S3 endpoint, not its static website endpoint
Origin path Empty
Origin access Origin access control (OAC)
OAC signing behavior Sign requests (recommended)

Keep S3 Block Public Access enabled. OAC lets CloudFront authenticate its reads without making the bucket public. See AWS's distribution setup.

Leave Origin path empty because Chunkify includes the output prefix in each playback URL. An origin path of /chunkify would add that prefix a second time.

Record the distribution ID and domain name assigned by CloudFront. The examples below use your-distribution.cloudfront.net as a placeholder. Replace it with your actual domain. A custom domain is optional.

Allow CloudFront to read the outputs

In S3, open your bucket's Permissions → Bucket policy. Allow this distribution to read objects under your output prefix. Replace YOUR_BUCKET, YOUR_AWS_ACCOUNT_ID, and YOUR_DISTRIBUTION_ID below.

The creation wizard may already have added a statement allowing CloudFront to read the whole bucket. Replace that distribution's generated statement with the scoped statement below, preserving unrelated statements in the policy.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowCloudFrontVideoOutputs",
      "Effect": "Allow",
      "Principal": {
        "Service": "cloudfront.amazonaws.com"
      },
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::YOUR_BUCKET/chunkify/*",
      "Condition": {
        "StringEquals": {
          "AWS:SourceArn": "arn:aws:cloudfront::YOUR_AWS_ACCOUNT_ID:distribution/YOUR_DISTRIBUTION_ID"
        }
      }
    }
  ]
}

Adjust chunkify/* if your output prefix differs. CloudFront's bucket permission is separate from the IAM credentials Chunkify uses to write outputs. See AWS's OAC policy examples.

Anyone with a CloudFront URL can read objects under this prefix. Keep private source videos outside it. OAC protects the S3 origin; restricting individual viewers requires a separate playback access setup.

If your bucket uses SSE-KMS encryption, also grant CloudFront access to the KMS key.

Allow playback from your website

This setup uses S3's CORS headers and passes them through CloudFront. In the bucket's Permissions → Cross-origin resource sharing (CORS) settings, merge this playback rule with your existing rules:

[
  {
    "AllowedOrigins": ["https://app.example.com", "https://chunkify.dev"],
    "AllowedMethods": ["GET", "HEAD"],
    "AllowedHeaders": ["Range"],
    "ExposeHeaders": ["Accept-Ranges", "Content-Length", "Content-Range", "ETag"],
    "MaxAgeSeconds": 3600
  }
]

Replace the application origin and add any other websites that play your videos. https://chunkify.dev allows playback in the Chunkify dashboard. S3 handles preflight requests; do not add OPTIONS to this bucket rule.

Preserve existing upload rules when saving the complete policy. Browser uploads go directly to S3 and also need PUT, the Content-Type request header, and an exposed ETag. See Configure CORS.

Configure caching

CloudFront must keep playlists up to date while caching media files. Chunkify writes HLS playlists with Cache-Control: no-cache, so CloudFront can revalidate them before reuse as renditions and captions become available.

In CloudFront, open Policies → Cache policies → Create cache policy. Name the policy ChunkifyMedia and use these settings:

Setting Value
Minimum TTL 0 seconds
Default TTL 86400 seconds, used when an object has no cache headers
Maximum TTL 31536000 seconds
Headers included in the cache key Include Origin
Cookies None
Query strings None

Minimum TTL must be 0 so CloudFront respects no-cache. The higher maximum allows completed media files to stay cached according to their own headers. See AWS's cache duration guide.

Open the distribution's Behaviors tab and edit the Default (*) behavior:

Setting Value
Origin The S3 origin configured above
Viewer protocol policy Redirect HTTP to HTTPS
Allowed HTTP methods GET, HEAD, OPTIONS
Cached HTTP methods GET, HEAD; leave OPTIONS caching off
Cache policy ChunkifyMedia
Origin request policy Managed policy CORS-S3Origin
Response headers policy None; this setup uses S3's CORS headers
Restrict viewer access No, for the public playback setup in this guide

CORS-S3Origin forwards the headers S3 needs for CORS and preflight requests. Including Origin in the cache key keeps responses for different viewing websites separate. AWS documents these CORS settings.

These methods also support byte-range playback requests. CloudFront supports range GETs; no separate origin or behavior is needed for .m4s or .mp4 files.

Under Error pages, set Error caching minimum TTL to 1 second for 403 and 404. Preserve the original error response. This limits cached errors if a request arrives before an object is available. See AWS's error caching guide.

Save the changes and wait for the distribution to finish deploying before testing. If you changed policies on an existing distribution, invalidate cached outputs so older responses do not hide the changes.

Add the CDN domain to Chunkify

In your Project, open Project settings → Storage, edit the S3 connection, and set CDN base URL to the distribution's HTTPS origin:

https://your-distribution.cloudfront.net

Enter only the HTTPS origin, without an output prefix, path, or query string, then select Save changes. The S3 connection can remain private; CloudFront reads its files through OAC.

For example, an object stored at chunkify/asset_2G6MJiNz71bHQGNzGwKx5cJwPFS/manifest.m3u8 is served at:

https://your-distribution.cloudfront.net/chunkify/asset_2G6MJiNz71bHQGNzGwKx5cJwPFS/manifest.m3u8

Chunkify returns this address as the video asset's cdn_url. Adding the base URL does not verify delivery. See CDN delivery for how playback URLs are built.

Verify playback

Create a test video asset using this storage connection. Once playback is available, use its cdn_url in a player on your website and check the browser's Network panel:

  • The master playlist, rendition playlists, and media requests succeed, and the video plays and seeks.
  • Responses allow your website's origin through Access-Control-Allow-Origin.
  • The poster, timeline previews, and any captions load.
  • Byte-range media requests return 206 Partial Content when requested.
  • After additional HLS renditions or caption tracks are ready, a new master-playlist request reflects the available outputs.
  • Repeated media-segment requests can return X-Cache: Hit from cloudfront, indicating a cache hit.

To inspect a playlist's response headers, include your website's origin. Replace the example path with a real video asset's path:

curl --silent --show-error \
  --dump-header - \
  --output /dev/null \
  --header 'Origin: https://app.example.com' \
  'https://your-distribution.cloudfront.net/chunkify/asset_2G6MJiNz71bHQGNzGwKx5cJwPFS/manifest.m3u8'

Test playback from your website as well as the Chunkify dashboard. A successful request without an Origin header does not establish that browser CORS works.

Troubleshoot delivery

Symptom Check
A file returns 403 Confirm the object exists, then check the OAC, distribution ARN, and bucket policy's output prefix.
A file returns 404 Confirm the exact object key in S3, keep the output prefix in the URL, and leave the origin path empty. If the file now exists, invalidate a previously cached error.
Browser reports a CORS error Check the bucket's CORS policy, the CORS-S3Origin origin request policy, and Origin in the cache key. Invalidate old cached responses after correcting the settings.
Playback shows outdated renditions or captions Check that Minimum TTL is 0, remove conflicting cache overrides, and invalidate the cached playlist before retesting.