This repository provides the Windows build of Rapira. It serves HTTP and unary gRPC, gRPC-Web, and Connect through embedded PHP. See UPSTREAM.md for the pinned core and contract revisions.
- Rapira for Windows supports Windows 10, Windows 11, and Windows Server on x64. It supports Windows 11 on ARM64.
- It embeds ZTS PHP 8.4 or 8.5. The main Rapira build embeds NTS PHP.
- It produces
rapira.exeand requires the Microsoft Visual C++ Redistributable for the target architecture. - Release archives use the name
rapira-v<VERSION>-php<8.4|8.5>-windows-<x86_64|arm64>.zip. Each architecture has arapira-v<VERSION>-windows-<x86_64|arm64>-SHA256SUMS.txtfile. - Each archive contains
rapira.exe, its project-built PHP runtime, extension DLLs,php.ini, PHP build metadata, examples, and licenses. - The PHP profile includes OpenSSL, cURL, SQLite, PostgreSQL, PDO, XML, iconv, mbstring with mbregex, intl, FFI, gettext, igbinary, and Redis. See ci/php-configure-flags.txt for the full profile. OPcache is included with JIT disabled.
- Each server process has its own OPcache cache by default. Its interpreter threads share that cache.
- Extension DLLs must match the bundled PHP minor, ZTS setting, architecture, and toolchain. See the PHP Windows extension requirements.
Download the archive for your PHP minor and architecture from GitHub Releases. Extract the archive. Run rapira.exe from that directory.
.\rapira.exe serve C:\app\rapira.tomlSee examples/rapira.toml for HTTP and gRPC pool configuration. HTTP supports classic, worker, and dispatcher modes. gRPC supports dispatcher mode.
The gRPC plugin supports bearer-token authentication before calls reach PHP. See gRPC authentication for the token file and TLS proxy configuration.
- Rapira starts one process. Each plugin has a fixed pool of PHP interpreter threads and its own work queue.
- MINIT runs once before the interpreter threads start.
<plugin>.pool.processessets the interpreter thread count for that plugin.- The Windows build supports only a static pool. It rejects the main build's scaling settings. It does not support reload or status requests.
<plugin>.pool.max_requestsrecycles an interpreter after a request quota with jitter.- A failed worker or dispatcher boot retries within five seconds without client traffic. An idle or active interpreter keeps its pool ready while another interpreter retries.
getmypid()returns the same process ID in every interpreter.- A native crash in one interpreter thread stops the server process.
http.listenandgrpc.listenaccept TCP addresses.- The first Ctrl+C or Ctrl+Break event drains active work. A second event forces exit code 130.
- Closing the console window does not start a drain.
- A forced exit can leave the pidfile. Remove a stale pidfile before the next start.
- Rapira does not register with Windows Service Control Manager. Use WinSW when you need a Windows service.
Add a TCP endpoint to an HTTP or gRPC server:
[observability]
listen = "127.0.0.1:9180"
keepalive_timeout_secs = 60
[observability.metrics]
[observability.probes]listen and at least one endpoint table are required. The endpoint runs on a separate thread with one Tokio IO worker. It runs no PHP.
GET /metricsreturns Prometheus text metrics.GET /livezreturns 200 withokwhile the server can answer.GET /readyzreturns 200 when every PHP pool has an idle or active interpreter. It returns 503 and lists pools without a ready interpreter during boot or a failed restart.- Other paths, methods, and disabled endpoints return 404.
Metrics with a pool label describe one plugin pool. A worker is an interpreter thread. Request and restart counters survive interpreter recycling. Shared queues are counted once per pool.
| Metric | Value |
|---|---|
rapira_workers |
Interpreter threads by starting, idle, active, or draining state |
rapira_workers_configured |
The pool's configured processes count |
rapira_requests_total |
Work completed or rejected by the host |
rapira_requests_failed_total |
Work the host could not complete |
rapira_requests_failed_on_full_queue_total |
Submissions that found a full queue and never entered it |
rapira_requests_queued |
Queued work and submissions waiting for queue space |
rapira_script_restarts_total |
Entrypoint restarts in interpreter threads |
rapira_build_info |
Rapira and linked PHP version labels, with value 1 |
An intake timeout adds one request and one failure. A cancelled submission that found a full queue adds only to the full-queue failure counter. The Windows endpoint has no per-worker process-exit or memory series because all interpreters share one process.
- The static middleware rejects decoded paths that contain a backslash or colon and any path segment that contains a tilde followed by a digit. It ignores trailing dots and spaces when it checks the file name against
forbid. - With the default Windows socket rules, another process under the same user account can bind a specific address on a port where Rapira listens on a wildcard address. Bind Rapira to a specific production address.
Source builds require native PowerShell 7, native MSVC tools with a Windows SDK, native LLVM with libclang.dll, and Rust. ARM64 dependency builds also use native CMake. Use tools and PHP files for the host architecture. Release jobs build PHP 8.4 and 8.5 ZTS from verified official source on native x64 and ARM64 runners.
Generate clangd commands with .\dev.ps1 -Devel <native-devel-directory> -Task clangd. The .clangd file reads them from the ignored target/clangd directory. See CONTRIBUTING.md for all Windows build commands.