This website uses cookies for some functions to work. Click here to read our privacy policy and learn about our use of cookies.
pCloud Encrypted Cloud Storage

How to Serve Images from a Subdomain on a WordPress Website

If you are serious about speeding up your blog, then you must have used tools like Pingdom and GTmetrix to test its speed. These tests usually show recommendations like serve images from subdomain, serve static content from a subdomain or from a cookieless domain or parallelize downloads across hostnames etc.

If you want to get rid of these flags in speed tests and want to speed up your blog, you should consider serving images from a subdomain. This is the easiest and completely free approach which helps in improving site load times.

In this article, I am sharing how I setup my WordPress websites to serve images from subdomain and improve page load time.

But, Why Serve Images From Subdomain?

In simple words, the number of connection a web-browser can make to a single domain is limited. Most modern browsers can make up to 6 connections per hostname at the same time.

Besides images, there are many things that load from your domain. This includes scripts, CSS, JS, HTML, simple text files etc. A browser can’t load rest of the files from the same hostname until other files are loaded first. You can think of this as a queue.

This is why, you often read recommendations to use CDN services and other ways of improving site speed. Of course, most CDN services aren’t free. In such case, serving images from a subdomain is an effortless way of improving speed of your blog by some extent. This method can also be referred to as sharding.

Does Serving Images From A Subdomain Really Help?

Yes, it does. Images are one of the heaviest parts of any site. But they’re also one of the most crucial ones.  Images help provide better understanding of your content and also with SEO.

A subdomain is considered as a separate website. By serving images from subdomain, it will take less time for a browser to load content from your server because the browser can simultaneously load content from different domains.

This significantly reduces the time a browser has to wait before it can serve all the content from your domain, dramatically improving load time of your blog.

I’m also serving images from a subdomain and you can checkout my blog’s speed ranking on Pingdom or GTmetrix before you continue.

Requirements

  • Some knowledge of cPanel and phpMyAdmin.
  • Backup.
  • Patience, a lot of patience.

My Setup

  • Hosting by SiteGround. Also tested with DreamHost and a VPS with CyberPanel.
  • WordPress v4.5.3. Tested up to WordPress v5.5.1.
  • Tested with php version up to v7.4.

Note: Replace https:// with http:// everywhere in this guide if your website does not use SSL certificate. This guide assumes your site is served over HTTPS.


Step 1: Creating A New Subdomain

To begin with, we will need a subdomain. To create a subdomain, log in to your cPanel or other control panel that your host provides and enter the Subdomains section.

Creating Subdomain on SiteGround

Under Create a Subdomain, enter the name of your subdomain. You can choose any name that makes sense. For example, you can use img, images, media or anything of your choice. I’m choosing media.

Choose your domain from the drop-down list (if you have more than one) on which you need to create this subdomain. I will choose techstuffer.com. My subdomain will be – media.techstuffer.com.

Change the Document Root to your WP Content folder. By default, it’s public_html/wp-content/uploads if you never changed it.

Creating Subdomain in cPanel

Attention: If you have changed the upload path for any reason, enter that path here. For example, I have changed the path to files/uploads from wp-content/uploads. In this case, I will enter public_html/files/uploads under Document Root. If you are unsure whether you changed this path or kept default, you should open an image from your blog and see the path. If it looks like yourblog.com/wp-content/uploads/image.jpg, then you have the default path.

If your control panel allows issuing SSL certificate here, check that option to serve images over https connection. If you don’t see this option here, you can issue an SSL certificate from a different section after the subdomain is created.

Click Create and a subdomain will be added to your server.

Now you have a working subdomain. Great! So lets move ahead and tell WordPress to upload all future images in the new location. Keep cPanel open. We will be coming back here.

pCloud Encrypted Cloud Storage

Step 2: Changing Media Upload Path in WordPress

Log in to your WordPress dashboard. Visit https://yourblog.com/wp-admin/options.php. This is a hidden WordPress options section.

Search for upload_url_path. Enter the subdomain here including https:// and without a slash at the end. I will enter https://media.techstuffer.com here.

Change Media Upload Path in WordPress

Scroll down and save these changes.

From now on, all images will be served from the subdomain. If you upload image2.jpg, it will be available at https://subdomain.yourblog.com/image2.jpg.

Note: If you opt for organising uploads in month-based directories like I do, your images are available at https://subdomain.yourblog.com/2020/09/image2.jpg where 2020 is the year and 09 is the month in which an image was uploaded to WordPress. My images, for instance, are now available at https://media.techstuffer.com/files/uploads/2020/09/image2.jpg.

Step 3: Update Image Paths In Old Blog Posts (Optional)

If your website is already live with images, posts, pages etc. then you should change the path to old images which are still served from the old path. You will not be editing your articles one by one manually, of course. You just need to run an SQL query to make changes in all old blog posts.

For this, go back to cPanel, find phpMyAdmin section and open it. Enter your phpMyAdmin credentials if asked for. From the left panel, find and click the database of your blog.

Find the SQL tab on top and click it. You will be presented with a white text area where SQL queries can be entered. Copy the following text, and paste it in the SQL area. If copy/paste doesn’t work, you should manually type it in the box.

UPDATE wp_posts SET post_content = REPLACE (post_content,’https://yourblog.com/wp-content/uploads/’,’https://subdomain.yourblog.com/’);

Replace subdomain with your subdomain and yourblog.com with the domain of your blog. I will change it to media and techstuffer.com respectively.

Click Go to run the SQL query. It should show the number of rows updated.

If you face trouble running the query, you can also use find and replace option instead:

Select wp_posts table from the left pane, click Search, click Find and Replace. Now enter https://yourblog.com/wp-content/uploads/ in Find and https://subdomain.yourblog.com/ in Replace with. Select post_content in Column.

Find and Replace Query in phpMyAdmin

Now click Go to run the query.

After completing this step, you have updated image paths in old posts with new path. If your old post has an image say image3.png under yourblog.com/wp-content/uploads/image3.png, the URL to this image should be updated to reflect the new path. It should now show the new path as subdomain.yourblog.com/wp-content/uploads/image3.png.

Step 4: Redirecting Old Image Paths to Subdomain (Optional)

By following all steps above, you have not actually changed the directory in which your images are uploaded. You just changed the address where your images are served from. So your images are still being uploaded to wp-content/uploads directory and they can be accessed from there too. You can access image2.jpg from both subdomain.yourblog.com/image2.jpg AND yourblog.com/wp-content/uploads.

But if we keep serving the image from old URLs, then our purpose of serving images from subdomain is not fulfilled. Search engines like Google also have old locations of your images. This is why, we will be redirecting old image locations to their new location. This step is optional if you want images to continue to be served from both the old and new locations.

For this, you will need to access .htaccess file in the directory of your WordPress installation. This is cpanelusername/public_html by default.

So go back to cPanel, find File Manager and open it. Check Show hidden files option and click Go. Now look for .htaccess file in the screen that just opened.

Show Hidden Files in cPanel

If you can’t find .htaccess file, you will need to create one. Click New File from the top panel and type .htaccess under file name. Click create and the new file will be created.

The .htaccess File Shown in cPanel

Now right click on the .htaccess file and click Edit. Copy and paste the following text in the file and save it.

RedirectMatch 301 ^/wp-content/uploads/(.*)$ https://subdomain.yourblog.com/$1

Make required changes to your subdomain and domain and save the file.

Now if you try to access images using old path (yourblog.com/wp-content/uploads/image.jpg, for example), it will be redirected to its new location (subdomain.yourblog.com/image.jpg). This will also help search engines recognize the new path to images of your blog.

Okay, every step needed to serve images from subdomain has been complete. Good work! It’s time to clear any cache you might be serving. Also go ahead and check your page speed score on Pingdom and GTmetrix. They should no longer show flags like Parallelize downloads across hostnames.


Serving Images from A Subdomain: Summing Up

You enthusiastic little thing! See what you did there? You just created a new subdomain and started serving images from it. By doing this, you dramatically improved your page speed score as well as load time. You should no longer see the recommendations to serve images from subdomain or from a cookieless domain.

In addition to serving images from a subdomain, there are other steps you should take in order to improve your WordPress site’s performance. You might want to read my article How I Supercharged My Blog to Score 90+ in Google PageSpeed for that.

That’s all, folks. You were reading How to Serve Images from Subdomain on a WordPress Site. I hope you found this article useful. If you have any question or if you get stuck somewhere, feel free to ask for guidance in comments. Also let me know if I missed something or if this article can be improved.

Support Me: If this article/tutorial helped you today, please consider supporting me and help me run frunction.com

  1. Thank you for a great tutorial. I have do it and worked perfectly but not completely I still get the Parallelize downloads across hostnames Warning
    This I know is due to a directory of thumbnails for my Online Arcade Games Site that are not inside the uploads folder.
    How would I include these
    http://www.3aliens.org/wp-content/thumbs/fog/A/asteroid-mining-empire.jpg
    http://www.3aliens.org/wp-content/thumbs/mochi/A/abe-clone-wars_img1.jpg
    there’s a lot more of them

      1. Generated by a plugin but these are from an old setup the current thumbs are put into the uploads directory.
        I have found a solution to move them into the uploads directory and change the posts image urls a lot of work so I will leave that for when I have free time.
        thanks for getting back to me.

  2. For this, and my mistake if I missed it in the tutorial itself, but would the existing uploads directory have to be moved into the new sub domain so that past images work normally? Thanks.

    1. I’m sorry for replying late and I hope you’ve found your answer already.
      You are not actually creating a new directory. You are keeping images in the same directory (wp-content/uploads) and just changing the domain to a sub-domain. So you will not need to move images anywhere.
      Just follow Step 3 and 4 so images are served from new location.

      1. Thanks! I went back through after commenting and read more thoroughly, I appreciate your help though as well as the article itself.

  3. Hi Parvey,

    Thanks for the instructions and useful tips. I am trying to do the trick now but obviously on the latest WP version 4.9.8. I also use Siteground. I have created the subdomain without issues and changed the url upload path but I get a syntax error message when I try to run the SQL query, probably due to the newer version of SQL that i have.

    Also I realised then that some images are now randomly showing broken links. I reverted to the classic media path to fix this, but still keen to get this going. Could you assist please?

    Thanks
    Thomas

    1. Hi Thomas.

      My blog used to run on SiteGround and now I’m using DreamHost. I am using the same setup as descibed in this post to serve images from a subdomain.

      I’m not sure if the newer version of SQL is causing the error because I recently ran the query without problem.

      I suggest you to take a look at the query for any breaks while copy/pasting.

  4. Hello! I have two questions:

    1. Is this tutorial still up to date?
    2. Can I completely remove /uploads folder after completing this tutorial?

    Best regards,
    Kacper

    1. Hi Kacper.
      Yes, the tutorial is up to date and working.
      You don’t actually remove /uploads directory. Your files are still uploaded to wp-content/uploads. What changes is the URL your files are served from.

  5. Thank you!
    I already moved my images to subdomain, but I can’t replace old images. When I typed query in Phpmyadmin, this error showed up.: #1064 – You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ‘://mysite.com/wp-content/uploads/’,’http://subdomain.mysite.coml/media/’)’ at line 1
    Do you have any idea what I should do?
    Thanks,
    Kacper

  6. Make sure you are entering the path correctly. Look for possible spaces or typos.
    Also, why does your URL look like subdomain.mysite.com/media/. It should be simply subdomain.mysite.com/

  7. Sir it shows me error in Step 3: Update Image Paths In Old Blog Posts:
    #1064 – You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ‘://kashpick.com/wp-content/uploads/’,’http://media.kashpick.com/’)’ at line 1

  8. Hi, I could not open your site to check it. It looks like it”s under development or a new webiste. If it’s a new website, you don’t need to follow step 3 as you won’t have any images on the old path.

    Make sure there are no unneccessary spaces in the query or try to type it manually. Also, I am not sure how this works with MariaDB.

  9. I’ve followed this tutorial and changed everything. The URL is pointing to my img.subdomain.com but I’m still getting 500 error and no files are displayed in WordPress too. The URLs are changed in the DB and redirect is done I see that the URL is pointing to the right subdomain. Can you please let me know what am I doing wrong?

    1. Do you receive error 500 on your main domain or only on subdomain while trying to access files from the new path?
      Your new path should look like subdomain.domain.com/wp-content/uploads/file.jpg and the change has to be made in WordPress options area for the images to be displayed.

  10. If you’re having problems with SQL syntax errors, change the single quote/apostrophe. When I copied and pasted it, the fancy version came over. I removed those and typed ‘ manually and it worked.

  11. Hi Parvez,

    Thanks for sharing this post. This post is really helpful in serving images from Sub Domain.

    However I am facing a pecular issue with the end result. Mine is a new blog and no old Posts are there.
    Now the problem is, if I leave the option upload_url_path as blank, images are visible. But the image url is like https://www.domain.com/wp-content/uploads/img1.jpg

    If I give upload_url_path = https://sub.domain.com, images are not visible in Media Library. Where as the images are there in backend, blank empty squares in library. While browsing permalink post only, points to https://sub.domain.com/img1.jpg

    What I have done so-far?
    1. Changed the file permission to 644/755.
    2. In WP Config I tried adding the following Line to change the default folder along with creation & changing Document Root path.
    define( ‘UPLOADS’, ”.’cdn’ );
    3. Installed & tried Force Regenerate Thumbnails plugin.

    Looking forward for your quick response.

    Thanks

    1. Hi Vivek.
      Are you able to browse an image at https://sub.domain.com/img1.jpg? If yes, then you should check the upload_URL_path. It should not have / at the end.
      It is possible that the subdomain does not have SSL certificate issued to it. In that case, issue it from cPanel and try to browse the image from subdomain.
      If both these things are already correct, upload a new image to library and see which URL it carries and open that link to see if that work.
      If all seems right, double check your setup and start over if needed.

      1. Hi Parvez,

        Thanks for your response.

        If I leave upload_URL_path blank, images are visible in library, can add to the post & visible in posts as well. Image URL is https://www.domain.com/media/img1.jpg

        If I fill upload_URL_path with https://sub.domain.com, blank squares are visible only. In Firefox, blank square is visible and points to https://sub.domain.com/img1.jpg .

        My hosting plan is SSD standard.
        https://www.globehost.com/web-hosting

        Not sure about SSL certificate to subdomain. Can google it and install.

        Thanks

        1. Check the URL of uploaded image after changing the URL path. If it says https://sub.domain.com/img1.jpg, your setup is correct and need SSL (because you are using https). Also check by putting http instead of https under upload_url_path.
          The reason you see blank squares could mean either SSL cert is missing or there is an error in the subdomain setup.

          1. Hi,

            I have another SSL subdomain, I pointed to the same. Still the result is same. I guess its because of Shared hosting. 🙁

            With SSL Sub domain or without SSL sub domain, the result is same.

  12. Hi Parvez,

    I am able to resolve the issue.

    It wasn’t the issue of SSL or anything else.

    When I signed up for Cloudflare, I replaced the cloudflare DNS with my hosting provider DNS in my domain registrar. After 3 days or rigorous testing and resetting the all the 4 DNS(2 from Cloudflare & 2 from hosting provider) the issue was resolved.

    Thanks Again
    Vivek

  13. hi, i follow the steps successfully, but the images are not showing in media folder, and not showing on the product page.

    1. Hi Adnan. For this to work successfully, makes sure that: 1) If your website is served over https, a valid SSL certificate is installed for subdomain. 2) The upload path does not have trailing slash or space (Step 2). 3) The subdomain is pointing to wp-content/uploads.

      Upload an image via Media, try to browse it and see which error you get (https error, error 404 or something else).

  14. Hi Parvez. 1 ) Yes website is served over https, and subdomain URL includes https but the lock sign in address bar has orange info icon over lock that says “Connection not secure” on subdomain https://subdoamin.domain.com/

    2) how and where to check the upload path have space or trailing slash or not
    3) I’m not sure about this as i have not touch this section yet, how do that.

    i upload image via media, 1) after uploading image from media the image is always show as white color, meaning the image have no preview. when tried to view image with direct link of upload path https://subdomain.domain.com/image.jpg error 404 is there. thanks

  15. Hi Again, i was reading the article again, let me tell you in detail. I’m with siteground. i have three domains/projects on my hosting plan called pro1, pro2 and pro3. i am working to serve images from subdomain for pro3. As mentioned in the article i have also changed default location of wp-content/uploads to data/data1 while i was creating subdomain i enter name of subdomain (images) and select appropriate domain. in the Document Root option it showed public_html/images instead public_html/data/data1 under Document Root as mentioned in article. Now I’m worried i have made subdomaim properly or not.

    another thing when i enter UPDATE wp_posts SET post_content = REPLACE (post_content,’http://yourblog.com/wp-content/uploads/’,’http://subdomain.yourblog.com/’); command in SQL it return syntax error 1064 then i followed second way, search and replace even this option could not find anything hence i leave it thing there could be noting to replace.

    i don’t know if I’m doing right or no. please help.

    1. Remove the subdomain. Add it again and enter the correct path – in your case, it should be public_html/data/data1 (because you have changed your upload directory).

      Also, the subdomain must have a valid SSL certificate otherwise it will show blanks instead of images. If you browse https://images.pro3.com/2020/09/image1.jpg, for example, it should show you the image without SSL warning.

      Hope this helps.

    1. 403 error could be because there’s actually no website at the subdomain or because WordPress uploads directory is restricted by default. I don’t think you need subdomain.domain.com to open. Its purpose is just to serve images and it will work as long as the rest of the setup is correct.

      The /2020/09/image.jpeg path will work only if ‘Organize my uploads into month- and year-based folders’ option is turned on under Settings > Media. Otherwise the path will be subdomain.domain.com/image.jpg. If this option is on, try visiting Settings > Permalinks and save as it is. I am not sure if it will work in this case but it helps in other cases.

      If nothing works, it could be a server configuration, php or some other issue that I don’t know about.

  16. Ok about 403 error i understand. no i turned off Organize my uploads into month- and year-based folders in settings > Media and upload a new picture now the URL is https://subdomain.domain.com/image.jpg but still it is not showing by direct link, there is 500 error on this page also there are no images showing in media upload dialogue box.

    i guess now the images are perfectly uploading on subdomain.

    i checked the new images path on cPanel > file manager, URL is home/public_html/domain.com

    1. Rename .htaccess file to .htaccess.bkp and visit your WordPress website again. A new .htaccess file should be created automatically and should solve error 500. You may have to enable ‘show hidden files’ option somewhere in file manager if you don’t see .htaccess file.

      Sometimes php configuration also causes error 500. In cPanel, change the php version of your subdomain to a different one, save it. Switch it back to the version it was before. Save again. Try loading your image once again.

  17. non of the tips help me. same results. i think i should leave and switch back as it seems above difficult for me to solve. thanks for the help.

    1. Too bad it didn’t work out for you, Adnan. I would suggest referring to other guides on this topic. I have tested this with different hosts, control panels and WordPress versions. In all cases it works and it’s working on this blog, too.

  18. i already follow 3 more blogs, same code is there and same result for me. one last try. i was checking with wp-config.php there i see some random codes then i remember i had also changed wp-content folder name to (cont) and plugins folder name to (mod). the code are

    define( ‘WP_PLUGIN_DIR’, dirname(__FILE__) . ‘/cont/mod’ );
    define( ‘WP_PLUGIN_URL’, ‘https://domain.com/cont/mod’ );

    define( ‘WP_CONTENT_FOLDERNAME’, ‘cont’ );
    define( ‘WP_CONTENT_DIR’, ABSPATH . WP_CONTENT_FOLDERNAME);
    define( ‘WP_SITEURL’,’https://’ . $_SERVER[‘HTTP_HOST’] . ‘/’);
    define( ‘WP_CONTENT_URL’, WP_SITEURL . WP_CONTENT_FOLDERNAME);

    these are working fine.. if you can look deep is these codes, are the code making problem for images delivering from subdomain. thanks

    P.S: if anyone want to change wp-content folder and plugin folder use these codes, do also change the both folders name as well.

Your email address will not be published. Required fields are marked *