Caddy + Static-PHP-CLI = ❤️
December 2, 2025 by prashanthca
A modern, tiny, dependency-free PHP runtime with a first-class web server
When you combine Caddy, the elegant, zero-config, HTTP/3-ready web server, with Static-PHP-CLI, the fully self-contained static PHP binary… something magical happens. You get a portable, minimal, and production-capable PHP stack that fits in your pocket and runs almost anywhere ‐ without extensions, package managers, or system dependencies.
In this post, we’ll dive into why the combination is powerful, how to set it up cleanly, and what you can do with it.
Why This Combination Works: The Power of Static Binaries
For decades, running PHP meant installing an OS-level package, configuring a web server (Apache or Nginx), and setting up a dedicated FastCGI Process Manager (PHP-FPM). This traditional stack is robust but often bloated and highly dependent on the host operating system.
Caddy and Static-PHP-CLI dismantle this complexity.
Component 1: Caddy — The Simple Powerhouse
Caddy is arguably the best modern web server available. Its key advantages are:
-
Zero-Config HTTPS: By default, Caddy handles certificates via Let’s Encrypt automatically. If you’re running locally, it uses self-signed certificates with a managed trust store.
-
Simple Configuration: The
Caddyfileis intuitive and declarative, making complex reverse proxies and static file serving trivial. -
Modern Protocol Support: Caddy speaks HTTP/2 and HTTP/3 natively.
Component 2: Static-PHP-CLI — PHP Reimagined
Static-PHP-CLI (or similar static builds like Bref’s PHP-FPM layer) takes the entire PHP interpreter, along with common extensions (like pdo, curl, json), and compiles them into a single, self-contained binary.
This offers revolutionary benefits for deployment:
-
Dependency-Free: No need for
apt,yum, or specific system libraries. -
Minimal Footprint: Ideal for Docker scratch images, serverless environments, or tiny VMs.
-
Portability: Just copy the single binary and run it.
The Synergy: A Self-Contained Stack
The magic lies in eliminating all external dependencies except for two files: caddy and php.
Traditional Stack: OS Kernel -> Apache/Nginx -> PHP-FPM Daemon -> PHP libraries/extensions. Modern Static Stack: OS Kernel -> caddy binary + php static binary.
This synergy results in a stack that is incredibly fast to deploy, easy to version control, and perfect for modern deployment strategies like Docker containers or deploying microservices to constrained environments.
Setting Up the Minimal PHP Stack
Getting this stack running only requires three files: the Caddy binary, the Static PHP binary, and the Caddyfile configuration.
Prerequisites
-
Download Caddy: Get the binary for your architecture from the Caddy downloads page.
Bash
# Example for Linux AMD64 curl -L "https://caddyserver.com/api/download?os=linux&arch=amd64" -o caddy chmod +x caddy -
Download Static-PHP-CLI: Download a static build. For this example, we’ll assume the binary is named
php-static.Bash
# (Get binary from project site/release page) chmod +x php-static -
Create your application root:
Bash
mkdir my-app cd my-app echo '<?php echo "<h1>Hello from Caddy and Static PHP!</h1>"; phpinfo();' > index.php
Step 1: The Caddyfile Configuration
Create a file named Caddyfile in your my-app directory. This configuration tells Caddy to listen on port 8080 and proxy PHP requests using the FastCGI protocol to a local port (9000).
Code snippet
# Caddyfile
:8080 {
# Set the root directory for file serving
root * .
# Serve static files first
file_server
# Handle PHP requests via FastCGI
# We proxy to 127.0.0.1:9000, where our static PHP-FPM process will listen.
php_fastcgi 127.0.0.1:9000
}
Step 2: Running Static-PHP as FPM
The key step is telling the static PHP binary to run as a FastCGI Process Manager (FPM) daemon, listening on the port specified in the Caddyfile (9000).
In your application directory (my-app), run the following command in a dedicated terminal:
Bash
# Start the static PHP binary in FPM mode
./php-static --fpm --listen 127.0.0.1:9000
This command starts a lightweight, self-contained PHP-FPM process, completely ignoring any system-installed PHP versions.
Step 3: Running Caddy
In a second terminal window, start Caddy:
Bash
# Start Caddy using the Caddyfile in the current directory
../caddy run
Caddy will initialize, load the configuration, and begin listening.
Success! You now have a complete, production-ready PHP stack running. Navigate to http://localhost:8080 in your browser. You will see the phpinfo() output confirming that the static PHP binary is handling the requests, routed cleanly by Caddy.
What You Can Do With It
This highly portable Caddy + Static-PHP-CLI combination unlocks several powerful use cases:
-
Microservice Deployment: Deploy small, dedicated PHP APIs without spinning up a full OS image or a heavy container. The resulting Docker image can be incredibly small (often under 50MB).
-
Self-Contained CLI Tools: If your application is a CLI tool that needs a temporary web interface (for configuration or monitoring), this stack provides a zero-setup web server.
-
CI/CD Testing: Use the static binaries directly in your Continuous Integration pipeline to run integration tests against a real web server environment instantly, without waiting for package installs.
-
Edge Computing/IoT: Deploy lightweight PHP applications to resource-constrained devices where traditional Linux package management might be overkill or unavailable.
The simplicity of Caddy combined with the portability of a statically compiled runtime creates a PHP stack that is fast, flexible, and perfectly suited for the demands of modern cloud-native development.
