I’ve migrated my website. Again.

This time, I decided to implement it using Gutenberg, a static website generator which is written in Rust. I decided it was finally time to stop saying ``I’ll learn Rust'', and just started.

I also revisited Docker and containerized my website, with Caddy as the HTTP/2 server. After using Caddy, I simply don’t want to go back to Apache2 or Nginx for personal projects ever again. Caddy’s configs are minimal and it automatically handles HTTPS certificates using Let’s Encrypt.

Here’s what my Caddyfile for andrewzah.com, andrei.blue, and znc.andrewzah.com looks like:

andrewzah.com, andrei.blue {
  tls your@email.com

  log / stdout {combined}
  errors stderr

  proxy / http://web:1111

znc.andrewzah.com {
  tls your@email.com

  log / stdout {combined}
  errors stderr

  proxy / http://znc:6697

That’s it. Then with Docker, I can use a Caddy proxy per service.

As Gutenberg is a static website generator I have no need for a database. Indeed, I thought it was overkill to run an application and a Postgres instance just for a handful of posts. I much prefer storing my posts through git. The application’s footprint is overall much smaller and I have less dependencies to manage. I want to focus on other programming projects, not so much my website.

2017 in Review

2017 was an exploratory year for me. I looked at Docker a lot more, learned a bit of Clojure, and delved into Rust.


I can’t really say much other than Docker is simply amazing. After I nuked my first VPS setup, I realized how tedious and truly time-consuming manually setting up a server is. It’s ridiculous. Now it takes me about 20-25 minutes to set up a server, and that’s only because I still do a bit manually (like a docker user, ssh keys, etc). In 2018 I plan on studying better provisioning and setup techniques so I can automate it completely.

My docker setup utilizes a script to manage several services, such as this website and my personal ZNC server. Adding a docker service is as simple as getting a premade docker image and making a Caddy proxy:

# compose.yml
version: "3.3"

      context: ${COMPOSE_ROOT}/services/bitlbee/
      dockerfile: Dockerfile-caddy-net
      - type: bind
        source: ${COMPOSE_ROOT}/services/bitlbee/Caddyfile
        target: /etc/Caddyfile
      - type: bind
        source: ${COMPOSE_ROOT}/data/caddy/caddypath-bitlbee/
        target: /var/caddy/
      CADDYPATH: "/var/caddy"
      - "6667:6667"
    restart: always
      context: ${COMPOSE_ROOT}/services/bitlbee
dockerfile: Dockerfile-bitlbee
proxy :6667 bitlbee:6667 {
  host znc.andrewzah.com
  tls your@email.com

So that uses my bitlbee Dockerfile and creates a Caddy proxy in the docker container. You can see all of my services here.


Studying Clojure — and forcing myself to stick with it — truly changed me as a programmer. Shifting from a pure Object Oriented mindset towards Functional Programming is easier said than done, but I cannot state how important it is to at least understand FP. Map, Reduce, and Filter are powerful. Languages like Ruby have implementations of these of course, but it’s tough to force yourself to actually use them.

Likewise with immutability. Coming from a Ruby background, having to program with immutable variables was like learning how to program all over again. It was tough. Yet as I reflect now, I think it’s a much better approach — although mutable variables are still a good choice in certain situations.

Reducers & Transducers

I particularly liked Clojure’s reducers & transducers. Again, it took time to understand, but once I did… it felt absolutely amazing to transform incoming data streams via concise, logical functions. Speaking of functions, it was quite a lot of fun to learn about the various functions Clojure provides, such as zipmap and trampoline.

I really like Clojure. Studying the standard library’s functions felt rewarding. The only thing I didn’t like was its debugging / compiler output. It was not particularly great, coming from a statically typed language like Crystal. I’m still quite new to Clojure, but I think it made some things much more frustrating than it needed to be.


Ah, Rust, what seems like the most talked about language recently. I’ve only been studying a bit since December, but I adore it so far. From everything that I’ve seen, it looks like Rust takes great concepts from various programming styles and paradigms and implements them well. Since Rust is new(er) it can take advantage of concepts like concurrent programming, as well as fix or address past issues in other languages.

What I will say is that Rust’s compiler is phenomenal. It makes error hunting so easy, it’s almost like a joy. Crates.io is also fantastic. Shoutouts to those developers.


What I love so far about rust is its model on Ownership. I still don’t know all that much about Rust, but it’s been a lot of fun reading the Rust Book and O’Reilly’s Programming Rust

My goal in 2018 is to deeply study Rust and explore safe systems programming. Possibly with audio hardware? We’ll just have to see.


I also spent almost 7 months in Korea. More info on that will come, but I truly enjoyed my time there, and I’m making a plan on returning full-time as a programmer.