Commits

A video on the home page, a quirky sitemap, and an updater that no longer needs you

A Friday of everything: the presentation video lands on the home page, Google goes...

Friday was one of those days where you touch everything: video in the early morning, updater in the morning, and a network blockage in the afternoon that had nothing to do with the code.

The presentation video, finally on the home page

The Web Base homepage was crying out for the presentation video. First, I built the structure: a round button showing the duration appears at the end of the hero and opens a card with the player, using native browser controls and a provisional cover while the file hadn't arrived yet. When the actual video arrived — square, 296 pixels —, the player kept this format and adapts to small screens; the button now shows a play triangle instead of waves.

One detail I was looking forward to resolving: I don't want the full browser controls. Out with volume, fullscreen, and the options menu; what stays are playback and the progress bar. All verified locally in the browser; deployment will come later.

Google and the sitemap: when the problem isn't in your code

The Search Console marks the sitemap as "Could not be fetched". Production, on the other hand, returns the correct XML: 79 well-formed URLs, no duplicates, with consistent robots.txt and canonical tags. And Google's live test retrieves it without issues. So: the file is fine, but the report insists otherwise.

I resubmitted it and the status stayed the same. I'm leaving it open waiting for a new fetch attempt; if it persists, I'll have to look at what exactly Google received and the Cloudflare access events before changing a single line. For now, I haven't touched the generator because there's no reproducible failure.

The updater updates itself

The promise of Web Base is that the client only presses buttons. But deploying backups required updating the updater manually, over SSH. "Couldn't this be avoided? A client isn't going to run a command on the server." All the more reason. Now the daemon — running as root on the host — launches an independent child process that updates the updater itself, survives the unit restart, and runs health checks and rollback if something goes wrong. With a one-hour timeout between attempts and a switch to disable it.

The first real test uncovered two bugs that the tests didn't catch. The protocol module has its own allowlist of actions, and the new ones had only been added to the daemon: real requests died with "unsupported action", because the tests called the handler directly without going through the protocol. And then a more subtle one: the systemd unit uses a private /tmp and the child extracted the new version there to pass it to Docker as a bind mount; Docker created it on the host's real /tmp, which the child doesn't see. Empty extraction. The solution: move the staging to the installation folder, a path visible to everyone.

And yet a third one, in the afternoon: the child died along with the unit it was itself restarting, because opening a new session doesn't remove you from the cgroup, the control group where systemd locks the process. Now it's born with systemd-run --scope and lives outside. I've also cleaned up the orphan staging files and the panel now tells the truth: "will retry at HH:MM; you don't need to do anything".

Complete backups: configure, delete, and restore

The backups section had been left half-done: just a listing, no form. Now there's real configuration (frequency, time, retention, include media), copy deletion with double validation of the name, and restoration with layered safety nets: before touching anything, it makes a copy of the current state — if it fails, it reinstalls itself —, runs the content through schema migrations, and restarts the API. To confirm, you have to type the filename. This has also been the first release that deploys itself from the panel, without SSH.

A network blockage that isn't code

I ended the day with the home server unable to go out through port 443 to the updates catalog. Curious: only to those two IPs, only on that port. The web doesn't go down because the tunnel runs on QUIC, which uses UDP. It's not a code problem: either the firewall, the router, or Cloudflare. Until it's resolved, the panel already warns when there's no contact with the catalog, instead of staying silent and making you think everything's fine.

Other journal entries