Optimal (Free) Blogging for Programmers: Hexo + Surge

Why?

Most programmers have more ideas than they know what to do with, more project ideas than they can ever get around to. Spending your life reinventing the blog doesn’t make sense. Just get the blog up in a day and write stuff and go code something more important.

Hexo generates a static ‘public’ folder that you just serve. No hackable wordpress server with constant security updates and gross PHP plugin mess needed. No need to deal with the complexity and/or cost of a server to run ghost.

That generated static public folder works perfect for surge.sh, which gives you free high speed hosting for static sites with an instantly incredibly simple deploy process, and even allows custom domains and subdomains for free.

Hexo is dirt simple. If you’re a competent JS programmer, you can reverse engineer it by just poking around. The three templates I’ve worked with and deployed at this point have all used EJS templates (other template languages are also supported), which I’d never seen before, but have learned just by playing with the code as it exists, supplemented with just some occasional googling when I get stuck. EJS has its flaws (I cannot for the life of me understand why line-by-line bracketing of JS is necessary, and the error handling is a bit painful), but overall it’s an intuitive, solid option that works well and does what it should do–deal with the problem of HTML cleanly. It’s not quite as nice as JSX or mithril, but I think the learning curve is lower and again, certainly for a blog, it’s far more than powerful enough.

Posts are written in markdown with YAML properties. Adding custom pages is as simple as adding a named folder with a named file, and a corresponding EJS template. Basic blog functions like tags, archives, etc. are usually built into the theme in an easy to understand way.

Want to build your own theme? Don’y like any of the ones you can find online? I haven’t done that myself yet, but I can tell it would be extremely easy. I have seen a free html5up.net theme converted to a hexo themes, as well as wordpress themes that have been adapted. It’s just a matter of knowing where to put the files, which you can learn by just downloading and poking around in an existing theme, and organizing the HTML into EJS files (which, as one of the strengths of EJS, is easy to do since HTML is valid EJS).

Hexo is also easy to add plugins to, to do any programmatic feature before deploy that you’d like. There is a large body of existing plugins for Hexo. I’ve only used one or two, but so far they’ve worked well for me.

The Hexo CLI allows quick local serving and auto-rebuilds on code editing, too, right out of the box.

Most themes seem to support disqus comments, if that matters to you, though I don’t like disqus and haven’t felt the need to add comments yet.

Combining these together, we get:

  • A free solution
  • An easily customizable, clean, open source solution
  • An easily deployable solution
  • A fast start-to-mvp solution
  • A out-of-thebox pleasant development process
  • A secure solution
  • A solution that is as feature-rich as you desire

How?

Requirements

I assume you have node.js (+ npm) and git, assume you’re using github, and are on a linux install (though it shouldn’t be much different for mac).

Install + Initialize Hexo

Instructions for that can be found here. As of this writing, that’s:

1
2
3
hexo init <hexo_folder>
cd <hexo_folder>
npm install

Pick a theme

Browse here, or use Google to look around for other lists. We’re going to work with Edinburgh, a theme I’ve always found attractive, but never quite right for my needs so far. As you see in its instructions, you just need to git clone the repo to the <hexo_folder>/source/themes folder of your new hexo project.

1
2
cd <hexo_folder>/source/themes
git clone https://github.com/sharvaridesai/hexo-theme-edinburgh themes/edinburgh

As in instructions in that repo point out, we then want to set the theme for our hexo project to be the theme we just ‘installed’. Go into <hexo_folder>/_config.yml and set the theme property to theme: edinburgh.

Push your new repo to git

Make the repo online on github first.
Then push the folder up to github.

Subprojects

Note: your theme is, by default, a subproject in git, since we used git clone for it. If you keep it that way, then updating the theme later becomes much more manageable, if updates occur. It also makes sharing your changes to the theme code itself shareable, later, if you so choose, and would allow pushing bugfixes and updates up to the original blog author if they’re open to pull requests. It’s also slightly better code separation, in theory.

The only cost is a small bit of complexity in your git usage–both for committing and collaborating.

I’d never used subprojects before, but they’re actually quite simple. Just make a second git repo for the theme itself, then cd into your theme you cloned and push the theme itself up to your new repo. (The alternative would, of course, be to fork the theme in advance and clone it down from your own fork).

If you don’t like the idea of any added complexity and want to just make the entire blog one complete single repo, you’ll need to delete the .git hidden folder. If you wait to do this later, the external repo can get weird about it.

Get surge

Hop on over to surge.sh and follow the instructions there. It’s literally a couple commands in the terminal, should take less than 5 minutes.

old post text REMOVE ME

ethical heroku warmup
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<script>
const pingSite = site => {
var oReq = new XMLHttpRequest();
oReq.open("GET", site);
oReq.send();
};

const pingHerokuSites = () => {
const sites = [
'http://mindseal.kylebaker.io',
'http://zebrabowling.kylebaker.io'
];
sites.forEach(pingSite);
};

pingHerokuSites();
</script>

Note that we’re not handling the response, since we don’t care about the response.

Of course, we’ll get a nasty CORS error in the console anyways–and sadly, there’s no way to catch that error. Security choice on Chrome’s part.

Not a big deal… unless you’re a programmer and expect people to open the console and poke around in your site. :)

Luckily, the fix is fairly simple. Enable CORS for a single endpoint on your heroku projects. If we’re running a small node.js server with express.js, you just need to yarn add cors, and then add something like this to your server code:

preventing CORS error server-side in express
1
2
3
4
5
var cors = require('cors');

app.get('/warmup', cors(), (req,res) => {
res.send("warming up");
});

Now just go back and add /warmup to the URLs in your sites array in the client code, and you’ll get lovely, quiet wake-ups for your Heroku dynos in the most ethical way possible.

I tried ZEIT’s now service, which is like a hybrid of Surge’s beautiful minimalist command-line deployment interface and Heroku’s free server-side hosting, but they of course do the same dyno-sleeping Heroku does for free plans. They also have a 1mb file limit, 100mb project limit, and seem to be a little slower than Heroku in my tests. Still, I’ll keep my eye on them in the future, they seem like a great company and they’re improving rapidly–I watched them respond to issues in their slack channel, and I was really impressed with the team. They also, for instance, give free hosting to jsperf–they’re clearly interested in giving back to the community, and their deploy process is beautiful. Unfortunately, free custom subdomains are a priority for me, which, unlike heroku and surge.sh, they don’t offer–otherwise, I’d likely be using them for zebrabowling.

Doe you feel some sense of faint familiarity? You’re actually only one step away from a microservice or serverless architecture, depending on your server needs.

Unlike AWS, which is free for a year and then just really cheap, Google Cloud now offers a free-forever level of service, which includes enough hours of service per month to keep an always-awake dyno of their lowest offered spec running non-stop, month after month. While my earlier projects mindseal and Zebra Bowling are both hosted on Heroku because they predate Google Cloud’s free tier, I only recently got around to deploying zipcoder, and because of the 70mb JSON file I use in that project, decided to go ahead and deploy it there to try out their new service.

It was a much larger hassle to get up and running than something like zeit, but once you have it up it’s an always-awake dyno. Eventually I may move all my projects to that little dyno. The deployment is a little more manual, but I could of course automate that if I wanted to with a little more work myself (so, manual automation vs. automatic automation?). Still, it’s just a few commands: git push, ssh, cd project git pull pm2 restart (extremely abbreviated, but you get the idea).

The main limitation for most users, I think, will be the 600mb of ram. Zipcoder uses about 150mb~ because it stores a tens of thousands of zipcode polygons as millions of coordinates in GeoJSON in memory in lieu of a database for both simplicity and speed, but mindseal and Zebra Bowling are likely sub-20mb node processes. I have nginx reverse proxying and pm2 managing my node process, so it would be relatively trivial to get two more apps up there. Of course, that said, you have to set all that up and manage it yourself.

Google Cloud Services’ free tier actually gives you many other things for free, as well.

If I wanted to free up that f1-micro, I could turn my zipcoder project into a true microservice architecture. To do this for free, we’d use GCS’ “Functions” (their equivalent of AWS’ lambda) service, and their Datastore service (their free NoSQL service). You get 2 million invocations/1 million seconds with the Functions service per month, and with Datastore you get 1 GB of NoSQL DB space and 50k/20k read/write per month.

The tradeoffs here are speed & availability, simplicity, automation, and design complexity.

You: Want the easiest option (that’s also pretty fast and highly available)?
Answer: Make it as a pure front-end static site and host it on surge.

You: But I need a server, a static site won’t cut it for me.
Answer: Heroku can do it all, but it’ll be slow for initial start up.

You: That slow initial load is a deal-breaker, but I love the easy deployment tools heroku gives me.
Answer: Mix it up–handle CORS, host the front-end on surge, only host the custom server stuff on heroku.

You: Hmmm… I don’t like the idea of separate deploys like that, I’d prefer to keep it all together.
Answer: Google Cloud Services f1-micro is a straight-up free server, with constant availability.

You: But I can only have one f1-micro, and the ram is pretty small, it’ll fall over under load, etc… I want more.
Answer: Break your project up properly. Use microservices with Google Cloud Services Functions and store stuff in Datastore. Free to start, and built to auto-scale from the ground up.

You: Microservices are a bit too agressively small, I have some more serious crunching to do
Answer: There’s an in-between service that blurs the lines from Google you might be interested in–the f1-micro is a part of Google Compute Engine, but there’s another service in between that and Google Function, and that’s Google App Engine. For storage, too, they have various options, and a substantial amount of space free right off the bat.

Whatever your needs, using these resources and strategies, you should be able to get any project off the ground.