A deterministic local development stack manager for Windows x64
βοΈ Deterministic State Machine β’ π§± Apache Β· MySQL Β· PHP β’ π‘οΈ Job-Object Isolation β’ π¦ Rust
Features β’ Installation β’ Architecture β’ License
RAMPP is a deterministic local development stack manager for Windows x64. It orchestrates Apache, MySQL, and PHP through a formally defined state machine β no race conditions, no orphaned processes, no partial config writes.
Replace XAMPP or Laragon with something you can read, audit, and trust.
- Deterministic β every state transition is explicit:
STATE + EVENT β NEW STATE + SIDE EFFECTS - Safe β every service runs inside a Windows Job Object; killing RAMPP kills the entire process tree, no zombies
- Observable β all transitions logged; events are replayable for debugging
- Fast β sub-second UI, Apache ready in β€ 3 s, MySQL ready in β€ 5 s
- Self-provisioning β generates
httpd.conf,my.ini,php.ini,phpmyadmin.confandconfig.inc.php, and initialises the MySQL data directory on first run; marker-gated so hand-edited files are never clobbered - phpMyAdmin integration β optional one-click admin toggle, wired automatically to the running MySQL + PHP instances
- System tray β lives quietly in the tray; full egui status window on demand
- Crash recovery β automatic restart with exponential backoff (1 s β 2 s β 4 s β 8 s β Error)
- Quick access β open localhost in the browser or jump straight to a service config file from each row
- Live uptime β each running service shows elapsed uptime; startup progress shown during Starting
- Log tools β copy the full log to clipboard or clear it with one click; error badges are dismissible
| Requirement | Notes |
|---|---|
| Windows 10/11 x64 | Only supported platform |
| Apache HTTP Server 2.4 (Win64, VS17) | From Apache Lounge |
| MySQL 9.x Community (ZIP) | ZIP archive, not installer |
| PHP 8.x Thread Safe (ZIP) | TS x64 ZIP β required for PHP-CGI FastCGI |
| phpMyAdmin (ZIP) | Optional β enables the built-in admin toggle |
| Visual C++ Redistributable 2022 x64 | Required by Apache Lounge builds |
Grab rampp.exe from the latest release and place it at:
C:\rampp\rampp.exe
Extract the Apache ZIP so that httpd.exe ends up at:
C:\rampp\apache\bin\httpd.exe
Extract the MySQL ZIP so that mysqld.exe ends up at:
C:\rampp\mysql\bin\mysqld.exe
Extract the PHP ZIP so that php-cgi.exe ends up at:
C:\rampp\php\php-cgi.exe
Optionally, extract phpMyAdmin so that index.php ends up at:
C:\rampp\phpmyadmin\index.php
phpMyAdmin is not required for Apache, MySQL or PHP to run β it only unlocks the admin toggle in the status window (see Configuration ownership below for the files RAMPP generates for it).
The final layout should look like:
C:\rampp\
rampp.exe
apache\
bin\httpd.exe
modules\
...
mysql\
bin\mysqld.exe
lib\
share\
...
php\
php-cgi.exe
ext\
...
phpmyadmin\ (optional)
index.php
...
Run vc_redist.x64.exe if you haven't already.
Double-click rampp.exe. On first launch RAMPP will:
- Generate
rampp.toml(ports 8080 + 3306 + 9000) - Create
apache\conf\httpd.conf,apache\htdocs\index.php,mysql\my.ini,php\php.ini, and (ifphpmyadmin\exists)apache\conf\phpmyadmin.conf+phpmyadmin\config.inc.php - Run
mysqld --initialize-insecure(~10β20 s, once only), then create a127.0.0.1account so RAMPP's own TCP connections (health checks, phpMyAdmin) can authenticate β see the note below - Show the system tray icon and status window
Click Start All to bring up all three services. Apache will be at http://127.0.0.1:8080/, MySQL at 127.0.0.1:3306 (root, no password), and PHP-CGI will be listening on 127.0.0.1:9000 (FastCGI, proxied from Apache).
Why a second MySQL account?
mysqld --initialize-insecureonly ever createsroot@localhost. RAMPP's own connections β health checks, phpMyAdmin, anything inrampp.toml's[phpmyadmin]section β are TCP to127.0.0.1(the loopback-only security constraint), which is a distinct grant fromlocalhostand would otherwise be refused outright. First-run initialization also grants<mysql_user>@'127.0.0.1'(default userroot, empty password) full privileges β but notWITH GRANT OPTIONβ so this works out of the box.
RAMPP generates httpd.conf, my.ini, php.ini, phpmyadmin.conf and
phpMyAdmin's config.inc.php, and each one carries a marker line on its first
line identifying it as generated.
- Keep the marker and RAMPP keeps the file in sync β ports, document root and
phpMyAdmin wiring all follow your settings automatically. Your previous content
is saved beside it as
.bakwhenever RAMPP changes it. - Remove the marker and the file becomes yours. RAMPP will never write it again. If a port then needs to move because something else holds it, the affected service reports an error naming the file instead of silently misconfiguring itself.
Upgrading to 1.5.0: before 1.5.0, php.ini and my.ini were never
regenerated once created. If you edited either of them while leaving the marker
line intact, your changes will be replaced on first run and saved to
php.ini.bak / my.ini.bak. Remove the marker line first if you want RAMPP to
leave the file alone permanently.
phpMyAdmin during a service crash: phpMyAdmin now stays enabled if MySQL or
PHP crashes, rather than switching itself off and requiring a manual re-toggle.
If PHP crashes, Apache's mod_proxy_fcgi can't reach the PHP-CGI backend and
returns 503 until auto-retry restarts it; if MySQL crashes while Apache/PHP
stay up, phpMyAdmin's own PHP code hits the failed connection instead, which
surfaces as an in-page connection error, not an Apache-level 503.
Edit C:\rampp\rampp.toml to change ports:
install_dir = "C:\\rampp"
[apache]
port = 8080
[mysql]
port = 3306
[php]
port = 9000
[phpmyadmin]
mysql_user = "root"
mysql_password = ""RAMPP validates the entire file before accepting it β an invalid config is rejected completely and the last valid config is preserved. After editing, restart the affected service from the UI.
[phpmyadmin] sets the credentials RAMPP uses for its own MySQL connections β
health checks and phpMyAdmin's config.inc.php β and the account that first-run
initialization grants at 127.0.0.1, described above. It does not need to match
any account you create yourself for other tools.
See Configuration ownership above for which files RAMPP regenerates and which it leaves alone.
RAMPP is a single binary built around a pure reducer:
STATE + EVENT β NEW STATE + SIDE EFFECTS
| Layer | File | Role |
|---|---|---|
| Types | state.rs |
AppState, ServiceState machine, all constants |
| Events | events.rs |
Event enum + SideEffect enum |
| Logic | reducer.rs |
Pure function β no I/O, fully unit-tested |
| I/O | executor.rs |
Translates SideEffects into process ops and threads |
| Processes | process.rs |
Windows Job Object spawn/kill |
| Health | health.rs |
Apache HTTP + MySQL TCP + PHP TCP readiness and health checks |
| Config | config.rs |
rampp.toml load/validate + atomic write |
| Paths | paths.rs |
Install-dir contract, traversal rejection, symlink rejection |
| Log | logger.rs |
Bounded ring buffer (1 000 lines) |
| Apache conf | apache_conf.rs |
Generate httpd.conf with PHP FastCGI proxy |
| MySQL conf | mysql_conf.rs |
Generate my.ini, initialize data dir, grant the 127.0.0.1 account |
| PHP conf | php_conf.rs |
Generate php.ini for PHP-CGI |
| phpMyAdmin conf | phpmyadmin_conf.rs |
Generate phpmyadmin.conf and config.inc.php |
| Provisioning | provision.rs |
Marker-gated, diff-driven reconciler for every managed config file |
| Tray | tray.rs |
Windows system tray |
| UI | ui.rs |
egui status window |
Stopped ββSTARTβββΊ Starting ββPROCESS_READYβββΊ Running
β β
PROCESS_EXIT PROCESS_EXIT
β β
ββββββββββββΊ Crashed ββββββββ
β
AUTO_RETRY (Γ4, backoff)
β
Starting
β
(max retries exceeded)
β
Error
Any state ββFATAL_ERRORβββΊ Error
Running ββSTOPβββΊ Stopping ββPROCESS_EXITβββΊ Stopped
Every service spawns inside a dedicated Windows Job Object with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE. Dropping the job handle terminates the entire process tree β Apache child workers, MySQL threads, everything β with no orphans.
If AssignProcessToJobObject fails the service transitions directly to Error and never starts.
| Service | Check | Pass condition | Interval | Fail threshold |
|---|---|---|---|---|
| Apache | HTTP GET 127.0.0.1:port/ |
200β399 + Server: Apache |
2 s | 3 consecutive |
| MySQL | TCP connect + 4-byte greeting | Handshake starts | 2 s | 3 consecutive |
| PHP | TCP connect to FastCGI port | Connection succeeds | 2 s | 3 consecutive |
Three consecutive failures trigger HEALTH_CHECK_FAIL, which kills the service and schedules a retry.
# Prerequisites: Rust stable toolchain (rustup.rs), MSVC build tools
git clone https://github.com/rbenzing/RAMPP.git
cd rampp
cargo build --release
# Binary at target\release\rampp.exeRun the test suite:
cargo test
cargo clippy -- -D warnings
cargo fmt -- --check- Services bind to
127.0.0.1only β no external exposure by default - All binary paths are absolute and validated against the install directory β no PATH-based execution
- Environment variables are sanitised before spawning child processes
- Config writes are atomic (
temp β fsync β rename) β a crash during write cannot corrupt the config - Symlinks are rejected for the config directory, binaries, and data directory
- MySQL is initialised with
--initialize-insecure(no root password); first run also grants<mysql_user>@'127.0.0.1'full privileges (noWITH GRANT OPTION) so RAMPP's own loopback connections authenticate β suitable for local development only
RAMPP is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License v3.0.
Built by Russell Benzing. RAMPP is a deterministic, auditable alternative to XAMPP/Laragon for local Windows development.
- Issues: GitHub Issues
- Releases: github.com/rbenzing/RAMPP/releases
If RAMPP is useful to you, you can support the work: