1: Introduction

Phlo is an integrated platform with its own full-stack language. You write .phlo source files; Phlo compiles them to PHP, CSS and JavaScript you can open and read, with every runtime error pointing back at the .phlo line you wrote. The same language carries four layers: the language itself, the application platform (backend resources plus the phlo.js SPA engine), the server platform (FrankenPHP, phloWS, phloWA) and the operations platform (the Phlo Dashboard). This guide covers all of them. The production release runs on a shared runtime, usually in /srv/phlo/, while each app keeps its own source, data, generated PHP and webroot.

1.1: Philosophy

1.2: Installation

Phlo requires PHP 8.3 or higher; the CLI build runs on the same PHP. For production, FrankenPHP is the recommended runtime (built-in web server, worker mode); classic PHP-FPM behind Nginx works too.

Fetch the runtime and scaffold your first app with the bundled installer:

git clone https://github.com/q-ainl/phlo.git /srv/phlo
php /srv/phlo/install.php /srv/example.nl/

The installer asks for a name, host and target, shows the runtime catalog and lets you pick resources (their @ requires are included automatically), writes the entrypoint, data/app.json, data/app.md, a first route and .gitignore, and only finishes after a clean build with concrete next steps.

Prefer a copy that cleans up after itself? Copy install.php into the new app directory and run it there; after a successful installation it removes itself:

cp /srv/phlo/install.php /srv/example.nl/ && cd /srv/example.nl && php install.php

The next sections describe what the installer sets up for you, and how to build the same thing by hand.

1.3: Project structure

A typical app:

/srv/example.nl/
  app.phlo
  page.home.phlo
  data/
    app.json
    auth.ini
    creds.ini
  php/
    app.php
    classmap.php
  release/
    www/
      app.php
  www/
    app.php

php/, www/app.js, www/app.css and release/ are build output. Only change them through the source and rebuild.

1.4: Entrypoint

Dev entrypoint in www/app.php:

<?php
require('/srv/phlo/phlo.php');
phlo_app (
    id: 'Example',
    host: 'dev.example.nl',
    auth: true,
    build: true,
    debug: true,
    app: '/srv/example.nl/',
    data: '/srv/example.nl/data/',
);

Release entrypoint in release/www/app.php:

<?php
require('/srv/phlo/phlo.php');
phlo_app (
    id: 'Example',
    host: 'stage.example.nl',
    app: '/srv/example.nl/release/',
    php: '/srv/example.nl/release/',
    data: '/srv/example.nl/data/',
);

1.5: Build

Use the CLI from the dev entrypoint:

php www/app.php build::run
php www/app.php build::lint
php www/app.php build::release

build::run transpiles the dev output, build::lint checks the generated PHP, and build::release writes the release output.

1.6: Web server

The web server points to www/ for dev and to release/www/ for stage/production. Unknown paths are rewritten to app.php.

For FrankenPHP (recommended), a single Caddyfile block is enough:

example.nl {
    root * /srv/example.nl/release/www
    php_server
}

For Nginx:

root /srv/example.nl/release/www;

location / {
    try_files $uri $uri/ /app.php?$query_string;
}

We use essential cookies to make this site work. With your permission we also use analytics to improve the site.