Day one was about building the lab. Day two was about keeping it running. Three things went wrong, and each one taught me something different about operating infrastructure, not just building it.
| Problem | Real cause | Fix |
|---|---|---|
| WordPress couldn’t resize images | A PHP library was missing | Added it to my Ansible role |
| Ansible timed out on both servers | My IP changed, twice | Updated one Terraform variable |
| “Error establishing a database connection” | Database server wasn’t responding | Restarted it and checked with Run Command |
1. “The web server cannot generate responsive image sizes”
When I uploaded screenshots for my posts, WordPress showed this warning. The message suggested converting my images to PNG, but they already were PNGs. The real problem was that my server was missing GD, the PHP library WordPress uses to make smaller copies of images for phones and thumbnails.
The fix had to be in code, not on the server. If I’d installed it by hand, the next rebuild would lose it. So I added it to my Ansible web role, along with a few other PHP extensions WordPress recommends:
- name: Install Apache and PHP
ansible.builtin.apt:
name:
- apache2
- php
- php-mysql
- php-gd
- php-xml
- php-mbstring
- php-curl
- php-zip
- php-intl
- libapache2-mod-php
state: present
notify: Reload Apache
The notify line was new too. It tells Ansible to reload Apache, but only when this task actually changes something. When I ran the playbook, the recap showed the new packages installing, followed by RUNNING HANDLER [web : Reload Apache]. Then I saved the change through a pull request, so GitHub’s checks ran on it before it reached my main branch.
2. Locked out by my own firewall
Next, Ansible couldn’t connect to either server:
ssh: connect to host <server IP> port 22: Connection timed out
Nothing was broken. My firewall only allows SSH from one IP address, mine. I had worked from a different network earlier in the day, so my IP had changed. Then I went home, and it changed back. Both times, the firewall was doing exactly what I told it to: block everyone else.
I compared my current IP with the one in my Terraform settings, updated that one variable, and applied it:
Plan: 0 to add, 1 to change, 0 to destroy.
Terraform updated only the firewall rule, without touching the servers. It finished in about two seconds.
Lesson: when I switch networks, my IP changes, so I need to update that one rule. The blog stays reachable either way, because the firewall only limits SSH, not website visitors.
3. “Error establishing a database connection”
Then my blog showed WordPress’s database error. Azure said both VMs were running, but I couldn’t SSH into the database server.
I restarted it, then used Run Command, an Azure feature that runs a command inside the VM through Azure’s own agent, without needing SSH:
az vm run-command invoke -g rg-homelab -n vm-homelab-db \
--command-id RunShellScript \
--scripts "uptime; systemctl is-active mysql ssh"
It reported the server had been up for 6 minutes, with both MySQL and SSH active. After that, my blog loaded normally.
To be honest, I’m not completely sure what the original problem was. My firewall IP was also wrong at the time, which made both problems look the same from my laptop. When I logged in afterward, memory usage was at 69% on a small VM running MySQL, so the server may have run low on memory. Adding swap space, or giving the database server a slightly bigger VM, is on my list.
What I learned
- Fix it in code. A fix that only lives on the server disappears on the next rebuild.
- Check one thing at a time. Two problems at once (a wrong IP and a struggling server) can look like one.
- Compare to something that works. When one server answered and the other didn’t, I knew it wasn’t my whole connection.
- Have a way in that doesn’t depend on SSH. Run Command let me check the server from inside Azure.









