Caddy + Static-PHP-CLI = ❤️
PHP Web Hosting

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:

  1. 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.

  2. Simple Configuration: The Caddyfile is intuitive and declarative, making complex reverse proxies and static file serving trivial.

  3. 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

  1. 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
    
  2. 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
    
  3. 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.