Skip to main content
This is the development environment — a checkout you can run and change. For installing FaPost on a server, see Self-hosting instead; the two have different goals and different trade-offs.
There are two ways to start. Docker gives you a runtime that matches production; a local install is faster if you already run PHP that way.

With Docker

Nothing to install but Docker itself.
That builds a development image from the same base as the production one, mounts your working tree, and starts PostgreSQL, Redis, Horizon, the scheduler and Vite. Edits take effect immediately — no rebuild.
The application is on http://localhost:8000, Vite on http://localhost:5173.

Why the dev image shares the production base

The development image is the dev target of docker/Dockerfile, built from the same base stage as the production one. That is deliberate: a separately assembled development image would have its own PHP build and extension set, and every difference between the two becomes a bug that only appears after deployment. What does differ is only what should:
  • dev Composer dependencies are installed
  • the source is mounted rather than copied, so edits are live
  • opcache.validate_timestamps=1, or nothing you type would take effect
  • the container runs as your user id, so files it writes stay yours
  • Xdebug is available, off unless the image is built with INSTALL_XDEBUG=1
vendor/ and node_modules/ are deliberately not mounted from the host. They are installed inside the container for its own platform, and sharing them would mix binaries built for a different OS.

Xdebug

Step debugging is trigger-based, so it costs nothing until you ask for it. The callback address defaults to host.docker.internal, which resolves on Linux too because compose maps it to the host gateway. If your IDE is elsewhere:

On your own machine

Requirements:
  • PHP 8.4 or newer
  • Composer 2
  • Node.js 20+ and npm
  • PostgreSQL 15+ or compatible
  • Redis
  • PHP extensions: pdo_pgsql, redis, intl, bcmath, gd, zip, plus pcntl and posix for Horizon
Check them all at once:
1

Install dependencies

2

Prepare the environment

.env.example ships the credentials the Docker stack creates for itself, so that path works unedited. Running against services you provisioned yourself means pointing these at them:
If your Redis runs without requirepass, set REDIS_PASSWORD=null rather than leaving it empty — Laravel reads the literal null as “no password”, and an empty string is a password of zero length.
3

Migrate and run

composer run dev starts the Laravel dev server, the queue listener, pail log tailing, and the Vite dev server together.

The Makefile

The repository root has a Makefile that wraps the everyday commands. It is a front-end, not a second source of truth: where Composer holds a sequence (setup, dev, test) the target delegates to it, so there is one definition of each.
make with no arguments prints each target with its description and, under it, the command that would actually run. Read that before running anything unfamiliar: it also shows whether the command goes through a container.

Running commands inside a container

By default every target runs against whatever PHP is on your PATH. If your PHP lives in a container — devilbox, a Compose stack, anything docker exec can reach — set CONTAINER and the PHP-side targets are prefixed with docker exec automatically:
To stop typing it, put the setting in .make.local at the repository root. The file is git-ignored: it describes your machine, not the project.
WORKDIR defaults to devilbox’s layout, /shared/httpd/<directory name>; set it when your container mounts the checkout elsewhere. The container name comes from Docker Compose: <project>-<service>-<index>, so devilbox’s PHP service is server-php-1 and its PostgreSQL is server-pgsql-1. Targets that run host tools stay on the host regardless of CONTAINER: make dev (Vite needs the host’s Node), make docs-dev (Mintlify), the tunnel targets. make shows which is which.

Adding packages on top of Core

To work against a package Core does not require — a Solution, a Plugin or a private extension — without touching Core’s composer.json, use a composer overlay. See Development setup → Packages Core does not require.

Checks

Or, through the Makefile, make test, make test-arch, make fix. See Testing and architecture checks for what each covers.

Running it like production

To exercise the actual production images locally, follow Docker Compose. Same topology, different images — useful for reproducing something that only happens with a compiled config cache and no dev dependencies.