Puppet FrankenPHP Module
Overview
This Puppet module installs and manages FrankenPHP on Debian-based systems (Debian, Ubuntu) using the official .deb package.
It is designed for a secure, multi-tenant architecture by managing two distinct components:
- FrankenPHP (Proxy): A main Caddy/FrankenPHP service, installed via
.deband managed bysystemd, which acts as a reverse proxy. - Isolated Applications: Individual PHP applications, each running in its own
frankenphpprocess under a dedicated system user. These processes are managed by Supervisor for process and user isolation.
Prerequisites
This module has external dependencies (see metadata.json):
puppetlabs/concat: Used to assemble the mainCaddyfilefrom fragments.puppetlabs/stdlib: For data types (Stdlib::Absolutepath).ajcrowe/supervisord: Used to manage the isolated application processes.
You must ensure that Supervisor is installed on the target node. This module only manages configurations for Supervisor, not its installation.
# In your base profile or site.pp
include 'supervisor'
Usage
The architecture is deployed in two steps for each website:
- Declare the isolated application (
frankenphp::app). - Declare the public-facing vhost that points to it (
frankenphp::vhost).
1. Base Installation
Simply include the main class. This installs the FrankenPHP binary and configures the proxy service (which is empty by default).
include 'frankenphp'
2. Defining an Isolated Application (frankenphp::app)
This defined type creates a dedicated user, a root directory, a specific Caddyfile for the app, and a Supervisor service to run it on a local port.
# Declare a 'blog-app' application
frankenphp::app { 'blog-app':
ensure => present,
root_dir => '/var/www/blog',
user => 'bloguser',
listen_port => '9010', # Ensure this port is free
}
This code will:
- Create the
bloguseruser. - Create the
/var/www/blogdirectory (owned bybloguser). - Create a Caddyfile for this app (listening on
localhost:9010). - Create the
/etc/supervisor/conf.d/frankenphp-blog-app.conffile to launch this process as thebloguser.
3. Exposing the Application (frankenphp::vhost)
This adds an entry to the main proxy Caddyfile to route public traffic to the isolated application.
# Create the public vhost for blog.example.com
frankenphp::vhost { 'blog.example.com':
ensure => present,
mode => 'proxy',
proxy_target => 'localhost:9010', # Must match the app's listen_port
extra_config => @(EOT)
# Caddy will handle HTTPS automatically.
# We add the Host header for the proxy.
header_up Host {host}
EOT
,
# Ensure the proxy isn't defined until the app is managed
require => Frankenphp::App['blog-app'],
}
Classes and Defines
Class: frankenphp
The main class that orchestrates installation (frankenphp::install), proxy configuration (frankenphp::config), and the main service (frankenphp::service).
Parameters:
version(String): The FrankenPHP version to download (e.g., '1.9.1').service_ensure(String): The state of the main service (default: 'running').service_enable(Boolean): Enable the main service on boot (default: true).
Define: frankenphp::app
Manages a single isolated PHP application.
Parameters:
root_dir(Stdlib::Absolutepath): The application's document root.user(String): The username to create for this application.listen_port(String): The local port the application will listen on (e.g., '9010').group(String): The group for the user (default:$user).ensure(Enum['present', 'absent']): Whether the application should exist (default: 'present').
Define: frankenphp::vhost
Manages an entry (a "site") in the main proxy Caddyfile.
Parameters:
server_name(String): The vhost name (default:$title, e.g., 'https://www.google.com/url?sa=E&source=gmail&q=blog.example.com').mode(Enum['proxy', 'fastcgi', 'php_server']): How Caddy should handle this vhost. For this architecture, always use 'proxy'.proxy_target(Optional[String]): The reverse proxy target (e.g., 'localhost:9010').fpm_socket(Optional[String]): (Forfastcgimode) Path to the FPM socket.root_dir(Stdlib::Absolutepath): (Forphp_server/fastcgimodes) Document root.extra_config(String): A raw string of extra Caddy directives for this vhost (for logs, headers, etc.).ensure(Enum['present', 'absent']): Whether the vhost should exist (default: 'present').
Limitations
- This module only installs FrankenPHP via the
.debpackage. It does not support other installation methods or operating systems. - The installation of the
supervisorservice itself is not handled. You must install it via another module orpackageresource.
License
Apache 2.0