Kanu Okereke Kanu

Kanu Okereke Kanu Fullstack Engineer (JS/TS, MERN) + QA Automation & DevOps. I ship production software and the pipelines that keep it reliable. Founder @ Oak Techx.

I write about homelab + infra at iamkay.eu.

Small thing that catches people out, including me the first time.When I set up a new server, the very first thing I do i...
03/09/2026

Small thing that catches people out, including me the first time.

When I set up a new server, the very first thing I do is install my laptop's security key on it, so that from then on I can log in without ever typing a password again. On Linux and Mac there is a single command for this that everyone in the field has used for twenty years.

On Windows, that command does not exist. Not missing from a menu, not needing to be switched on. It simply is not there.

Windows does include proper SSH tools these days, and they are good. There are nine programs in the folder. The one that copies your key over is not among them.

The reason is a bit of trivia that explains a lot: that command was never a program. It is a small script written for Linux-style shells, and when Microsoft ported the toolkit to Windows they built the real programs and left the scripts behind. Which means it is not an oversight that will get fixed. It is just not coming.

The good news is the script does something simple, so you can do the same thing yourself in one line: read your key, connect, create the folder, add the key, set the permissions. Type the password once and never again for that machine.

Better news, if you already have the Git software installed on your Windows machine: you already have the missing command. The Git installer bundles a second, more Linux-like set of these same tools, and that set includes it. So it works perfectly in one window and does not exist in another window on the same computer. Worth knowing before you spend twenty minutes concluding your installation is broken.

The problem that actually eats time is the one where the key arrives correctly and the server still asks for a password. Nine times out of ten it is folder permissions. The server quietly refuses keys if the folder they live in is writable by anyone other than you, and it will not tell you that. It just falls back to asking for a password, which looks exactly like the key never arrived. The server's own log says precisely what happened, and that is the only place it says it.

Why I bother with all of this: the password gets typed exactly once, by me, on my own machine, and never goes into a note, a message or a file. After that, adding a new machine is a thirty second job instead of a decision about where to write a password down.

Every server I have built this year got this treatment on its first boot, and I have never once had to go looking for one of their passwords. For most of them I genuinely do not remember what it was.

Full write-up: https://www.iamkay.eu/blog/ssh-copy-id-windows?utm_source=facebook&utm_medium=social&utm_campaign=post-14-ssh-copy-id-windows

I moved a test environment for one of my software projects off rented cloud servers and onto the machines in my house. I...
01/09/2026

I moved a test environment for one of my software projects off rented cloud servers and onto the machines in my house. It took one evening, and the ongoing cost went to nothing.

Some background. The project is an app where each customer gets their own web address. The test version of it was running on rented infrastructure that charged every month, for an environment nobody actually uses outside of weekday afternoons. Meanwhile I have servers in my house doing similar work already, bought and paid for, with the electricity being spent regardless. The test environment was paying rent elsewhere for no good reason.

The tricky part was that every customer needs their own address, and it had to keep working that way. So the job was never "move one app." It was "build an address system that still works when there are twenty customers, without twenty pieces of manual work every time."

My first attempt used the obvious structure, giving each customer a name in front of a shared one. I built the entire path for it, tested it from outside the house, and got a security certificate failure.

It turned out the free certificates I was relying on only cover one level of naming depth. What I had built was two levels deep. Getting that covered needs a paid upgrade, about ten dollars a month. I was doing this whole migration to stop paying a monthly bill, so trading one subscription for a slightly smaller one was not a win. That was out.

The fix was to change the shape of the names so they stay one level deep, putting the customer name into the address rather than in front of it. Same free certificate, covering every customer that will ever exist.

It came with two honest downsides, and I would rather say them than pretend otherwise. Every customer still needs their own DNS entry added, which is scriptable but not free. And the customer names become visible to anyone who looks at the public records. For a test environment full of fake accounts that is fine. For the real thing it would not be, and the real thing would need a different approach.

The whole migration, four separate applications, took about fifty minutes from starting to everything serving.

The one thing I deliberately did not move is the real customer database, which stays on a managed service. My house does not have battery backup on the servers yet, and the main database is the wrong place to find out how your house handles a power cut. The test environment can afford to learn that lesson. The live one cannot.

Full write-up: https://www.iamkay.eu/blog/staging-off-the-cloud?utm_source=facebook&utm_medium=social&utm_campaign=post-13-staging-off-the-cloud

I gave a new server an address on my network that was already being used by my password vault. I only caught it because ...
27/08/2026

I gave a new server an address on my network that was already being used by my password vault. I only caught it because I said the number out loud while typing it and something about it sounded familiar.

I had checked first. My check was just narrower than my question.

The command I used lists what is running on the machine you are logged into. It says nothing about the other two machines. So on a network of three servers I was looking at a third of the picture, and crucially it did not look like a third. It looked like a complete list, because it was a complete list of something.

Checking whether an address responds is no better, and worse in one way: it tells you what is switched on right now. Something that is powered off still owns its address, and takes it straight back the moment it starts.

A few weeks later I made the same mistake and did not catch it. What actually happens is stranger than you would expect.

Everything looked fine. The address responded from everywhere, every time, because both machines were answering and whichever one got there first won that round. Nothing about that looks broken.

Then the actual service failed, and it failed differently depending on where I tested from. From most machines, refused. From one machine, perfect. That one working case cost me twenty minutes, because something that works from exactly one place looks like a permissions problem, not an addressing problem. Meanwhile the thing that routes traffic to my services was sitting on one of the confused machines and serving errors to everyone.

Clearing the cache does not help, and that is the giveaway. The wrong machine is still sitting there, still answering. Anything that gets better on one machine, stays broken on another, and reshuffles when you clear a cache is two things fighting over one address until proven otherwise.

The check that actually works is to read what every machine has been assigned in configuration, across the whole network, including things that are switched off. One command, about a second, and it is the only genuinely reliable answer.

Both times the underlying mistake was the same. I ran a check whose scope was narrower than the question I was asking. Neither command was wrong. Both gave complete, accurate answers to a question I had not meant to ask.

That is far easier to walk into than a tool that gives you a wrong answer, because a wrong answer eventually contradicts something. A correct answer to the wrong question agrees with everything, right up until it does not.

Full write-up: https://www.iamkay.eu/blog/ip-collision?utm_source=facebook&utm_medium=social&utm_campaign=post-12-ip-collision

Half past midnight, two commands left in a session that had gone well for five hours. One to copy some settings files to...
25/08/2026

Half past midnight, two commands left in a session that had gone well for five hours. One to copy some settings files to a new location, one to delete the originals. I ran them in the order my notes had them.

Both printed nothing. For these commands, printing nothing is what success looks like, so I carried on.

The copy had failed. The folder it was copying into had not finished being created yet, and copying into a folder that does not exist does not produce a dramatic error. It just quietly does nothing. At midnight, "did nothing" and "did everything" look exactly the same on screen.

So the delete removed the only copy of the settings for twelve things running on that server. The family photo storage, the password vault, the thing that makes the internet work in this house, the monitoring, the backups.

To be clear about what was lost: not the data. Every file was untouched. What went was the description of how it all fits together. Which is arguably worse, because you can point at data. A running service with no settings file is not a service, it is an unlabelled disk.

Nothing went down, and the reason is genuinely interesting. Once one of these services has started, it never looks at its settings file again. It read it once at startup, built itself, and now runs from what it holds in memory. So all twelve carried on serving as if nothing had happened. Nobody in the house noticed anything, that night or since.

That is a real safety margin, and it is also the most dangerous kind, because it is invisible. Nothing tells you that you are inside it. One power cut and I would have had twelve stopped services and no record of how any of them were set up.

I had taken a full copy of everything into an ordinary folder half an hour earlier, as the first step of the job. Four minutes to put it all back. Everything came back still running, having never actually stopped.

The lesson I took is not "be careful with delete commands," because filing it there is how you make the same mistake next month with a different command.

The real mistake was that I took a single safe operation and rebuilt it out of two unsafe ones. There is a command that moves things, and it will never leave you with the original gone and the destination empty, because it does the checking for you. I could not use it here, so I did the same job by hand with a copy and a delete. The moment you do that, the checking becomes your job. I did not do it.

And the honest part: the delete served no purpose at all. Nothing required it. Those were tiny text files on a machine with hundreds of gigabytes free. I removed them because leaving them there felt messy. The only genuinely dangerous command in a thirty minute job was the one that was pure housekeeping.

Full write-up: https://www.iamkay.eu/blog/verify-before-destroy?utm_source=facebook&utm_medium=social&utm_campaign=post-40-verify-before-destroy

I renamed a server, ran every check I could think of on it, and everything came back healthy. Then I tried to open it fr...
20/08/2026

I renamed a server, ran every check I could think of on it, and everything came back healthy. Then I tried to open it from my laptop and it may as well have been unplugged.

What made this a genuinely annoying hour is that it was broken in one direction only. From the server itself I could reach anything: the router, the internet, other machines in the house. From anywhere else, the server was silent. And confusingly, all the services running on that server were still perfectly reachable. Only the machine underneath them had gone dark.

That one-way behaviour is what sends you hunting in the wrong place. Almost every network fault breaks traffic both ways. A bad cable, a wrong setting, a dead route: all of them stop things in both directions. So I checked all of that first, and all of it was fine. Meanwhile I could watch my laptop's requests physically arriving at the server. They just never got an answer.

It turned out to be the firewall, which I had not touched. Renaming the machine was enough.

The software keeps its firewall settings in two places: the saved configuration, and the live rules actually running in the system. Renaming the machine moves the saved configuration. The software notices the two no longer match, marks it as needing an update, and then does not perform the update. So the live rules keep enforcing permissions tied to a name the machine no longer has. Anything trying to get in fails to match. Anything going out is unaffected, because outgoing traffic is allowed by default and never had to match anything.

The fix took under a second: one command to restart the firewall service. Access came back before I finished reading the output.

Three things made this worse than a normal outage. It never reported an error, so nothing alerted. It looked nothing like a firewall problem, because a firewall that lets everything out is not where anyone starts looking. And it was delayed, because every test I ran while I was on the machine was an outgoing test, and outgoing was fine.

The lesson I actually kept: any job that changes a machine's identity should finish with a test run from somewhere that is not that machine. Everything the server told me said it was fine. The server was not fine. It just had no way to tell me, because telling me was the broken part.

Full write-up: https://www.iamkay.eu/blog/pve-firewall-pending?utm_source=facebook&utm_medium=social&utm_campaign=post-39-pve-firewall-pending

I gave my first server a good name back when it was the only machine I owned. Then I bought two more, and the good name ...
18/08/2026

I gave my first server a good name back when it was the only machine I owned. Then I bought two more, and the good name was sitting on the box least likely to still be here in two years.

So the server needed renaming. The catch was that twelve things were running on it at the time, including the family photo storage, the password vault and the thing that makes the internet work in this house. Renaming it while all of that stayed online was the whole challenge.

On a normal Linux machine, renaming is one command and you are done. On this software it is not, because it keeps a folder of settings named after the machine. Change the machine's name and all the settings are suddenly filed under a name it no longer answers to. It will boot up perfectly happily and show you an empty server with nothing running on it, which is a memorable thing to see at half past midnight.

The obvious move is to rename the folder to match. That fails, because a background process has already created the new folder for you the instant it noticed the new name. So you copy the contents across instead. And there is the trap: if you copy one second too early, before that process has finished building the empty folders, the copy quietly does nothing and tells you nothing. When you are working through a checklist at speed, "no message" looks exactly like "success."

I then deleted the original before checking the copy had worked. Twelve sets of settings, gone from the only place they lived.

Everything kept running anyway, and the reason why is genuinely interesting. Once a service has started, it holds its own settings in memory and never looks at that folder again. The files can vanish completely and everything carries on serving. That gave me a window to restore from a backup I had taken half an hour earlier, and nothing my family uses went down for a second.

But that is forgiveness, not permission. If the power had cut during that window I would have had twelve running services and no idea how any of them were set up.

The lesson I actually took from it: the one step that could have cost me everything was a step I did not need to take at all. Nothing about renaming the machine required deleting that old folder. I could have left it sitting there forever and been perfectly fine.

Full write-up, including the exact sequence that works: https://www.iamkay.eu/blog/pve-node-rename?utm_source=facebook&utm_medium=social&utm_campaign=post-09-pve-node-rename

One of my automated build systems sat there doing nothing for ten minutes, and every status light said it was perfectly ...
13/08/2026

One of my automated build systems sat there doing nothing for ten minutes, and every status light said it was perfectly healthy. The default setting was the problem the whole time.

A bit of background for the non-developers: I run a system that automatically tests and builds my projects whenever I make a change. It uses a shared "worker" to do that job. My build was stuck waiting in line, but when I checked the worker, it reported itself as healthy and available. Healthy and stuck at the same time is a confusing combination, and it's the clue.

It turned out the worker ships with a setting that lets it do only one job at a time, across every project it serves. Not one job per project. One job, full stop. So a different, busier project of mine was hogging the single lane, and everything else just queued up behind it silently.

Once I understood that, the fix was changing a single number so the worker can handle two jobs at once instead of one. Restart it, and the backed-up jobs cleared in about thirty seconds. The only cost is a bit more memory when two jobs overlap, which is a fine trade.

The lesson I keep relearning with self-hosted tools: the defaults are usually tuned for the simplest possible case, one project, one user, one thing at a time. The moment your setup is busier than that, the default quietly becomes the bottleneck. "Healthy but not moving" is often a sign you've outgrown a default, not that something broke.

More homelab stories at https://www.iamkay.eu/blog/ci-concurrent?utm_source=facebook&utm_medium=social&utm_campaign=post-43-ci-concurrent

My family can reach our home cloud from anywhere in the world, and I never opened a single hole in my home firewall to m...
11/08/2026

My family can reach our home cloud from anywhere in the world, and I never opened a single hole in my home firewall to make that happen.

For years the standard way to reach something on your home network from outside was "port forwarding," which basically means punching a hole in your router and exposing a service to the entire internet, then hoping you keep it patched faster than someone finds it. I never liked that hole. So my setup doesn't have one.

Instead I run a small piece of software called Cloudflare Tunnel. Here's the clever part: instead of the internet reaching in to my house, a little agent inside my house reaches out to Cloudflare and holds that connection open. When my wife opens our photo cloud from her phone, the request goes to Cloudflare first, then travels back down that already-open connection into my house, and lands on the right service. Every connection is outbound from my side. My router's "who's allowed in" list never changes, because the answer is still nobody.

The bit I'm proudest of is how contained it is. That tunnel agent lives in its own isolated corner of my network, and the one rule allowing it to reach anything important is a single line that says "only this one agent, only to this one address, only on the secure web port." Nothing else. If that agent ever got hacked, it couldn't log into my other machines or touch our files directly. It has exactly one job, and the network makes sure that's all it can do.

On top of all that, it's free for personal use, and you get Cloudflare's attack protection sitting in front of everything as a bonus.

If you're still forwarding ports to reach your home services in 2026, this is the upgrade worth making. Same access, none of the exposure.

(One note for the technically curious: the specific IP addresses and internal names I mention are documentation placeholders on reserved ranges, not my real ones. The design is exactly how I run it. The addresses are stand-ins on purpose, so nothing here points at a live machine.)

More homelab stories at https://www.iamkay.eu/blog/cloudflare-tunnel?utm_source=facebook&utm_medium=social&utm_campaign=post-08-cloudflare-tunnel

I had set up automatic failover for the piece of my homelab that routes web traffic, felt good about it, and then discov...
06/08/2026

I had set up automatic failover for the piece of my homelab that routes web traffic, felt good about it, and then discovered it only half worked.

The setup: two identical servers share one "floating" address between them. If the active one dies, the address is supposed to jump to the spare, and visitors never notice. To test it, instead of shutting down the whole server, I just killed the specific program doing the routing.

The traffic stopped, and the floating address never moved. It sat on the machine that was no longer doing anything.

The reason turned out to be a gap in what the failover system was actually watching. It checks that the other server is alive by listening for a heartbeat between the two. A heartbeat proves the machine is powered on and on the network. It says nothing about whether the actual program is running. So with the machine up but the program dead, the heartbeat kept going, the system thought everything was fine, and the address stayed put.

The fix was small: I added a health check that actively pokes the program every couple of seconds and, if it doesn't answer, tells the failover system to hand the address over. Five lines of config. Now "the program died" triggers the same failover that "the whole server died" always did.

The lesson generalizes to any automatic failover you set up: a heartbeat proves the box is up. It does not prove the thing you actually care about is up. Test by killing the program, not just the machine, or you'll find this gap the hard way during a real outage.

More homelab stories at https://www.iamkay.eu/blog/vrrp-track-script?utm_source=facebook&utm_medium=social&utm_campaign=post-42-vrrp-track-script

My password vault lives on a box in my house now, and I want to be honest about both sides of that.The good side: every ...
04/08/2026

My password vault lives on a box in my house now, and I want to be honest about both sides of that.

The good side: every password still syncs to my phone and my browser exactly like it did when I paid Bitwarden for the service. Nothing about my day-to-day changed. The difference is that the encrypted database now sits on hardware I own, in my home, instead of on a company's servers.

The tool that makes this work is called Vaultwarden. It's a rebuild of the Bitwarden server that speaks the same language as the official apps, so the real Bitwarden browser add-on and phone app work with it untouched. You just point them at your own address. The apps stay the official, audited ones. Only the server behind them changes. It's tiny too, small enough that I mostly forget it's running.

Now the honest side, because this is the part people skip. That little database file is the vault. Not a copy of it, the actual thing, holding every password I have. When Bitwarden hosts it for you, they keep multiple copies in multiple places so a disaster never wipes it out. The moment you host it yourself, that becomes your responsibility.

So before I trusted it with a single real password, I set up the backups. My server takes a full snapshot every day, which handles a dead drive or a bad update. But a backup that only exists in the same house as the original is one fire or flood away from being gone. So the next step, the one that actually makes this as safe as the paid service, is an encrypted copy sent off to cloud storage. It's scrambled before it ever leaves the house, and I hold the only key.

The plain truth: I traded about forty dollars a year and a big company's safety net for full control over where my most private data lives. That trade is only worth it if you actually do the backups. A self-hosted vault with no off-site copy isn't cheaper than Bitwarden. It's just riskier and free, which is a bad deal wearing a good-deal costume.

Done properly, with daily backups and an off-site copy, I'm comfortable calling it even. The vault is mine, the apps are the same ones I already trusted, and the only thing I signed up for was taking backups seriously. That part was worth it.

More homelab stories at https://www.iamkay.eu/blog/vaultwarden?utm_source=facebook&utm_medium=social&utm_campaign=post-07-vaultwarden

Adres

Amsterdam

Openingstijden

Maandag 09:00 - 17:00
Dinsdag 09:00 - 17:00
Woensdag 09:00 - 17:00
Donderdag 09:00 - 17:00
Vrijdag 09:00 - 17:00

Telefoon

+2348035485417

Meldingen

Wees de eerste die het weet en laat ons u een e-mail sturen wanneer Kanu Okereke Kanu nieuws en promoties plaatst. Uw e-mailadres wordt niet voor andere doeleinden gebruikt en u kunt zich op elk gewenst moment afmelden.

Snelkoppelingen

Uitgelicht

Delen

Categorie