Converting from Word Press to Static Content Site
Monday, January 1, 2018
My salvoz.com blog site went through numerous iterations over the years, both in hosting and blogging platform. It initially was self-hosted on DasBlog, then moved to GoDaddy, and finally to WordPress and MediaTemple for hosting.
WordPress and MediaTemple were okay, but I wasn't using, nor did I need the full capabilities of WordPress. In fact, most of the plug-ins I used were for security and performance improvements. I also wanted to redirect the MediaTemple hosting fees towards another project.
Therefore, I decided to jump on the Static Content generator bandwagon. The site consists of a collection of files (markdown, html templates, meta-data) and is built whenever a change is made to static HTML files, and finally deployed. The advantages are raw performance and little concern for site security.
- Static Content Generator: Wyam
- Comments: Disqus
- Host: Netlify
- Build: Cake and TeamCity
- WordPress Export: Jekyll Exporter
- Content Editor: VS Code
Exporting the Site
I started out by using WinSCP to download my entire site from Media Temple as a backup and then converted my site to use Disqus for comments. This was straight-forward - I just needed to install the Disqus WordPress plugin and follow the migration steps. I then installed Jekyll Exporter to export the content of my site to Jekyll files.
I ran into a few problems around WordPress and PHP with Jekyll Exporter, mainly the error "cannot use output buffering in output buffering display handlers". I tried the following to resolve this issue:
- Upgraded all plug-ins
- Upgraded WordPress
- Confirmed I was running a recent version of PHP
- Set debug mode in wp-config.php
- define('WP_DEBUG', true);
- Increased the memory limit, also in wp-config.php
- define('WP_MEMORY_LIMIT', '512M'); //What finally fixed it.
With my images downloaded via WinSCP and a collection of Jekyll markdown files, I was ready to start the conversion to Wyam.
Following the instructions I installed Wyam using Chocolatey.
choco install Wyam -s https://www.nuget.org/api/v2/
Next I created a new site using the blog recipe.
wyam new -r blog
And to run the site in preview mode, with live re-load
wyam -r blog -p -w
After I had the basic folder structure setup by Wyam, I went about importing my content. First, I made sure that I had Git LFS setup for my repository so images and binary files where handled more efficiently in Git. Ultimately, I decided to upload all of my old images to Azure Blog Storage instead of redeploying them with the site every time.
I wrote code to convert the Jekyll meta-data in the markdown posts to Wyam and update image links. I defined a standard for code snippets in posts; I use the markdown pre/code identifier ( ``` ) and highlight.js, and a div tag with a little extra formatting for margins and padding.
The most time consuming part of the migration was reviewing all the old posts and cleaning up the code snippets and lists (the Jekyll exporter seemed to have a problem exporting these).
Originally I planned to host the site on Azure Function proxies ("free consumption based plan") in front of Azure Blob storage. Azure Function proxies handle the following:
- Lack of default document support in Blob Storage
- Custom domain with SSL support
- Redirects from my old blog URL format to the new
Mark Heath has a write-up on how to use Azure Functions to accomplish the above tasks, and was my initial inspiration for using Azure. I deployed my entire site to blob storage and DNS cut-over before I decided to switch to Netlify.
Netlify is where the Wyam site is hosted, as well as the lead maintainer's blog. It is a hosting provider that is focused on static sites, and offers a generous free hosting plan for even commercial endeavors. The Netlify documentation is a great place to see all of their features, but the ones I was most interested in are:
- Robust Redirect and Rewrite Rules
- Custom 404 page support
- Free SSL on Custom Domains (using Let's Encrypt)
- Hands-off deployment to their CDN for an extra performance boost
- Support for command line deployments
The redirect and rewrite rules are pretty important to get your root domain to redirect to www and vice-versa depending on what you want your primary URL to be. For this site, I've been using the root of the domain, salvoz.com for several years. I have another site that I converted to Wyam and hosted on Netlify and decided to go with www. I discovered that having a DNS CNAME record for your root domain is technically not allowed as per the DNS spec; however, some Name Server providers, such as ZoneEdit and Netlify allow this. Azure DNS prevents it, and while NameCheap allows you to do this, if you have a MX record pointing at your root domain, it will not resolve with a CNAME also pointing at the root.
Build and Deployment
I use Cake to write my build scripts, and Team City to run the Cake Script whenever the master branch of my repository is updated. As I mentioned earlier, I had my site deploying to Azure before Netlify, and I still have my build script and Team City setup to support this. In fact, I still deploy to both locations just to keep track of the progress of Azure Blobs as a static content site.
There is a Cake add-in for Wyam, which is well-documented, and you can look at the Wyam github repository for an example of building and deploying to Netlify, which I followed for the most part. I ended up with a PowerShell script invoked from Cake to upload to Netlify. Using Curl, as the Wyam site does, turned into a bit of a hassle on my Windows-based build agents. Once I installed Curl using Chocolatey, I got certification validation errors, so I decided to go with something more native to Windows.
Also as part of my Cake script, I set keys for AppInsights and Google Analytics. You can see in my script that I pass the Azure Storage account key and Netlify API token in as parameters. These are set as password fields in Team City to afford some level of protection. The keys for AppInsights and Google Analytics I leave in the build script, since they are visible to anyone who looks at the source of the published web pages.
Rather then display my full Cake script here, I will simply link to a copy.
Once the site was up and running with the new URLs for the posts, I updated my Disqus comments accordingly. Disqus has 3 ways you can update the comment to post association, which include: Manual, CSV File, and an Automated Crawl. Manual and CSV should be self explanatory. The automated crawl, which is the method I used, require that you have 301 redirects setup from your posts' old URLs to their new URLs, which I did. So after a couple of hours, I had all my comments updated and showing up on my posts once again.
While it ended up to be a little more work then I thought, I am pleased with how everything turned out. While I've used VS Code a bit for editing my Cake scripts, I've become quite happy working inside VS Code during this migration project. A big thanks goes out to my wife who spent considerable time going through the old posts.