{"id":2241,"date":"2017-12-17T12:57:18","date_gmt":"2017-12-17T07:27:18","guid":{"rendered":"https:\/\/pheonixsolutions.com\/blog\/?p=2241"},"modified":"2026-09-12T17:21:06","modified_gmt":"2026-09-12T11:51:06","slug":"moving-wordpress-media-amazon-cloudfront-s3","status":"publish","type":"post","link":"https:\/\/pheonixsolutions.com\/blog\/moving-wordpress-media-amazon-cloudfront-s3\/","title":{"rendered":"How to Move WordPress Media Files to Amazon S3 and CloudFront"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">Introduction<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Amazon S3 provides scalable and reliable storage for static website content such as images, videos, and other media files. By moving WordPress media files to Amazon S3 and serving them through Amazon CloudFront, you can reduce the load on the WordPress server and improve media delivery performance for visitors.<br><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Prerequisites<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Before proceeding, make sure you have:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>A working WordPress website with administrator access.<\/li>\n\n\n\n<li>Access to the <strong>AWS Management Console<\/strong>.<\/li>\n\n\n\n<li>An AWS IAM user with the required permissions to access S3.<\/li>\n\n\n\n<li>An S3 bucket created for storing the WordPress media files.<\/li>\n\n\n\n<li>AWS Access Key ID and Secret Access Key.<\/li>\n\n\n\n<li>AWS CLI installed and configured on the WordPress server.<\/li>\n\n\n\n<li>The <strong>Amazon Web Services<\/strong>, <strong>Amazon S3, and CloudFront<\/strong> WordPress plugins installed and configured.<\/li>\n\n\n\n<li>A complete backup of the WordPress files and database.<\/li>\n\n\n\n<li>Sufficient AWS S3 storage and CloudFront configuration for the website.<\/li>\n\n\n\n<li>Caching should be temporarily disabled while performing the migration to avoid stale media URLs.<\/li>\n<\/ol>\n\n\n<h2>Implementation<\/h2>\n<p>In this post, we will explain moving wordpress media to Amazon CloudFront and S3.<\/p>\n<p>Step 1: Install the following plugins on WordPress.<\/p>\n<p><a href=\"https:\/\/wordpress.org\/plugins\/amazon-web-services\/\" target=\"_blank\" rel=\"noopener\">https:\/\/wordpress.org\/plugins\/amazon-web-services\/<\/a><\/p>\n<p><a href=\"https:\/\/wordpress.org\/plugins\/amazon-s3-and-cloudfront\/\" target=\"_blank\" rel=\"noopener\">https:\/\/wordpress.org\/plugins\/amazon-s3-and-cloudfront\/<\/a><\/p>\n<p>Step 2: Configure your Amazon Web Services account here and create a new user in the AWS console.<\/p>\n<p>Step 3: To create the AWS S3 bucket for your domain, create the new user in AWS and copy the AWS Access Key ID and Secret Access Key.<\/p>\n<p>Step 4: Log in to your server and configure the AWS user using the following command.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"null\">aws configure<\/pre>\n<p>Step 5:Go to your WordPress site upload folder and run the following command.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"null\">aws s3 sync . s3:\/\/bucket-name\/folder<\/pre>\n<p>Step 6: In the root folder, you can create a new file named aws-cdn-script.php using the following code.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"null\">&lt;?php\n\n    ini_set('display_errors', 1);\n    error_reporting(E_ALL);\n\n    \/* ======================================================\n    This script is NOT FULLY TESTED (not tested on Windows Server either)\n    USE AT YOUR OWN RISK - development environment Ubuntu Linux 14.04.3 LTS\n\n    The purpose of this script is for small websites and blogs\n    to have their existing media to work through Amazon S3\n    \n    There's a great plugin, WP Offload S3, that we'll be tapping\n    into...it works great for new media, but this is a quick\n    fix for EXISTING media - media added before you start\n    using WP Offload S3.\n\n    This script is not fully tested, but should be useful for\n    most situations.  It does create a backup of your database,\n    though it's not tested to work 100% in all hosting scenarios.\n\n    Put this file in your WordPress root directory, where wp-config.php is.\n    You must also already have these 2 plugins installed and configured:\n    - https:\/\/wordpress.org\/plugins\/amazon-web-services\/\n    - https:\/\/wordpress.org\/plugins\/amazon-s3-and-cloudfront\/\n\n    TURN OFF CACHING if you have it on your site.  Re-enable it after\n    everything is done.\n\n    ======================================================\n    STEPS\n\n    1) Manually upload all of your existing \/wp-content\/uploads\/ files to the\n    Amazon S3 bucket (the bucket you configured WP Offload S3 to use for new images)\n\n    2) Add and configure plugins (the 2 listed above)\n\n    3) Run this script from the root directory of your WordPress site\n\n    ======================================================\n    Developer: TJ Nevis\n    Website: http:\/\/blog.TJNevis.com, http:\/\/NevisTechnology.com\n    More Info: http:\/\/blog.tjnevis.com\/wordpress-and-amazon-s3-quick-fix-for-existing-media-to-be-served-on-amazon-s3\/\n    Last Updated: 04\/19\/2016\n    ====================================================== *\/\n\n    require_once 'wp-config.php';\n    require_once 'wp-content\/plugins\/amazon-s3-and-cloudfront\/wordpress-s3.php';\n    global $table_prefix;\n\n    echo '&lt;h1&gt;Move Existing Media to Amazon S3&lt;\/h1&gt;';\n    echo '&lt;h3&gt;By TJ Nevis [&lt;a href=\"http:\/\/NevisTechnology.com?ref=S3Script\" target=\"_blank\"&gt;NevisTechnology.com&lt;\/a&gt;] Detailed blog post &lt;a href=\"http:\/\/blog.tjnevis.com\/wp-offload-s3-quick-fix-for-existing-media\/\" target=\"_blank\"&gt;here&lt;\/a&gt;&lt;\/h3&gt;';\n\n    \/* ======================================================\n    First step, we're going to back up the database and\n    save it in the the root directory of your site (where this file is)    \n    ====================================================== *\/\n    $dbHost = $wpdb-&gt;dbhost;\n    $dbName = $wpdb-&gt;dbname;\n    $dbPassword = $wpdb-&gt;dbpassword;\n    $dbSaveFileLocation = dirname(__FILE__) . '\/backup-' . date('Y-m-d-h:i:s', time()) . '.sql';\n    $dbUser = $wpdb-&gt;dbuser;\n\n    exec(\"mysqldump --user=$dbUser --password=$dbPassword --host=$dbHost $dbName &gt; $dbSaveFileLocation\");\n\n    \/* ======================================================\n    Let's get set up with by grabbing WP Offload S3 values\n    ====================================================== *\/\n    amazon_web_services_require_files(); \/\/ Thanks k0nG\n    $aws = new Amazon_Web_Services( __FILE__ ); \/\/ Thanks k0nG\n    $awsS3 = new Amazon_S3_And_CloudFront(__FILE__, $aws); \/\/ Thanks k0nG\n    $bucket = ( !empty( $awsS3-&gt;get_setting('cloudfront') ) ) ? $awsS3-&gt;get_setting('cloudfront') : $awsS3-&gt;get_setting('bucket'); \/\/ If you're using a CDN and the setting is saved, use that for CloudFront URL replcaement, otherwise use the S3 bucket name\n    $region = $awsS3-&gt;get_setting('region'); \/\/ Thanks k0nG\n    $folderPrefix = $awsS3-&gt;get_setting('object-prefix');\n\n    \/* ======================================================\n    Check if the user is requesting to remove the existing media updates\n    ====================================================== *\/\n    if( isset($_GET['remove']) &amp;&amp; $_GET['remove'] ) { \/\/ ?removeS3Update=true\n        if( $dbConnection = mysqli_connect($dbHost, $dbUser, $dbPassword, $dbName) ) {\n\n            $removeAmazonS3Info = \"DELETE FROM \" . $table_prefix . \"postmeta WHERE meta_key = 'amazonS3_info';\";\n            $reversePostContentHref = updatePostContent(\n                                            'href',\n                                            $table_prefix . 'posts',\n                                            get_site_url( $wpdb-&gt;blogid ) . '\/' . $folderPrefix,\n                                            \"https:\/\/$bucket.s3.amazonaws.com\/$folderPrefix\",\n                                            true\n                                        );\n            $reversePostContentSrc = updatePostContent(\n                                            'src',\n                                            $table_prefix . 'posts',\n                                            get_site_url( $wpdb-&gt;blogid ) . '\/' . $folderPrefix,\n                                            \"https:\/\/$bucket.s3.amazonaws.com\/$folderPrefix\",\n                                            true\n                                        );\n\n            echo 'RUNNING COMMAND: ' . $removeAmazonS3Info . ' - '; \n            if( $dbConnection-&gt;query($removeAmazonS3Info) ) {\n                echo ' &lt;strong&gt;TRUE, ' . $dbConnection-&gt;affected_rows . ' rows affected&lt;\/strong&gt;&lt;br \/&gt;';\n            }\n\n            echo 'RUNNING COMMAND: ' . $reversePostContentHref . ' - ';\n            if( $dbConnection-&gt;query($reversePostContentHref) ) {\n                echo ' &lt;strong&gt;TRUE, ' . $dbConnection-&gt;affected_rows . ' rows affected&lt;\/strong&gt;&lt;br \/&gt;';\n            }\n\n            echo 'RUNNING COMMAND: ' . $reversePostContentSrc . ' - '; \n            if( $dbConnection-&gt;query($reversePostContentSrc) ) {\n                echo ' &lt;strong&gt;TRUE, ' . $dbConnection-&gt;affected_rows . ' rows affected&lt;\/strong&gt;&lt;br \/&gt;';\n            }   \n\n        }\n\n        echo '&lt;h3&gt;DONE with removing records for WP Offload S3 - reverted back to serving from the local server&lt;\/h3&gt;';\n\n        exit(); \/\/ Don't do the rest of the script\n    }\n\n    \/* ======================================================\n    Start fresh, delete data thatis from WP Offload S3    \n    ====================================================== *\/\n    $wpdb-&gt;delete($table_prefix . 'postmeta',\n        array(\n            'meta_key'  =&gt; 'amazonS3_info'\n        )\n    );\n\n    \/* ======================================================\n    Grab the attachments from the database, we'll need\n    the meta_value (image name), and the post ID it's related to\n    ====================================================== *\/\n    $picturesToUpdate = $wpdb-&gt;get_results(\"SELECT * FROM \" . $table_prefix . \"postmeta WHERE meta_key = '_wp_attached_file'\");\n\n    foreach($picturesToUpdate as $picture) {\n        $pictureMetaData = serialize(array(\n            'bucket'    =&gt; $bucket,\n            'key'       =&gt; $folderPrefix . $picture-&gt;meta_value,\n            'region'    =&gt; $region \/\/ Thanks k0nG\n        ));\n\n        \/* ======================================================\n        Now let's insert the record that WP Offload S3 looks for\n        to change the image URL to your S3 URL\n        ====================================================== *\/\n        $wpdb-&gt;insert($table_prefix . 'postmeta', \n            array(\n                'post_id'   =&gt; $picture-&gt;post_id,\n                'meta_key'  =&gt; 'amazonS3_info',\n                'meta_value'  =&gt; $pictureMetaData\n            )\n        );\n\n    }\n\n    if( $dbConnection = mysqli_connect($dbHost, $dbUser, $dbPassword, $dbName) ) {\n\n        $hrefMySQLUpdate = updatePostContent(\n                                'href',\n                                $table_prefix . 'posts',\n                                get_site_url( $wpdb-&gt;blogid ) . '\/' . $folderPrefix,\n                                \"https:\/\/$bucket.s3.amazonaws.com\/$folderPrefix\"\n                            );\n        $srcMySQLUpdate = updatePostContent(\n                                'src',\n                                $table_prefix . 'posts',\n                                get_site_url( $wpdb-&gt;blogid ) . '\/' . $folderPrefix,\n                                \"https:\/\/$bucket.s3.amazonaws.com\/$folderPrefix\"\n                            );\n\n        echo 'RUNNING COMMAND: ' . $hrefMySQLUpdate . ' - '; \n        if( $dbConnection-&gt;query($hrefMySQLUpdate) ) {\n            echo ' &lt;strong&gt;TRUE, ' . $dbConnection-&gt;affected_rows . ' rows affected&lt;\/strong&gt;&lt;br \/&gt;';\n        }\n\n        echo 'RUNNING COMMAND: ' . $srcMySQLUpdate . ' - ';\n        if( $dbConnection-&gt;query($srcMySQLUpdate) ) {\n            echo ' &lt;strong&gt;TRUE, ' . $dbConnection-&gt;affected_rows . ' rows affected&lt;\/strong&gt;&lt;br \/&gt;';\n        }\n\n    }\n\n    echo '&lt;h3&gt;DONE with adding records for WP Offload S3 to recognize the image on S3&lt;\/h3&gt;';\n\n\n\n    function updatePostContent($type, $table, $blog, $s3bucket, $reverse = FALSE) {\n        \/\/ $reverse is to remove the post_content updates and put them back to serving locally\n        $from   = ( !$reverse ) ? $blog : $s3bucket;\n        $to     = ( !$reverse ) ? $s3bucket : $blog;\n\n        return \"UPDATE $table SET post_content = replace(post_content, '$type=\\\"$from', '$type=\\\"$to');\";\n    }\n\n?&gt;<\/pre>\n<p>Step 7: In the URL, you can access this page like http:\/\/sitename.com\/aws-cdn-script.php?remove=true, and after execution, the file will be removed.<\/p>\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Migrating WordPress media files to Amazon S3 and serving them through CloudFront can reduce the resource usage of the WordPress server and improve the delivery of static content. Before running the migration script, always maintain a verified backup of the database and media files.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">After confirming that all media is loading correctly from S3\/CloudFront, the temporary migration script should be removed from the WordPress root directory for security reasons. The migration should also be tested carefully on a staging environment before applying it to a production website.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">FAQs<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">1. Why should WordPress media files be moved to Amazon S3?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Moving media files to Amazon S3 reduces the storage and bandwidth load on the WordPress server. It also provides scalable and highly durable storage for images and other static files.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">2. What is the role of Amazon CloudFront?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Amazon CloudFront is a Content Delivery Network (CDN) that delivers files from locations closer to website visitors, which can improve media loading performance.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">3. Do I need both Amazon S3 and CloudFront?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">No. WordPress media can be served directly from Amazon S3. CloudFront is optional but recommended when you want CDN-based delivery and better global performance.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Related Articles<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/pheonixsolutions.com\/blog\/how-to-download-files-from-s3-bucket-to-local-machine-or-server\/\">How to download files from S3 bucket to local machine or server<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/pheonixsolutions.com\/blog\/a-guide-to-upload-images-to-s3\/\">A Guide to upload Images to S3<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Talk to our experts<strong>:<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Looking for the right technology solution for your business?. Our experts can help with\u00a0web hosting, domain registration, DevOps and cloud, software development, web applications, mobile applications, and enterprise solutions. Get in touch with our team <a href=\"https:\/\/pheonixsolutions.com\/contact\" target=\"_blank\" rel=\"noreferrer noopener\">here<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction Amazon S3 provides scalable and reliable storage for static website content such as images, videos, and other media files. [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[1019],"tags":[280,273,167],"class_list":["post-2241","post","type-post","status-publish","format-standard","hentry","category-cloud-aws","tag-amazon","tag-php","tag-wordpress-2","psol-cat-cloud-aws"],"jetpack_publicize_connections":[],"jetpack_shortlink":"https:\/\/wp.me\/phn2x7-A9","jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/pheonixsolutions.com\/blog\/wp-json\/wp\/v2\/posts\/2241","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/pheonixsolutions.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/pheonixsolutions.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/pheonixsolutions.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/pheonixsolutions.com\/blog\/wp-json\/wp\/v2\/comments?post=2241"}],"version-history":[{"count":2,"href":"https:\/\/pheonixsolutions.com\/blog\/wp-json\/wp\/v2\/posts\/2241\/revisions"}],"predecessor-version":[{"id":11724,"href":"https:\/\/pheonixsolutions.com\/blog\/wp-json\/wp\/v2\/posts\/2241\/revisions\/11724"}],"wp:attachment":[{"href":"https:\/\/pheonixsolutions.com\/blog\/wp-json\/wp\/v2\/media?parent=2241"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/pheonixsolutions.com\/blog\/wp-json\/wp\/v2\/categories?post=2241"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/pheonixsolutions.com\/blog\/wp-json\/wp\/v2\/tags?post=2241"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}