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 Contentwhen 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. |