WordPress vs Hugo

This is a popular old blog post, I have moved back to WordPress now. Posting this here with updates about why I moved back to WordPress.

Managing WordPress can get time consuming. I have tried to move to static website several times but kept going back to WordPress. But there are several advantages of static sites generators that I finally moved for good. I am also advising a lot of my clients to use Hugo especially when they know that they will rarely ever update their sites.

Here are some of main advantages of Hugo (or other static site generators) vs WordPress and other CMS.

No System Administration

In order to run WordPress, you need a web server. You will need to configure it, install database and PHP. A server hosting a website is always connected to Internet. So it is always available target for hackers. This means you need to secure the server properly and keep it up to date.

When using Hugo, you don’t need PHP and database. All you need is a web server, this reduces attack surface area significantly. As long as you don’t have any extra software running on the server, all you need to worry web server being properly secured.

Of course, you can use shared hosting for WordPress and avoid all headaches of System Administration.

No WordPress or plug-ins to update

The one huge advantage of Hugo is that there is no code to execute. Well no code on server to execute. You may still have some Javascript. But this Javascript code executes in a user’s browser and unlikely to be easily exploitable.

WordPress & plugins executes code on a server. This mean bugs in WordPress can be exploited to access your server or even install malicious code. That code can further infect your users’ machines. I have spend hours and hours restoring websites for clients when their websites got hacked. Of course, you can avoid this by keeping your WordPress installation up to date and carefully choosing plugins & themes. But this means regularly logging in the WordPress admin interface and applying any new updates.

On other hand, you will never have to update Hugo generated site once generated. Only time you will update is to change some content on it.

Simpler Backups

Normally, I don’t give admin login for WordPress & server because of risk involved with client installing bad plugin or messing up something else. I used to manage backups myself.

But I have tried to restore WordPress sites that were developed by someone else. Backup were too old, theme didn’t work with current version of WordPress. Some plugins were not in backup file and are no longer available. And the worst backup file contained viruses & malware.

With Hugo, client gets zip file but it includes full functioning website. While it is still technical, but it should be a lot simpler to restore a static website. It can be as simple as uploading a folder to web server.

No Updates that Break your Site

Since static sites don’t need to be updated to secure against hacks, there is very little worry about any update that will break theme. If you don’t update your Hugo version, you should get same results if you run it against same source files.

In WordPress land, I have seen some people not updating their website for months or years and then when they do, it breaks their theme or plugins.

Where WordPress Wins

There is one area where Hugo cannot touch WordPress. When client is actually using their WordPress site as blog or if they regularly post new content. With static sites, client will need to be technical enough to use markdown and git. Or they will email posts to you.

In my experience though most people rarely update their websites regularly enough to warrant all the extra headache involved with hosting WordPress.

My Hugo Workflow

Personally, I moved my blogs to Hugo because of above reasons and I like the new workflow. My workflow consist of

  1. Email myself a blog idea as I get it.
  2. Write a rough draft either in iA Writer on iPad or skip this step and
  3. Write final version in Sublime Text on my laptop
  4. Commit and push

I love iA Writer for its typewriter mode where the line that you are writing stays in the middle of screen rather than at the bottom.

Setup Outgoing Email on Lightsail Ubuntu VPS

I followed instructions here: https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-postfix-as-a-send-only-smtp-server-on-ubuntu-18-04

Everything seemed okay but email were not getting delivered. Logs showed me that smtp connections were timing out:

tail -f /var/log/mail.log
May  3 12:28:10 postfix/smtp[3160]: connect to gmail-smtp-in.l.google.com[]:25: Connection timed out
May  3 12:28:10  postfix/smtp[3160]: connect to alt1.gmail-smtp-in.l.google.com[2800:3f0:4003:c00::1a]:25: Network is unreachable
May  3 12:28:40 postfix/smtp[3160]: 4984C41A1E: to=<xxxx@gmail.com>, relay=none, delay=3246, delays=3186/0.01/60/0, dsn=4.4.1, status=deferred (connect to alt2.gmail-smtp-in.l.google.com[2a00:1450:400b:c00::1a]:25: Network is unreachable)

However, I could ping any of above ip addresses just fine.

Next step was to see if ip address of my VPS was blacklisted in RBLs, I used https://mxtoolbox.com/blacklists.aspx. None of my ip addresses were in any black list.

Port 25 was open in firewall, both on server and in Lightsail’s networking UI.

After spending another hour or so troubleshooting, I found this thread: https://forums.aws.amazon.com/thread.jspa?threadID=316397. It seems AWS/Lightsail have recently started to throttle outgoing emails, but by throttling they meant completely blocking it. You need to open a support ticket to remove these limits here: https://console.aws.amazon.com/support/contacts?#/rdns-limits

So I submitted my request, hopefully, this will resolve the issue.

Error: xcode-select: error: tool ‘xcodebuild’ requires Xcode, but active developer directory is a command line tools instance

This is from my old blog, it is one of more popular post so copying here. I had been playing with Cordova then and was getting this error when building iOS version:

Error: xcode-select: error: tool 'xcodebuild' requires Xcode, but active developer directory is a command line tools instance

Full re-install of Xcode didn’t fix this error. The solution was to run following command:

sudo xcode-select --switch /Applications/Xcode-beta.app/Contents/Developer

Hello World, Again!

As a child, I fell in love with video games and wanted to make my own video games. This is the main reason why I got into programming.

While in college I made a few games/demos using DirectX and random tutorials. Then I applied for job at many game studios but never heard back from them. Then life got in the way, I got a regular programming job. Then I got a startup bug and worked on various side-projects. After various failure of programming side-projects, I decided I should have non-programming side-project/hustle. So I worked as a part-time photographer and got my real estate license.

Now almost 20 years later since first I made games using tutorials, I am again learning game programming.

Over last few weeks, I did research on various game engines, and finally settled on Godot and Flutter. Godot looks like is a beginner friendly game engine. Whereas Flutter is not really a game engine, but it seems perfect for some of simpler educational type games that I am envisioning.

Another thing I did is moving back to WordPress for blogging. I am hoping to write more often about my indie programming and game development journey ahead. I am slowly copying my older popular posts from Hugo but mostly starting over here.

Wealth Lab Pro Earning Play Screener

This is a quick script that I use to find options to buy or sell.

using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using WealthLab;
using WealthLab.Indicators;
using Community.Components;

namespace WealthLab.Strategies
	public class MyStrategy : WealthScript

		protected override void Execute()
			DataSeries maFast = EMAModern.Series(Close, 50);
			DataSeries maSlow = EMAModern.Series(Close, 200);
			DataSeries maFast_1 = EMAModern.Series(Close, 10);
			DataSeries maSlow_2 = EMAModern.Series(Close, 50);
			DataSeries ma = EMAModern.Series(Close, 10);
			DataSeries maFast_3 = EMAModern.Series(Close, 10);
			DataSeries maSlow_4 = EMAModern.Series(Close, 50);


			//for(int bar = GetTradingLoopStartBar(201); bar < Bars.Count; bar++)
			int bar = Bars.Count - 1;
				if (IsLastPositionActive)
					Position p = LastPosition;
					if (p.EntrySignal.Contains("Group1|"))
						if (CrossUnder(bar, maFast_3, maSlow_4))
							SellAtMarket(bar + 1, p, "Group1");

					if (maFast[bar] > maSlow[bar])
						if (maFast_1[bar] > maSlow_2[bar])
							if (Close[bar] < ma[bar])
								if (EarningsDate.InWindow(this, bar, "earnings per share", 7, 0))

									BuyAtMarket(bar + 1, "Group1|");


TypeError: require.extensions.hasOwnProperty is not a function

While playing with https://github.com/alexa/interactive-adventure-game-tool, I ran into following error:

> interactive-adventure-game-tool@1.0.0 start /Users/amer/alexa/interactive-adventure-game-tool
> node node_modules/gulp/bin/gulp.js

            if (!require.extensions.hasOwnProperty(ext)) {

TypeError: require.extensions.hasOwnProperty is not a function
    at requireDir (/Users/amer/alexa/interactive-adventure-game-tool/node_modules/require-dir/index.js:97:37)
    at Object.<anonymous> (/Users/amer/alexa/interactive-adventure-game-tool/gulpfile.js:1:85)
    at Module._compile (module.js:660:30)
    at Object.Module._extensions..js (module.js:671:10)
    at Module.load (module.js:573:32)
    at tryModuleLoad (module.js:513:12)
    at Function.Module._load (module.js:505:3)
    at Module.require (module.js:604:17)
    at require (internal/module.js:11:18)
    at Liftoff.handleArguments (/Users/amer/alexa/interactive-adventure-game-tool/node_modules/gulp/bin/gulp.js:116:3)
npm ERR! errno 1
npm ERR! interactive-adventure-game-tool@1.0.0 start: `node node_modules/gulp/bin/gulp.js`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the interactive-adventure-game-tool@1.0.0 start script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/amer/.npm/_logs/2018-01-02T05_12_24_832Z-debug.log

The solution was to update require-dir to version 0.3.2 in package.json and run npm install again.