Scott Hanselman

Real World Cloud Migrations: CDNs are an easy improvement to legacy apps

July 05, 2019 Comment on this post [4] Posted in Azure
Sponsored By

I'm doing a quiet backend migration/update to my family of sites. If I do it right, there will be minimal disruption. Even though I'm a one person show (plus Mandy my podcast editor) the Cloud lets me manage digital assets like I'm a whole company with an IT department. Sure, I could FTP files directly into production, but why do that when I've got free/cheap stuff like Azure DevOps.

As I'm one person, I do want to keep costs down whenever possible and I've said so in my "Penny Pinching in the Cloud" series. However, I do pay for value, so I'll try to keep costs down whenever possible, but I will pay for things I feel are useful or provide me with a quality product and/or save me time and hassle. For example, Azure Pipelines gives one free Microsoft-hosted CI/CD pipeline and 1 hosted job with 1800 minutes a month. This should be more than enough for my set up.

Additionally, sometimes I'll shift costs in order to both save money and improve performance as when I moved my Podcast's image hosting over to an Azure CDN in 2013. Fast forward 6 years and since I'm doing this larger migration, I wanted to see how easy it would be to migrate even more of my static assets to a CDN.

Make a Storage Account and ensure that its Access Level is Public if you intend folks to be able to read from it over HTTP GETs.

Public Access Level

With in the Azure Portal you can make a CDN Profile that uses Microsoft, Akamai, or Verizon for the actual Content Distribution Network. I picked Microsoft's because I have experience with Akamai and Verizon (they were solid) and I wanted to see how the new Microsoft one does. It claims to put content within 50ms of 60 countries.

You'll have a CDN endpoint host name that points to an Origin. That Origin is the Origin of your content. The Origin can be an existing place you have stuff so the CDN will basically check there first, cache things, then serve the content. Or it can be an existing WebApp or in my case, Storage.

Azure Storage Accounts for my blog

I didn't want to make things too complex, so I have a single Storage Account with a few containers. Then I mapped custom endpoints for both my blog AND my podcast, but they share the same storage. I also took advantage of the free SSL Certs so and are both SSL. Gotta get those "A" grades from right?

Custom domains for my CDN

Then, just grab the Azure Storage Explorer. It's free and cross platform. In fact, you can get Storage Explorer as an app that runs locally, or you can check it out in the Azure  Portal/in-browser as well, here. I've uploaded all my main assets (images used in my CSS, blog, headers, etc).

I've settled on a basic scheme where anything that was "/images/foo.png" is now "" or /main/ or /podcast/ depending on who is using it. This made search and replaces reliable and easy.

It's truly a less-than-an-hour operation to enable a CDN on an existing site. While I've chose to use Azure Storage as my backing store, you can just use your existing site's /images folder and just change your markup to pull from the CDN's URL. I recommend you make a simple or This can also easily be enabled with a CNAME in less than an hour. Having your images at another URL via a subdomain CNAME also allows for even more download parallelism from the browser.

This is all in my Staging so you won't see it quite yet until I flip the switch on the whole migration.

Exploring future possibilities for dynamic image content

I haven't yet moved all my blog content images (a few gigs, but many thousands of images) to a CDN as I don't want to change my existing publishing workflow with Open Live Writer. I'm considering a flow that keeps the images uploading to the Web App but then using the Custom Origin Path options in the Azure CDN that will have images get picked up Web App then get served by the CDN. In order to manage 17 years of images though, I'd need to catch URLs like this:

and redirect them to

As I see it, there's a few options to get images from a GET of /blog/content/binary to be served by a CDN:

  • Dynamically Rewrite the URLs on the way OUT (as the HTML is generated)
    • CPU expensive, but ya it's cached in my WebApp
  • Rewriting Middleware to redirect (301?) requests to the new images location
    • Easiest option, but costs everyone a 301 on all image GETs
  • Programmatically change the stored markup (basically forloop over my "database," search and replace, AND ensure future images use this new URL)
    • A hassle, but a one time hassle
    • Not sure about future images, I might have to change my publishing flow AND run the process on new posts occasionally.

What are your thoughts on if I should go all the way and manage EVERY blog image vs the low hanging fruit of shared static assets? Worth it, or overkill?

The learning process continues!

Sponsor: Seq delivers the diagnostics, dashboarding, and alerting capabilities needed by modern development teams - all on your infrastructure. Download now.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Hosting By
Hosted in an Azure App Service
July 08, 2019 9:54
We are working with Azure on the enterprise level - and I agree, it saves a lot of many. We reduced our costs almost twice by moving to cloud. And I really love working with Azure (even comparing to all the buzz around AWS).

However the further we go the more I tend to see that for private hosting Azure is way too expensive. E.g. our AppInsights instances are eating about 100$ per month... Just logging/monitoring. Of course it's nothing for enterprise, but for private usage I would think twice if it's important to log something so hardly for me.
For enterprise there are a lot of other savers, like maintenance costs, licenses, etc. However for private usage - it's not something significant in regards to maintaining.

I agree, it's up to you what balance you choose, which Azure services you use and how you use them, but for example.. I'm running quite small "private" app, which is not massively used WebApp, with small DB. And it is eating almost whole my MSDN subscription given monthly quote (about 100$). For private hosting (e.g. Wordpress-level blog, not widely-known), I guess even 20-30$ is already expensive.

Maybe it's just a feeling, or maybe I'm doing something wrong, or maybe it's just historically, that .NET hosting is expensive. Can you elaborate something on it, dispel my doubts about it? ;)

It would be also really interesting if you could present your numbers when you done migrating to cloud. :)
July 08, 2019 18:43
I think that keeping all blog images on CDN is overkill. I keep on CDN only those on home and categories pages + logo.
July 09, 2019 14:04
I agree with Aleksandras, the amount of times I've had bill shock for minor things put me off Azure, much as I like it as a platform. I really wish they'd offer a tiered setup where you can have a certain amount of functionality for a set price. Many smaller businesses/personal setups just need the bare minimum so this should be free money for Microsoft
July 10, 2019 3:57
An Azure VM is certainly pricey for a low-traffic, personal site.

OTOH, if you can adapt your code to serverless (no web server - your code only runs when its invoked), I've been hearing a lot about Azure Functions or AWS Lambda as potential pay-for-what-you-use solutions.

One model, for dynamic functionality, would be a function which responds to a URL and returns something suitable for display in the browser (I'm glossing over the configuration). Alternatively, you could have the function code write static content to blob storage and serve it from there. (I've done the latter, serving content from an S3 bucket and believe Azure recently introduced something to it.)

Azure Functions:


Comments are closed.

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.