VS Code Apache Launcher
Windows-first VS Code extension for starting a project-scoped Apache server with optional PHP support, development ports, and temporary .htaccess fallback routing.
Behavior
- Start is available only from a local
.php or .html file inside an open workspace folder.
- The containing workspace folder becomes Apache
DocumentRoot.
/ routes to the file from which Start was invoked when the project has no local .htaccess.
- Other URL paths continue to resolve from the same workspace root.
- The default host is
localhost.
- Auto port selection uses the first available claimed port from
55000 through 55100.
- Ports 80 and 443 are not launcher defaults.
- The generated URL opens in the default browser after Apache passes readiness checks.
Window Ownership
Each VS Code window can own at most one Apache server.
- Start is rejected while that window is already starting, running, or stopping Apache.
- Stop and Restart operate only on the server owned by the current window.
- Stop and Restart are rejected when the current window has no applicable session.
- Separate VS Code windows may run separate projects concurrently.
- An OS-backed named-pipe lease plus claim metadata prevents concurrent windows from receiving the same port; Windows releases the lease automatically if an extension host exits.
- Each window receives its own runtime directory, Apache config, PID file, temporary fallback, and ownership manifest.
- One window never stops or removes resources belonging to another live window.
Apache on Windows may show a parent process and one or more worker processes in Task Manager. The extension records and verifies the owned process tree rather than assuming one PID represents the complete server.
Commands
The editor context menu and Command Palette provide:
Apache Server: Start
Apache Server: Stop
Apache Server: Restart
Apache Launcher: Validate Setup
Apache Launcher: Open Served URL
Apache Launcher: Reveal Runtime Config
Restart retains the original start file and workspace. It does not depend on whichever editor happens to be active later. Current settings are validated again, the prior port is reused only when the current host and port policy still allow it, and generated runtime artifacts are rebuilt before launch.
Settings
apache.binPath: absolute path to httpd.exe.
apache.baseConfigPath: absolute path to a base Apache config/template.
apache.globalHtaccessPath: optional absolute path to a global fallback .htaccess template. The bundled template is used when this setting is empty.
server.host: generated server host, default localhost.
server.portMode: auto or fixed, default auto.
server.fixedPort: port used in fixed mode, default 55000.
server.portRangeStart: first auto-port candidate, default 55000.
server.portRangeEnd: last auto-port candidate, default 55100.
php.enabled: enables PHP processing in generated runtime configuration.
php.cgiPath: absolute path to php-cgi.exe.
php.iniPath: absolute path to php.ini.
Example OSPanel paths:
apache.binPath=C:\OSPanel\modules\PHP-8.4\Apache\bin\httpd.exe
apache.baseConfigPath=C:\OSPanel\modules\PHP-8.4\Apache\conf\httpd.conf
php.cgiPath=C:\OSPanel\modules\PHP-8.4\PHP\php-cgi.exe
php.iniPath=C:\OSPanel\modules\PHP-8.4\PHP\php.ini
When the base config already loads php_module, Apache uses that module's base-config wiring. Otherwise, the generated virtual host wires .php requests through the configured CGI executable and INI path.
.htaccess Strategy
Precedence is deterministic:
<workspace>\.htaccess when present.
- The configured
apache.globalHtaccessPath template.
- The extension's bundled fallback template.
Configured and bundled fallback templates are copied to owner-specific temporary storage. The extension appends a runtime-only / rewrite for the selected start file. It never writes .htaccess into the project and removes the temporary fallback after Stop, failed Start, or window deactivation.
Runtime Configuration
Runtime files are written under VS Code extension global storage, not into Apache or the project. The generated copy:
- assigns the selected workspace as
DocumentRoot;
- assigns an owner-specific PID file;
- adds only the claimed development listener;
- disables active inherited
Listen directives in the generated copy;
- leaves the configured base Apache file unchanged;
- runs
httpd -t before launch;
- reports Start success only after the selected host and port accept a connection.
Use Apache Launcher: Reveal Runtime Config to inspect the exact generated file.
Shutdown And Recovery
Normal VS Code window closure awaits shutdown of that window's verified Apache process tree. An unexpected Apache exit changes the status to Apache: Crashed, retains restart context, and offers Restart without automatically relaunching.
If Windows or VS Code is force-terminated before cleanup completes, the ownership manifest remains. On a later activation, the extension reconciles only manifests whose owning extension-host process is confirmed dead. Ambiguous process identities are retained and logged instead of being killed.
Development
Requirements:
- Node.js 22 LTS (
.nvmrc)
- npm 10.x
- Windows for runtime/process integration
Commands:
npm install
npm run build
npm run lint
npm test
npm run test:real
npm run package
npm test launches VS Code with temporary --user-data-dir and --extensions-dir paths. Therefore, a Marketplace installation of gvb.vscode-apache-launcher in the regular VS Code profile is not loaded by automated tests.
npm run test:real additionally runs the gated OSPanel Apache E2E using the paths shown above. It launches two independent owners with same-named index.php files, verifies distinct content and ports, exercises isolated Restart/Stop/deactivation, and fails if either runtime config still owns a process afterward.
For manual testing, use an isolated profile as well. Reuse the same isolated directories for both windows when testing cross-window port coordination:
$profile = Join-Path $env:TEMP 'vscode-apache-dev-profile'
code --new-window --extensionDevelopmentPath="$PWD" --user-data-dir="$profile\user-data" --extensions-dir="$profile\extensions"
Run the same command again for the second development window. Do not use the regular profile for this test because the published extension has the same extension identifier as the development build.
Troubleshooting
- Setup validation fails: verify all configured paths are absolute and point to existing files.
- Syntax validation fails: open the
Apache Launcher output channel and inspect [verify] lines.
- No auto port is available: increase
server.portRangeEnd or stop another development server.
- PHP source is displayed: confirm
php.enabled, inspect whether the base config loads php_module, and verify the CGI paths when it does not.
- Stop cannot verify exit: inspect
[process] output. Ownership is intentionally retained rather than risking termination of an unrelated PID.
- A live legacy PID is reported after upgrade: the extension does not kill it because old versions did not record enough ownership identity; stop it manually after verifying it belongs to Apache Launcher.
Scope
Version 1 remains Windows-only. Linux/macOS support, Windows Service control, HTTPS certificate automation, and multi-vhost orchestration are out of scope.