Weekly recap
I didn’t plan for this week to be about infrastructure. But that’s what it became. I sat down on Monday to fix one small thing, and by the time I looked up, I had touched almost the entire setup — both servers, the VPS, the notebook, and even a personal project that had nothing to do with servers at all.
I’m writing this down before I forget. Less changelog, more diary.
The theme of the week wasn’t installing things. It was fixing them.
Looking back, almost none of what I did was “spin up a new service.” It was mostly figuring out why something was wrong and fixing the cause instead of treating the symptom. That pattern repeated itself so often that it became the thread running through the whole week.
The cleanest example was the GoToSocial theme. There was a readability bug in the admin panel: almost-white text on a light gray background, basically unreadable. I spent too much time theorizing about which selector was painting the text the wrong color, when the real problem was the background. The --almost-white variable in GoToSocial is not a text color; it is a surface color. I had mapped it to a light value, so the whole panel was getting a light background from there. The fix was one line. Same old lesson, learned again: when text “disappears,” the first thing to check is background-color in DevTools’ Computed panel, not whatever theory your brain just invented.
That pattern — stop guessing and read the actual state — showed up again in Unraid, PeerTube, and pretty much everything else.
The servers
Nyx (Unraid / Ryzen 5800X)
I started with a boring permissions problem while moving qBittorrent downloads — the container UMASK was set to 022, so I changed it to 002 — and somehow ended up investigating CPU temperatures. The dashboard temps were way too high.
My guess was a process. Claude’s guess was hardware. Both were partly right. vmstat showed a constant 91% idle, so load wasn’t the issue. The main culprit was the frequency governor being stuck on performance, holding the cores at 4641 MHz even while idle. I switched it to powersave with EPP set to balance_performance through amd-pstate-epp, and the clocks dropped to around 3710 MHz. But the temperature only improved a little. That tells me there’s also a physical cooling limit involved — probably dried-out thermal paste, which is a known pain point with the 5800X. That stays on the list: open the machine and check it properly.
I made the governor and EPP settings persistent in /boot/config/go, in the right order — governor first, EPP after — otherwise the file locks up.
skullserver (Debian / Contabo)
This was the heaviest day. Four fronts: security, cleanup, MOTD, and IRC.
The discovery that annoyed me the most: UFW had the correct default-deny policy, but Docker injects its own iptables rules and bypasses UFW. Result: around thirteen containers were exposed to the internet even though the firewall made it look like they were not. I moved everything from 0.0.0.0 binds to either 127.0.0.1 for services behind a proxy, or to the Tailscale IP for direct access. I also found a Shadowsocks service running as init.d that I didn’t even remember anymore — gone. Cleaned up nine orphaned UFW rules too.
I rewrote the MOTD from scratch because the Debian 13 pt_BR locale was breaking the parsing of free — it returned Mem.: instead of Mem:. The new version reads directly from /proc and forces LC_ALL=C. I also gave it the look I wanted: monochrome editorial style, oxblood accent, a thin ruler instead of a box-drawing frame.
The IRC client that kept dropping wasn’t the server after all. It was the residential connection’s NAT timeout. Solved by routing the client through Tailscale with a single line in the Windows /etc/hosts.
murad.chat (Debian / Contabo)
This one was about load average, which had gone up after I added more federated services — Funkwhale, BookWyrm, Pixelfed, Lemmy, Iceshrimp. But the truth is the load average was lying to me: constant 82–99% idle, zero I/O wait. The high number wasn’t a real problem.
Still, I managed to tighten three services. Funkwhale Celery went from 6 workers down to 2. BookWyrm went from 100 threads down to 12, and Flower was shut off. Pixelfed Horizon was the annoying one — balance=auto enforces at least one worker per queue, so limiting processes didn’t help. The fix was HORIZON_BALANCE_STRATEGY=false with a fixed pool. Horizon RAM dropped from 1.19 GB to around 247 MB.
OpenBSD
Intermittent network drops that only came back after a reboot. The log gave it away immediately: duplicate IP address. ARP conflict — another machine had the same static IP, probably a cloned VM that inherited the config. I moved it to a free IP outside the DHCP pool. No drama.
The visual side
GoToSocial — “Fediverso IDEA” theme
Besides the admin bug I mentioned earlier, the constant challenge here is the 10,000-character limit in the custom CSS field. It forces you to write tight CSS, with no spare comments or junk left behind. The final version landed at around 3,500 characters. Dark space-like background, cyan/violet/lavender palette.
Unraid WebUI
I first tried a vaporwave/synthwave theme and wasn’t happy with it — the selectors were too generic and created bordered boxes around everything. I ended up adopting a Nord theme I found and liked better, so the work became filling in the gaps. The theme was written for an older Unraid version and used ID selectors where 7.3.1 uses classes. The dashboard is table-based, and there were some .stopgap elements that are transparent spacers — the theme was painting them, which made the widgets visually bleed into each other. I made them transparent again and unified the cards with matching border radius.
PeerTube — pablo.tube
I reinstalled the PeerTube instance I had previously shut down because of resource usage and unwanted federation. This time the rules were clear: federation off, transcoding limited to one job, and a hard 480p ceiling regardless of upload size. Along the way I found a broken acmetool hook that was causing all certificate renewals for all domains to silently fail the nginx reload — it was trying to restart dovecot, which does not even exist there anymore, with set -e enabled. Fixed with || true. I also gave the instance a “YouTube 2008” look with CSS and a MutationObserver that wraps “Tube” in a red box to make the logo read Pablo.[Tube].
Kubuntu
The Dell XPS 13 running Kubuntu was choking on Google Drive — a known KDE bug where Online Accounts authenticates correctly, but Dolphin throws “Access denied” because Google blocks the shared OAuth client used by kio-gdrive. I gave up on kio-gdrive and switched to rclone with FUSE. I mounted two remotes — personal and skull — using a single systemd service template with %i substitution, plus enable-linger so it comes up at boot. I also created my own OAuth client in Google Cloud and published it to production to avoid the trap of tokens expiring every 7 days.
I took the opportunity to clean things up: removed snaps I don’t use anymore — Firefox, Element, Thunderbird — replaced Thunderbird with Melia, and fixed Portuguese spell checking. The system itself was healthy: 5.4s boot, zero failed services, TRIM active. More hygiene than repair.
And the project that wasn’t about servers
In the middle of all that, I worked on a family video from 1989 — around 200 minutes of celebrations, including a first birthday. I wanted to improve the quality.
After testing several upscale tools, I learned an annoying truth: the problem with the video is not recoverable noise, it is intrinsic blur from the original capture. Detail that was never recorded cannot be reconstructed by upscale magic. What actually worked was CodeFormer, focused on face restoration — it detected the four faces in the frame and produced something visibly sharper and more recognizable. The honest caveat is that it reconstructs a plausible face; it does not recover the lost pixels. The -w 0.7 parameter strikes a decent balance between quality and identity fidelity. Good enough to make running it on the whole video worth it.