# PHP hosting

> Source: https://ferron.sh/docs/use-cases/content/php

Ferron can run PHP applications through CGI or FastCGI. FastCGI is the recommended approach for most deployments. PHP worker processes stay alive between requests. This reduces process startup overhead and improves throughput.

## PHP through FastCGI (recommended)

To run PHP with FastCGI (commonly PHP-FPM), use `fcgi_php`:

```ferron
# Example configuration with PHP through FastCGI. Replace "example.com" with your domain name.
example.com {
    root /var/www/html # Replace "/var/www/html" with your PHP app directory
    fcgi_php unix:///run/php/php8.4-fpm.sock # Replace with your PHP FastCGI socket or TCP URL

    # If using PHP-FPM over a Unix socket, ensure the socket is accessible by Ferron.
    # For example, in your PHP-FPM pool configuration:
    #   listen.owner = ferron
    #   listen.group = ferron
}
```

You can also point `fcgi_php` to TCP listeners (for example `tcp://127.0.0.1:9000/`). Use this when your PHP FastCGI server does not use a Unix socket.

### Disabling PHP in specific locations

You can disable PHP FastCGI for specific locations within a domain that has `fcgi_php` enabled globally. Use `fcgi_php false` in a `location` block. This stops the PHP backend from processing `.php` files in that scope:

```ferron
example.com {
    root /var/www/html
    fcgi_php unix:///run/php/php8.4-fpm.sock

    # Disable PHP execution for static file paths
    location /static {
        fcgi_php false
        root /var/www/static
    }

    # Disable PHP for API/proxy endpoints
    location /api {
        fcgi_php false
        proxy http://localhost:3000
    }
}
```

This is useful when you have a mixed deployment. For example, a PHP application that serves static files or proxies to another backend for certain paths. Without `fcgi_php false`, Ferron attempts to process `.php` files in those locations through the PHP backend. This could cause unexpected behavior.

## PHP through CGI

If you specifically want classic CGI execution, enable `cgi` and map the `.php` extension:

```ferron
# Example configuration with PHP through CGI. Replace "example.com" with your domain name.
example.com {
    root /var/www/html # Replace "/var/www/html" with your PHP app directory
    cgi {
        extension ".php"
    }
}
```

CGI is functional but usually slower than FastCGI for production workloads. Ferron starts a PHP process per request. For more control, see [Configuration: FastCGI support](https://ferron.sh/docs/configuration/content/fastcgi.md).

> [!tip]
>
> - If you use PHP-CGI with the CGI module, you may need `cgi.force_redirect = 0` in your CGI `php.ini`. Without this setting, requests can fail with a force-cgi-redirect warning.
> - If PHP files download instead of executing, verify you enabled either `fcgi_php` or `cgi` + `extension ".php"` in the correct domain/location block.

## Distributed tracing with PHP

PHP applications that use CGI or FastCGI automatically receive W3C Trace Context headers (`traceparent`, `tracestate`, and `baggage`) when tracing is enabled in Ferron. These headers appear as CGI environment variables (`HTTP_TRACEPARENT`, `HTTP_TRACESTATE`, `HTTP_BAGGAGE`).

With the official [OpenTelemetry SDK for PHP](https://opentelemetry.io/docs/languages/php/), these headers enable distributed tracing out of the box. The SDK reads the incoming `traceparent` header and creates child spans. This connects your PHP backend traces to the rest of your infrastructure.

> [!info]
> You need only install and configure the OpenTelemetry SDK. No other PHP-side configuration is required. See [Tracing configuration](https://ferron.sh/docs/configuration/observability/tracing.md) for details on enabling trace generation and sampling in Ferron.

> [!important]
> Keep upload/download directories outside of `cgi-bin` when using CGI to avoid accidental CGI execution of uploaded files.

## See also

- [PHP edge caching (LSCache)](https://ferron.sh/docs/use-cases/content/php-edge-cache.md): Use Ferron as an edge caching proxy in front of Apache. This setup supports the LSCache plugin for PHP hosting.