WinRavel: Bundle a Laravel App into a Single Windows .exe
Laravel is great — until you have to ship it to someone who doesn't have PHP, Composer, a web server, or any idea what a "database" is. So I built WinRavel: point it at a Laravel project, click Build, get one .exe that just runs.
No PHP install. No XAMPP. No composer install. Double-click → a dark control window opens → your app serves on 127.0.0.1.
What's inside the exe
- FrankenPHP (PHP 8.5 + Caddy) — the app server, baked in
-
Your Laravel app — fully set up at build time (
composer install,key:generate,migrate, optionaldb:seed) - SQLite (default) or a bundled MariaDB server for apps that need real MySQL
- Optional source obfuscation of
app/
On first run it extracts to %APPDATA%\<App>, then frankenphp php-server serves it. A Windows Job Object ties the PHP (and MariaDB) process to the launcher so nothing orphans.
The interesting engineering bits
1. No recompile per build (self-extracting).
The launcher is a precompiled C# stub with FrankenPHP's runtime embedded. Building an app just appends a payload — [app.zip][config][footer] — to a copy of that stub. The stub reads the trailing bytes of its own exe at startup. Result: builds are instant, and the build machine doesn't need the .NET SDK.
2. Bundling MariaDB without 250MB.
MySQL/Postgres have no real embedded mode for PHP (and PGlite is WASM/JS — useless from PHP's pdo). So for "real MySQL" I bundle a trimmed MariaDB: just mariadbd + a few DLLs + a pre-initialized template data dir. At build time WinRavel boots it, creates the DB, runs migrations, shuts it down, and ships the migrated data dir. The launcher starts/stops it automatically. Shrinking InnoDB's redo log (96MB → 8MB) keeps it lean.
3. Obfuscating PHP that still runs.
Each app/*.php file becomes <?php return eval(gzinflate(xor(base64_decode('...'))));. Namespaces and class names stay intact (they live inside the eval'd code), so Laravel's reflection/autoload still works. Honest caveat: pure-PHP obfuscation is deterrence, not DRM.
4. SQLite ≠ MySQL.
A "Force SQLite" toggle rewrites a MySQL .env to SQLite — handy, but it'll break on MySQL-specific SQL. That's why the MariaDB bundle exists.
Stack
C# / .NET 10 (WinForms builder + launcher) · FrankenPHP · Caddy · MariaDB · Inno Setup.
Try it
👉 github.com/fdciabdul/WinRavel — download WinRavel-Setup.exe from Releases.


Top comments (0)