Upgrading PHP

WordPress now has a health check you can run against your site to make sure it has all the latest bells and whistles. You can find it under Tools > Site Health — this is new to me, but I haven’t used WordPress in years.

My health check had some straightforward items — including to remove themes I wasn’t using. But there were two that I knew I would have to get my hands dirty for — upgrading PHP to at least 7.3, and installing the PHP extension imagick. I had to bumble around the Internet to figure out all the steps, so I figured I’d detail my findings here to make sure I understood what I did.

Installing PHP

I decided to go straight to PHP 7.4 since it’s the latest and this WordPress blog doesn’t have a lot of customization. On my host DigitalOcean, Ubuntu 18.04 comes with PHP 7.2 by default. So first thing was to SSH into the box and start getting the relevant packages.

$ apt-get install software-properties-common
$ add-apt-repository ppa:ondrej/php
$ apt-get update
$ apt-get install php7.4

The software-properties-common was already installed, but I’m pretty sure it enabled me to add the Personal Package Archive (PPA) on the next line. It looks like Ondřej Surý maintains the PPA for PHP — seems odd, but I saw multiple sources cite this repo so I went ahead with it. Then I ran a standard apt-get update and installed PHP 7.4 next.

For a sanity check, I ran php --version and was surprised it was on 7.4! But alas, this wasn’t enough for WordPress to start using it. So next I had to figure out how to get off of PHP 7.2.

Loading PHP Via Apache

This part was cool b/c I learned more about how Apache works! In the /etc/apache2/mods-available directory are a list of available mods for Apache to use, including php7.2.load and the newly installed php7.4.load. My gut told me I had to enable PHP 7.4 and disable 7.2, so that’s exactly what I did.

$ a2dismod php7.2
$ a2enmod php7.4
$ systemctl restart apache2

Loading Remaining WordPress Libraries

There was a DigitalOcean tutorial that suggested I install the following commonly-used WordPress PHP extensions.

$ apt-get install php-curl php-gd php-mbstring php-xml php-xmlrpc php-soap php-intl php-zip

Of course that wasn’t enough. After making Apache configurations above and restarting, I was told I needed to install the MySql extension.

$ apt-get install php-mysql

This worked! Now that I had WordPress running on 7.4, I went ahead with the remaining imagick extension.

$ apt-get install php-imagick

That’s it!

Execute Program

I recently started getting into Execute Program — it comes free with a subscription to Destroy All Software and I was feeling a bit down about work. (More on that later.) I’m making my way through the JavaScript Arrays course as a mix of refresher and new. Once I’m done (or close to done), I’ll attempt TypeScript, since there are some things I want to build in React using it and it’ll be useful at work.

Speaking of work and why I was feeling down: I had a pretty bad week last week. I was really struggling with the codebase I was working in and wasn’t quickly learning from my mistakes. This week has started off better; I attribute that both to a better attitude and my amazing co-workers. Everyone is really supportive of each other and that goes a long way towards getting myself out of a rut. On top of that, over the weekend I reflected on where I was mentally and I think that’s helping me figure out how to ground my problem-solving.

So that’s why I’m continuing to do the JavaScript learning. It’s useful. It’s fun. It’s productive. Of course I’d love to create my fantasy football API or build a React project in TypeScript but those projects take a lot of energy and right now I only have so many spoons to give.

I’ll catch ya’ll later. Hoping to make this a more regular thing.

Another First Post

I had a long day at work but because I made a large batch of congee yesterday, I was able to put on Snoopy in Space as soon as I got home and work on getting this blog setup. It runs on Ghost — a version of the blogging software that is much more advanced than the last time I used it. And yes, once again, I’ll eventually move all of my old posts over to this blog.

Edit: I moved to WordPress instead. Something about not being able to do indented Markdown lists and also no POST endpoints for API fun.

Click thru for the full thread!

I’m not entirely sure what I’ll write about. I really just know I want to write again. A lot has happened since my last post, especially professionally — I now have a much healthier relationship with my job! And I know that over time, I’ll find my voice again. In the meantime, you’ll just have to get used to me figuring out how to use words again.

2019, here we are

Today In-Summary

Today I accomplished:

More about that fried rice…

The other day I purposefully made more rice than I could eat so I’d have leftovers for fried rice. My mom also made a ham for Christmas and gave me some of it, so I used that for my protein and practiced my knife skills cutting it up. The veggies were frozen. I used soy sauce and oyster sauce and even threw in some butter as advised on “Basics with Babish” (still used a wok, though!). I even thought about how the salts and fats came together in this dish — that’s about all I know since I’m still in the middle of Salt, Fat, Acid, Heat.

More Generally

It’s 2019. I was thinking about how the year change is arbitrary, but having the time to reflect is still real. Because of Christmas, we’re encouraged to take time off and regroup. I was also reading about the history of the weekend and in summary I just want to say that even though the year-change is arbitrary, the desire to improve is continuous and the act of talking about it now is coincidental.

During my senior year, I set some goals for myself that I wanted to accomplish. I remember how useful it was to frame that year’s projects and reflect on what I was doing. I hope to do something similar this year with completing my thesis, working as a developer, and being healthier with what I eat and how active I become.

Tool Boxes

Photo by s w on Unsplash

I like to tell people to develop skills like they would add tools to a tool box. I think I first came across this metaphor as a musician and it made perfect sense: learn scales, rhythmic exercises, excerpts from different composers — combine in different ways later on when you encounter something new. Rinse and repeat.

And it applies to what I do now with software too. Except… I’m just not applying it. I’m not thinking about it in the same way that I would with music, which I approach very theoretically and like a puzzle. You would think that kind of thinking would be obvious with programming for machines, but I’ve been a bit stressed out. And when I’m stressed out, I stop trying to add new tools — I instead rely on the ones I have, and even then only the very familiar ones.

I thought of this again today with cooking. I was using my rice cooker and only now decided to measure out the amount of rice I was going to use. I used to do this when I would measure out rice when living with my family! But I lost my dad and with that stress I forgot how to cook. And it’s only until today I realized I could gain that tool back, measuring rice.

Going back to music, I want to reflect on how I succeeded reasonably well without practicing. And it’s because I created a bunch of tools and I became intimate with how they worked. Then when I was stressed out playing (which was, admittedly, most of the time) I’d still know how to use those tools.

It’s also worth noting that because I had those tools, I was also less stressed out about what I was playing. The same goes for cooking. The same goes for coding. And the same goes for whatever it is you’re trying to do. If you can develop an intimacy and familiarity with the tools of your craft, you’ll be able to wield them that much better when you’re under a lot of pressure and stress.

Moving Offices

After our company closed our office to save some coin, I’ve been working from home now for about a month and have a better handle of what that change has meant for me and my well-being. Everyone on our team is adjusting slightly differently, but hopefully by shedding some light on my experience I can shed some light on what to prepare for if the same thing happens to you.

First, What We Accounted For

I think we did a lot of things right when preparing to work from home. The big thing was to do trial runs, communicate about our experiences, and share any insights we might have. We tackled it as a team and that was really useful.

As for specific advice, we immediately figured out the following:

  • It would be difficult to truly know what WFH is like until we got all our equipment shipped from the office (extra monitors and keyboards, etc.), so we tried to focus on learning other aspects of what would change.
    • On the flip side, it gave us a clear impression that working out of coffee shops wouldn’t be ideal given the lack of equipment. Meetings in coffee shops have gotten less awkward, but they can still be noisy.
  • Getting out of the house was obvious to fight getting restless.

Working From Home a.k.a. Changing Your Commute

I think the best way to treat a transition to working from home is to think about it as a change in your commute. At this same company, we had moved our office downtown and it changed everyone’s commute. We should have treated this the same way. I think if we did that, we would’ve considered the following:

  • Commute route / length would change drastically
    • This might mean we need to reconsider what transit benefits mean for us.
    • If the length changes drastically, we should consider what that means for our routines.
    • Sometimes the mode changes, like going from a car to a train. There may be more or less walking.

I didn’t really think about the impact of walking less every day — the little amount I did when going to and from train stations and going out to lunch was instrumental in keeping my mood up and keeping my weight down! And that weight crept up on me — I didn’t notice it until I weighed myself at the doctor’s.

The separation between work and home is also important. I play games and program for fun in the same space I now work. Having the monitors in the same place isn’t a huge problem, but I need to make sure I get out of my desk and do something else for a bit before returning to it. Otherwise it all kinds of melts together.

Last, having a zero minute commute means more time in the day, right? Except for me, that commute time was necessary to stay sane. I used it to read books and get into a better reading habit! So now I need to make sure I bake that in to my schedule again.

Offices Are Social Spaces

And we are social creatures. We knew this would be affected, but it’s hard to gauge that in testing when you still have an office to return to. Not only does it feel more draining working from home without anyone to talk to, it completely affects the problem-solving methods that our team was accustomed to. We have to be much more deliberate.

And yes, Iggy is great, but she’s not a person! No matter how hard she tries. 🙂

Corporate Passed On Costs To Us

This one is simple — company not only saves money on not having an office via rent, but also via utilities, amenities like snacks and coffee, and providing a gym. And not only do we have to pay for these now in a budget sense, we also have to build their responsibility into our habits. I can’t just bring a duffel bag to work and swing by the gym during lunch — I need to take a twenty minute bus ride to the gym, workout, and come back. I also need to pay for it. And before you ask, no, none of us received raises to cover these costs.

Ultimately, Structure Is Good

I talked to my therapist about this today. Even though I’m not Type A and I don’t impose a lot of structure on myself, I like to dance around existing structure. Without it, I can’t dance! So it’s a big change for me to not have my routine of waking up, showering, getting on a train, sitting down at a desk and saying good morning to everyone.

So we need new structures: for our habits, for our social well-being, to make sure we budget appropriately and to help us do our jobs effectively. And if you know me, you already know I don’t have a lot of faith in those in positions of leadership and power to lead on this appropriately. So we need to roll up our sleeves and get ready to get our hands dirty.

Bringing this back

This blog has been neglected for a bit, and I think I should bring it back in some form. In general, I’ve kinda laid low since the beginning of July, when we went through some huge restructuring changes at work and I haven’t had the energy to process them in written form. Instead I’ve been just trying to process them as they came, by myself and with my team. It’s been a lot, but I feel like I can at least post some updates now.

I now work from home. Which is to say, I see a lot more of my dog Iggy now. She’s nuzzled up against me right now, alternating between snoring loudly and trying to get some pets in. The biggest changes to my lifestyle center around broadcasting my work actions more (lunch, logging on and off, reaching out for help) and making sure I don’t go stir crazy being inside all the time. Iggy helps with this too.

I want to do more technical writing in the near future. Advent of Code is around the corner and I need to prep some CI/CD examples for different languages for the group I mentor. I also want to do more work on ceruleanlabs.com and that includes setting up Concourse so team members can manage their own deploys without me. Honestly, I guess I’m doing a lot of DevOps these days.

This blog is interesting in that it contains samples of my writing for over a decade of my life — without that context, it’s really scary to release out into the wild. But if I do it right, then I shouldn’t be too worried — it shows an individual growing over time and continuous learning. After all, that’s all I can really hope for myself. Right now, this blog only shows entries since May 12th. But the archives are there (I should add them to source control) and I still plan to republish them at some point. It is just not a top priority given all the other things I want to accomplish, and I don’t want to cut any corners to complete the archives import because it needs to be done correctly.

Anyhoo, that’s it for now. Expect more posts in the near future. ^_^

Separating Ideas From Actionables

I use Todoist for all of my task management, and for that it works wonderfully. However when it comes to tracking ideas — or even things I just think I should do — Todoist is lost. It’s the same problem with email — items collect dust because I don’t want to act on them but I also don’t want to write them off or forget about them.

For example, I made an item for a new tattoo. But there are no actionables for it right now. Actionables might include eventually saving money? Coming up with ideas for a design? It’s like I need a placeholder for it because I want to break it down further and categorize it, but right now I can’t.

Part of me wants to build some custom view to handle all of these use cases. The other part of me just realizes I just started to figure out how Filters work and finally made one to separate work tasks from other things I might want to do. So I’m probably getting ahead of myself with wanting to use the Todoist API. This is the same brain that sometimes wants to build custom budgeting software instead of just using Excel!

Filters have a lot of strength because the tasks can be prioritized differently based on what I need to do. So something like a “Chores” list would just list all my chores and then I’d do them when I have time and energy. Something like a software project might just have a priority order and then I’d pick which one to do next.

We’ll see what I can do to better leverage the software I have. I still want to develop better ways to develop ideas, build out habits, and plan out larger projects that have several components that need to be done over larger swaths of time.

Rails + Puma + Capistrano + Nginx

About a month ago I decided I wanted to get a website going for Cerulean Labs, my catch-all organization that has supported game dev, mentoring meetups, and other random group projects. It would be good to have a website that allowed users in the organization to coordinate meeting up, sharing projects, and reviewing important info like community guidelines.

I specifically chose Rails because I haven’t developed on it since Rails 3 and I miss developing in Ruby. Puma is the default app server out of the box, and Capistrano takes care of deploys. Last, Nginx is used as a proxy.


Below are the components I had to install on the host machine. The order is all out of whack — I bounced around as I figured out what still needed to be setup. If you’re looking for specific guides, check out the bottom of this post.

SSL Certificate

I used Let’s Encrypt to get my certificate. First, I setup my dependencies:

$ sudo add-apt-repository ppa:certbot/certbot
$ sudo apt-get update
$ sudo apt-get install python-certbot-nginx

Installing the cert:

$ sudo certbot --nginx -d www.ceruleanlabs.com

Testing renewal:

$ sudo certbot renew --dry-run

It’ll prompt you along the way but the questions are straight-forward.

Nginx Gotos

I used the following when I wanted to check the syntax of my config files, check to see if nginx was running, and then to restart it whenever I made a change.

$ sudo nginx -t $ sudo service nginx status $ sudo service nginx restart

Nginx Config

When you first look at /etc/nginx/sites-available/default it looks something like this:

server {
    root /var/www/html;

    index index.html index.htm index.nginx-debian.html;
    server_name www.ceruleanlabs.com; # managed by Certbot

    location / {
            try_files $uri $uri/ =404;

    listen [::]:443 ssl ipv6only=on; # managed by Certbot
        listen 443 ssl; # managed by Certbot
        ssl_certificate /etc/letsencrypt/live/www.ceruleanlabs.com/fullchain.pem; # managed by Certbot
        ssl_certificate_key /etc/letsencrypt/live/www.ceruleanlabs.com/privkey.pem; # managed by Certbot
        include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
        ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

server {
    if ($host = www.ceruleanlabs.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot

    listen 80 ;
    listen [::]:80 ;
    server_name www.ceruleanlabs.com;
    return 404; # managed by Certbot

The first server block shows a default Nginx page. The second block makes sure that your site is always served over HTTPS.

We want to first add an upstream block that points to where our Puma socket will be located. I put this at the very top of the file:

upstream puma {
    server unix:///var/www/ceruleanlabs/shared/tmp/sockets/puma.sock fail_timeout=0;

Next we want to rewrite the guts of that server block that is currently serving the default Nginx page. Mine looks something like this, given we’re serving a Rails app via Puma:

server {
    root /var/www/ceruleanlabs/current/public;
    access_log /var/www/ceruleanlabs/current/log/nginx.access.log;
    error_log /var/www/ceruleanlabs/current/log/nginx.error.log info;
    server_name www.ceruleanlabs.com;

    location ^~ /assets/ {
        gzip_static on;
        expires max;
        add_header Cache-Control public;

    try_files $uri/index.html $uri @puma;
    location @puma {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;

        proxy_pass http://puma;

    listen [::]:443 ssl; # managed by Certbot
        listen 443 ssl; # managed by Certbot
        ssl_certificate /etc/letsencrypt/live/www.ceruleanlabs.com/fullchain.pem; # managed by Certbot
        ssl_certificate_key /etc/letsencrypt/live/www.ceruleanlabs.com/privkey.pem; # managed by Certbot
        include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
        ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

    error_page 500 502 503 504 /500.html;
    client_max_body_size 10M;
    keepalive_timeout 10;

Firewall Config

This part was also straightforward, and again I followed the guide at the bottom of this post. I pretty much just ran the following commands:

$ sudo ufw allow "Nginx Full"
$ sudo ufw allow "OpenSSH"
$ sudo ufw delete allow "Nginx HTTP"

$ sudo ufw status

Ruby Setup

$ curl -fsSL https://github.com/rbenv/rbenv-installer/raw/master/bin/rbenv-installer | bash

I then followed the rbenv guide for installing it to my shell so it would be available when I’m running commands remotely via Capistrano. You can set that shell for that user with chsh -s /bin/bash — using Bash, for example, with a ~/.bash_profile that looks like this:

export PATH="$HOME/.rbenv/bin:$PATH" eval "$(rbenv init -)"

JavaScript Runtime

We need a runtime for compilation of the Javascript components. I ended up just installing Node on the host machine, but you can also add something like mini_racer to your Gemfile to add support as well.


$ cap production deploy

Additional Setup

This is all open-source, so you can of-course check out the rest of the app configuration on GitHub: https://github.com/ceruleanlabs/ceruleanlabs.com The rest of the changes I had to make mostly centered around configuring the Rails app with the correct database credentials, libraries, etc. I should’ve written my steps down better haha, but you’ll find the rest of what’s configured in the repo.

Useful Docs and Guides

Step 2: CircleCI and S3 Buckets

The second part took longer than usual. Part of this was because I was wrestling with DNS — I don’t think DNS changes ever go quickly — but the other part was because I was hit with another bout of depression. #yaydepression

For the second part I configured CircleCI to build and deploy this blog to an S3 bucket, which I reconfigured with the slidingdown.com URL by using Route 53 as my new DNS provider.


This part was pretty fun. I first setup Docker to make sure it could containerize correctly. This helped me debug a JS dependency for Middleman — something I quickly fixed with mini_racer. Next I figured out how to get it to build on CircleCI. CircleCI lets you build one project for free, which is why I’m having it run my blog, which is a private repo.

One useful piece of information was understanding how to persist data in workflows. The diagram in the article really helped and I was able to cobble the rest together using documentation.

AWS Configuration

The S3 configuration was really straightforward once I got the hang of the naming conventions and what how permission should be setup. I followed Amazon’s guide for setting up a custom domain static site And if you’re wary about copypasta’ing the policy into your bucket’s config, you can get the same results from using the AWS Policy Generator.

Getting CircleCI authenticated was also really easy — I created an IAM user specifically for CircleCI and gave it S3 permissions.

The most annoying part was figuring out I needed to switch from my own DNS provider to Route 53. I was trying to setup my own CNAME record and it didn’t take — S3 balked at my configuration. So I made the switch and everything worked magically.

Putting it all together

And now CI/CD for my blog works! The only nice-to-have I really want to have is SSL support. It’s not necessary because I host a static site, but it’s where the web is heading and Firefox gets angry. There might be an option using CloudFront that I can explore.