2026年11月14日
2026年11月14日
Serve WordPress Images via CloudFront (S3 + WP Offload Media Lite)
This article is a localized edition of the Japanese original. Read the Japanese original
Amazon CloudFront is AWS's CDN (content delivery network). There are two main ways to use it with WordPress.
| Approach | What it does | Good fit when |
|---|---|---|
| Serve only media from CloudFront | Uploaded images and other files live in S3 and are delivered through CloudFront | You have lots of images, or want to cut server bandwidth or disk usage |
| Put the whole site behind CloudFront | The WordPress server becomes the origin, and pages also go through CloudFront | You want faster delivery of the pages themselves. You need to plan how logins and cookies are handled |
This article covers the media-only approach, which has fewer steps and less that can go wrong. For putting the whole site behind CloudFront, see Placing CloudFront in front of WordPress.
Screen names and settings follow the official AWS and WP Offload Media documentation as of November 2026.
Overview
- Create an S3 bucket (with public access still blocked)
- Create an IAM user and access key for WordPress
- Install WP Offload Media Lite and put the keys in
wp-config.php - Create a CloudFront distribution and let it read S3 through OAC
- Point WP Offload Media's delivery at CloudFront
- Optionally add a custom domain (for example,
media.example.com)
About the plugin
WP Offload Media Lite (wordpress.org slug: amazon-s3-and-cloudfront) copies files uploaded to the Media Library to a bucket such as S3 and rewrites the URLs in your pages to point at the bucket or a CDN. As of November 2026 the current version is 3.4.4, and it requires WordPress 5.9 or later and PHP 8.1 or later.
Here's what the free Lite version can and can't do:
| Feature | Lite | Paid (Pro) |
|---|---|---|
| Copy newly uploaded files to S3 and rewrite their URLs | Yes | Yes |
| Use CloudFront for delivery (custom domain supported) | Yes | Yes |
| Move the existing Media Library to S3 in bulk | No | Yes |
| Serve CSS, JavaScript and fonts from the CDN (Assets Pull) | No | Yes |
With Lite, existing images are not moved and keep being served from your server.
Step 1: Create an S3 bucket
- Open S3 in the AWS Management Console and choose "Create bucket".
- Pick a bucket name (for example,
example-wp-media) and a Region (for example, Asia Pacific (Tokyo)ap-northeast-1). - Leave "Object Ownership" at the default ACLs disabled (recommended) and keep "Block all public access" on.
- Choose "Create bucket".
Visitors read files only through CloudFront, so the bucket doesn't need to be public.
Step 2: Create an IAM user and access key
Create an IAM user that WordPress uses to write to the bucket. Grant only the actions this bucket needs.
In the IAM console under "Users", choose "Create user" and give it a name (for example, wp-offload-media). Don't give it console access. Attach the following policy to the new user as an inline policy, replacing example-wp-media with your bucket name.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ObjectLevel",
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:DeleteObject"
],
"Resource": "arn:aws:s3:::example-wp-media/*"
},
{
"Sid": "BucketLevel",
"Effect": "Allow",
"Action": [
"s3:GetBucketPublicAccessBlock",
"s3:GetBucketOwnershipControls",
"s3:ListBucket",
"s3:GetBucketLocation"
],
"Resource": "arn:aws:s3:::example-wp-media"
}
]
}
This has the same structure as the minimum policy in the official WP Offload Media documentation. With public access blocked and ACLs disabled on the bucket, s3:PutObjectAcl isn't needed.
Next, create an access key.
- On the new user's "Security credentials" tab, choose "Create access key" and select "Application running outside AWS" as the use case.
- Note down the access key ID and secret access key that are shown. The secret can't be displayed again later.
If WordPress runs on EC2, you can use an IAM role instead of access keys (use-server-roles, described below).
Step 3: Install WP Offload Media Lite and set the keys
Under Plugins → Add Plugin, search for "WP Offload Media Lite", install it and activate it. Then add the access key to wp-config.php, above the "That's all, stop editing!" line.
<?php
define( 'AS3CF_SETTINGS', serialize( array(
'provider' => 'aws',
'access-key-id' => 'YOUR_ACCESS_KEY_ID',
'secret-access-key' => 'YOUR_SECRET_ACCESS_KEY',
) ) );
If you enter the keys on the plugin's screen, they are stored in the database. Putting them in wp-config.php reduces the risk of the keys leaking through things like database backups. If you use an IAM role on EC2, write 'use-server-roles' => true, instead of the two key lines.
With the keys in place, move on to the plugin settings.
- Open Settings → WP Offload Media, select the existing bucket (
example-wp-media) in the storage settings and save. - Turn on Offload Media (copy to the bucket) in Storage Settings. Keep Deliver Offloaded Media (URL rewriting) in Delivery Settings off until you set up CloudFront in Step 5 (if it's on, turn it off and save).
At this point, newly uploaded images are copied to S3 while your pages keep showing the files on your server. Because the bucket is private, rewriting URLs to S3 at this stage would break the images.
Step 4: Create the CloudFront distribution
For S3 origins, AWS recommends OAC (origin access control) rather than the legacy OAI (origin access identity). With OAC, only CloudFront can read the bucket.
- In the CloudFront console, choose "Create distribution".
- Name the distribution, choose "Single website or app" as the type and continue.
- Under "Origin type", choose Amazon S3, then use "Browse S3" to select the bucket from Step 1.
- Under "Settings", choose Use recommended origin settings. The recommended settings include creating an OAC.
- Choose whether to enable AWS WAF protections, review, and choose "Create distribution". When you create it this way, CloudFront updates the S3 bucket policy for you.
- It's done when the status changes from "Deploying" to a date and time. Note the domain name, which looks like
d111111abcdef8.cloudfront.net.
If you open the bucket policy on the S3 "Permissions" tab, you'll see something like the following. This is also the format to use if you write it yourself (replace the account ID and distribution ID with your own).
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowCloudFrontServicePrincipalReadOnly",
"Effect": "Allow",
"Principal": {
"Service": "cloudfront.amazonaws.com"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::example-wp-media/*",
"Condition": {
"StringEquals": {
"AWS:SourceArn": "arn:aws:cloudfront::111122223333:distribution/EDFDVBD6EXAMPLE"
}
}
}
]
}
The Condition allows reads only from your specific distribution, so other people's CloudFront distributions can't read the bucket.
To add OAC to an existing distribution later, choose "Origin access" in the left menu, then "Create control setting", and create it with signing set to "Sign requests (recommended)" and Origin type S3. Then edit the S3 origin on the distribution's "Origins" tab, set "Origin access" to Origin access control settings (recommended) and pick the OAC you created. Update the bucket policy yourself to the format above.
Step 5: Point WP Offload Media’s delivery at CloudFront
- Open Delivery Settings under Settings → WP Offload Media.
- Choose Amazon CloudFront as the Delivery Provider and click "Save Delivery Provider".
- Turn on Use Custom Domain Name (CNAME) and enter the domain you noted in Step 4 (without
https://, for exampled111111abcdef8.cloudfront.net). - Turn on Deliver Offloaded Media and save.
Upload a new image, insert it into a post and check how it displays. If the image URL uses the CloudFront domain, the setup is working.
To configure this in wp-config.php, add 'delivery-provider' => 'aws' (the value that means CloudFront), 'enable-delivery-domain' => true, 'delivery-domain' => 'd111111abcdef8.cloudfront.net' and 'serve-from-s3' => true (Deliver Offloaded Media) to the AS3CF_SETTINGS array. Settings defined in the constant can no longer be changed from the screen.
Step 6: Serve from a custom domain (optional)
Here's the flow for serving from your own domain, such as media.example.com.
- Get a certificate in AWS Certificate Manager (ACM). Certificates used with CloudFront must be issued in the US East (N. Virginia)
us-east-1Region. Choose DNS validation and add the CNAME record it shows to your DNS. - Add an alternate name to the distribution. Edit the distribution settings, add
media.example.comunder "Alternate domain name (CNAME)", and select the certificate from step 1 under "Custom SSL certificate". - Add a CNAME in DNS. Point the CNAME for
media.example.comatd111111abcdef8.cloudfront.net. If you use Cloudflare DNS, set this record to not be proxied (DNS only). - Change WP Offload Media's delivery domain. In Delivery Settings, change the custom domain to
media.example.comand save.
Verify that it works
# Through CloudFront (returns 200 with an x-cache header)
curl -sI https://d111111abcdef8.cloudfront.net/wp-content/uploads/2026/11/sample.jpg
# Directly from S3 (returns 403 if the bucket is private)
curl -sI https://example-wp-media.s3.ap-northeast-1.amazonaws.com/wp-content/uploads/2026/11/sample.jpg
The paths are examples. In practice, use the image URL from your post minus the domain (it includes year/month and version folders). If x-cache in the CloudFront response says Miss from cloudfront, it was the first fetch; fetch the same URL again and if it says Hit from cloudfront, it's being served from the cache.
Things to watch
- Existing images are not moved (Lite). Images in older posts keep their server URLs. Moving them in bulk requires the paid version.
- Replacing images and caching. By default, WP Offload Media adds a version folder to the path in the bucket to avoid file name clashes and stale cache (the setting is called Add Object Version to Bucket Path). If you turn this off, overwriting a file with the same name can leave the old image in CloudFront. In that case, invalidate the path under "Invalidations" in CloudFront.
- Local files. By default the original files also stay on your server. Turning on "Remove Local Media" (delete from the server) saves disk space, but make sure you know how to restore from S3 before using it.
- Costs. You pay for S3 storage and requests, CloudFront data transfer and so on. Check the AWS pricing pages for current rates.
- Key management. Keep the access keys only in
wp-config.php, and deactivate and delete them in IAM when you no longer need them.
For S3 storage basics, see also Setting up Amazon S3 storage.
Summary
- To serve only media through CloudFront, S3 + WP Offload Media Lite + CloudFront is a straightforward setup
- Keep the S3 bucket private and let only CloudFront read it via OAC and the bucket policy
- Give the IAM user only the minimum permissions for that bucket, and put the keys in
wp-config.php - Choose Amazon CloudFront in Delivery Settings and set the delivery domain
- Issue the certificate for a custom domain in
us-east-1
Questions about WordPress? The publisher of this site is based in Japan and replies in Japanese. Contact (Japanese)