Your whole PHP stack,
in one window.
Libxa Desktop installs and supervises PHP, Node, Nginx, MySQL and phpMyAdmin, then
serves every project on its own local domain. No separate setup, nothing added to
your PATH.
Windows 10 / 11 · 64-bit · ~100 MB
Two things to know before installing
Builds are not code-signed yet, so Windows shows “Windows protected your PC” the first time: More info → Run anyway. And automatic runtime installation is Windows-only; on macOS and Linux the app detects what your package manager installed but cannot fetch runtimes itself.
What it does
From an empty machine to a served site.
Everything below works on a computer with nothing installed on it.
Installs what you are missing
Nginx, MariaDB, PHP and Node download from each publisher’s own host and are verified against a SHA-256 before anything is extracted. A mismatch deletes the file and stops. Nothing touches system directories or your PATH.
Every PHP version, side by side
Install 8.0 through 8.5 and switch the active one with a click. Each site is routed to its own version by a php-cgi process per version: a legacy project on 8.1 and a new one on 8.5 are served at the same time.
Supervises the stack
PHP-FPM, Nginx and MariaDB run as child processes of the app, with combined logs, a stop that does not orphan workers, and an Nginx left behind by a crash reaped at the next launch.
Serves your projects on .test
Park a directory and every project inside it gets a local domain and a generated server block. Laravel, LibxaFrame, Symfony, WordPress and plain PHP are detected from composer.json first and file layout second.
Creates new applications
Name it, pick a folder, and the app resolves a suitable PHP, fetches a verified Composer if you have none, runs create-project, installs front-end dependencies with the active Node, and parks the directory.
phpMyAdmin, configured for you
One click installs it, points it at the managed database, and serves it at phpmyadminlibxa.test: bound to your machine only, because it administers the database as root.
HTTPS on your .test domains
A certificate authority created on your machine signs a certificate for any site you switch TLS on for, and one button trusts the root. No prompt for elevation, because the per-user store does not need it.
Preview a site as you configure it
The preview renders beside a site’s settings at a desktop, tablet or mobile width, so changing a version and seeing the result does not mean a window sitting on top of the controls you are using.
A terminal at the project
Open a shell already sitting in a project’s directory. Windows Terminal, PowerShell or cmd on Windows, Terminal on macOS, and the common emulators on Linux, tried in order so a missing one falls through.
It stays out of the way
Start it with your machine and leave it in the tray, where the menu carries your sites, each service with its own start and stop, and the PHP version switch. The window is there when you want it.
Integrity
Nothing runs unless it checks out.
Every runtime is fetched over HTTPS from the publisher’s own host. The SHA-256 is computed while streaming and compared before anything is extracted: a mismatch deletes the file and aborts, so an unverified binary is never put somewhere the app would later run it.
| Runtime | Versions | Source | Verification |
|---|---|---|---|
| PHP | 8.0 – 8.5 | downloads.php.net | Publisher’s SHA-256, from the release manifest |
| Node.js | 20 – 26 | nodejs.org | Publisher’s SHA-256, from SHASUMS256.txt |
| Nginx | 1.29.4 | nginx.org | SHA-256 pinned in the app |
| MariaDB | 11.4.4 | archive.mariadb.org | Publisher’s SHA-256, from sha256sums.txt |
| phpMyAdmin | 5.2.3 | files.phpmyadmin.net | Publisher’s SHA-256, from the .sha256 file |
| Composer | latest | getcomposer.org | Publisher’s SHA-256, fetched with the phar |
Per-site PHP
One process per version,
not one in total.
A single php-cgi
serves exactly one PHP build. Running several versions at once means one process
each, and an Nginx fastcgi_pass
that sends each site to the right port.
The supervisor and the config generator derive the same version-to-port map from the same site list, sorted, so a restart cannot shuffle ports out from under a config that was already written.
# each site routed to the php-cgi running its version legacy-app.test → 127.0.0.1:9000 PHP 8.1 my-app.test → 127.0.0.1:9002 PHP 8.4 new-app.test → 127.0.0.1:9003 PHP 8.5 phpmyadminlibxa.test → 127.0.0.1:9001 PHP 8.3 ✓ localhost only for phpmyadminlibxa.test
Details that matter
The parts you only notice when they are wrong.
The hosts file is edited inside a marked block
Everything outside “# BEGIN Libxa Desktop” is left byte-for-byte alone, so Herd’s block and your hand-written entries survive. The write is staged to a temp file and copied by an elevated step, so the app itself never runs as administrator.
Failures name the cause and the next step
A busy port says which port and offers a free one. A privileged port says it needs elevation. Nginx exiting is reported with the line from its own error log, not “exited unexpectedly (code 1)”.
A port is checked before the process is spawned
nginx -t validates the config but never binds. The port is probed by both connect and bind, because on Windows a second socket can bind a port that is already being served, and the probe is retried for three seconds, since a database released by the previous run takes seconds to shut down.
It updates itself, but never behind your back
Checks on launch and every six hours, downloads in the background using a blockmap so only changed blocks transfer, and verifies the SHA-512. Then it waits for you to press “Restart and install”, stopping the services first.
Custom chrome and a tray menu
A frameless window with a live status pill, and a tray icon that starts, stops and opens any site without opening the window. Light by default, matching the LibxaFrame welcome page.
Security posture
A local tool with more reach than most.
The renderer is sandboxed
contextIsolation on, no Node access, a CSP with no remote or inline script. Every capability is an explicit typed method on the preload bridge.
Downloads are verified
Publisher-supplied SHA-256, checked before extraction. A mismatch deletes the file.
phpMyAdmin is localhost-only
It administers the database as root and Nginx binds every interface: on an untrusted network the default would be an open database console.
Updates are checksum-verified
The updater checks each download against the SHA-512 in latest.yml before it will install it.
Install it and park a folder.
That is the whole setup. Everything else the app fetches for you.