Skip to content
LibxaFrame
Packages 12 August 2026 8 min read

Libxa Desktop 0.4.0: three settings that changed nothing

A PHP version that switched in the interface and nowhere else, a FastCGI port that moved when a different site changed version, an updater that asked for draft releases, and a terminal that counted a process dying instantly as success.

Libxa Desktop 0.4.0 rebuilds the Sites page, and fixes three settings that saved correctly and then changed nothing at all.

The settings that lied

A site's PHP version could be changed. The dropdown moved, the choice was saved, the list showed it afterwards. The site went on running the version it had been running before, or started answering 502.

Three things have to happen when that version changes, and only the first was happening. The setting was written. The nginx configuration was rewritten on disk, but nginx was never told to reload it, so the running server kept the old one. And no php-cgi was ever started for the version just picked, so even after a reload the port the config pointed at had nothing listening on it.

Switching the default version had the same gap, and that one decides which binary the PHP service runs and where every unpinned site is sent. Nothing took effect until the next launch.

The port that moved

Underneath was a worse one.

Each PHP version gets its own php-cgi on its own port, and nginx routes each site to the right one. The port used to be the version's position in a sorted list of the versions in use:

{8.3, 8.4}        →  8.3 = 9000, 8.4 = 9001

Switch one site from 8.3 to 8.5 and 8.3 is no longer in use, so the list becomes {8.4, 8.5}:

{8.4, 8.5}        →  8.4 = 9000, 8.5 = 9001

8.4 just moved from 9001 to 9000. The worker serving it is still listening on 9001, and the freshly written config now sends its traffic to 9000. Sites that nobody touched, on a version nobody changed, stopped working.

A comment in that function claimed the sort made the assignment stable. It makes it stable for as long as the set does not change, which is not the same thing, and the difference is invisible until someone changes a version.

The port is now a function of the version itself:

port = 9000 + (major - 8) × 10 + minor

8.0 answers on 9000, 8.4 on 9004, 9.0 on 9010. Adding or removing a version cannot move another one, because no version's port depends on which others exist.

The update that never arrived

The updater was configured to look for draft releases. Drafts are not returned by the unauthenticated GitHub API, so every installed copy checked on launch and every six hours, found nothing, and reported that it was up to date. It was not.

One word in the build configuration. The kind of bug that produces no error anywhere, on any machine, and simply means nobody ever gets a new version.

The terminal that opened nothing

Clicking Terminal did nothing at all: no window, and no error either.

Opening a terminal means trying candidates in order, since every platform disagrees about what a terminal is. The check for "did this one work" was the absence of an error event within 400 milliseconds. A program that does not exist raises ENOENT and is skipped correctly. A program that starts and then immediately dies raises nothing, so it counted as success, the search stopped there, and no further candidate was tried.

Watching the exit code tells the two apart. Exiting zero straight away is normal and means it worked, because Windows Terminal hands the request to an already-running instance and the process it was launched as has nothing left to do. Any other code means try the next one.

A page with room in it

The Sites page was a table. Every row carried a URL, a path, a framework badge, a PHP dropdown, an HTTPS toggle and four buttons, and every per-site setting added since made the rest narrower. There was nowhere to put a Node version.

It is now a list of sites beside a pane for the selected one, with General and Information tabs. The preview lives in that pane rather than in a window of its own, which is the arrangement that actually matches what a preview is for: changing a setting and seeing what it did, without a window sitting on top of the control you are using.

Node joins PHP as a per-site version. It is stored empty rather than as a copy of the current default, so a site that has never been given one keeps following the default as it changes, instead of being pinned to whatever happened to be current the day it was first scanned.

Also

Launch at login, and start minimised as a tray application: together they start the app with the machine and leave it in the tray with no window until asked. Launching at login is unavailable on Linux, which has no single mechanism to register with, and the setting says so rather than silently doing nothing.

The tray menu now carries the sites, each service with its own start, stop and restart, the default PHP version switch, and the configuration directory.

Existing installations update themselves, now that they can find the release.

Keep reading