|
| 1 | +# frankenphp-laravel |
| 2 | + |
| 3 | +A pre-built [FrankenPHP](https://frankenphp.dev/) + **PHP 8.4** base Docker image with every PHP extension a Laravel [Octane](https://laravel.com/docs/octane) application needs already compiled in. It exists to solve one problem: cold-boot speed. Building the required extensions at container start (the usual `install-php-extensions` step) adds **2+ minutes** to first boot. By baking the extensions, Composer, and common system tooling into the image ahead of time, downstream Laravel projects can extend this image and start almost instantly. |
| 4 | + |
| 5 | +This repository contains **only the image definition and its CI pipeline** — it is not a runnable Laravel application. The published image is consumed as a base (`FROM`) by Laravel project scaffolds such as `RandomSynergy17/laravel-docker-template` and other internal apps. |
| 6 | + |
| 7 | +> Published image: `ghcr.io/randomsynergy17/frankenphp-laravel:latest` |
| 8 | +
|
| 9 | +## Features |
| 10 | + |
| 11 | +- **FrankenPHP 1.11** app server (runs Laravel Octane in worker mode via `OCTANE_SERVER=frankenphp`). |
| 12 | +- **PHP 8.4** with extensions pre-installed: `pcntl`, `pdo_pgsql`, `pgsql`, `redis`, `zip`, `intl`, `mbstring`, `bcmath`, `opcache`, `exif`, `gd`. |
| 13 | +- **Composer 2** copied in from the official `composer:2` image. |
| 14 | +- Common system tooling: `curl`, `git`, `unzip`, `zip`, plus the dev libraries needed to support the bundled extensions (`libpq-dev`, `libzip-dev`, `libicu-dev`, `libonig-dev`). |
| 15 | +- **Marker file** at `/etc/frankenphp-laravel-extensions` (contents: `image`) so a consuming project's entrypoint can detect that extensions are already baked in and skip the install step. |
| 16 | +- **Automated multi-arch publishing** to GitHub Container Registry (GHCR) on every push to `main` and on version tags. |
| 17 | +- Tuned build args — `PHP_VERSION` and `FRANKENPHP_VERSION` are overridable at build time. |
| 18 | + |
| 19 | +## Tech Stack |
| 20 | + |
| 21 | +| Layer | Choice | |
| 22 | +|-------|--------| |
| 23 | +| App server | FrankenPHP `1.11` (base image `dunglas/frankenphp:${FRANKENPHP_VERSION}-php${PHP_VERSION}`) | |
| 24 | +| Language | PHP `8.4` | |
| 25 | +| Intended runtime | Laravel Octane (worker mode) | |
| 26 | +| Dependency manager | Composer 2 | |
| 27 | +| Target databases / cache | PostgreSQL (`pdo_pgsql`, `pgsql`) and Redis (`redis` extension) | |
| 28 | +| Registry | GitHub Container Registry — `ghcr.io/randomsynergy17/frankenphp-laravel` | |
| 29 | +| CI | GitHub Actions (`docker/build-push-action`) | |
| 30 | +| License | MIT (declared via the OCI image label) | |
| 31 | + |
| 32 | +## Getting Started |
| 33 | + |
| 34 | +### Prerequisites |
| 35 | + |
| 36 | +- [Docker](https://docs.docker.com/get-docker/) (with Buildx for building locally). |
| 37 | +- A GitHub account with access to GHCR if you intend to pull the published image or push new builds. |
| 38 | + |
| 39 | +### Using the published image (recommended) |
| 40 | + |
| 41 | +Most consumers do not build this repo directly — they reference the published image as a base in their own `Dockerfile`: |
| 42 | + |
| 43 | +```dockerfile |
| 44 | +FROM ghcr.io/randomsynergy17/frankenphp-laravel:latest |
| 45 | + |
| 46 | +# Your Laravel app build steps here. |
| 47 | +# Extensions, Composer, git, unzip, etc. are already present. |
| 48 | +``` |
| 49 | + |
| 50 | +Or pull it directly: |
| 51 | + |
| 52 | +```bash |
| 53 | +docker pull ghcr.io/randomsynergy17/frankenphp-laravel:latest |
| 54 | +``` |
| 55 | + |
| 56 | +### Available tags |
| 57 | + |
| 58 | +The CI pipeline produces the following tags (see [Usage](#usage)): |
| 59 | + |
| 60 | +- `latest` — tracks the `main` branch. |
| 61 | +- `php8.4-YYYYMMDD` — date-stamped builds from `main` for version pinning. |
| 62 | +- `MAJOR.MINOR.PATCH` and `MAJOR.MINOR` — produced from `v*` semver Git tags. |
| 63 | + |
| 64 | +### Configuration / build args |
| 65 | + |
| 66 | +The image is configured at **build time** via Docker `ARG`s (override with `--build-arg`): |
| 67 | + |
| 68 | +| Build arg | Default | Description | |
| 69 | +|-----------|---------|-------------| |
| 70 | +| `PHP_VERSION` | `8.4` | PHP version of the FrankenPHP base image. | |
| 71 | +| `FRANKENPHP_VERSION` | `1.11` | FrankenPHP base image version. | |
| 72 | + |
| 73 | +Runtime environment baked into the image: |
| 74 | + |
| 75 | +| Env var | Value | Purpose | |
| 76 | +|---------|-------|---------| |
| 77 | +| `OCTANE_SERVER` | `frankenphp` | Tells Laravel Octane to use the FrankenPHP server. | |
| 78 | + |
| 79 | +The default working directory is `/app/data/app` (where a consuming project is expected to place its Laravel source). |
| 80 | + |
| 81 | +> Note: This repository ships **no `.env.example`, migrations, or application code** — database setup, migrations, and runtime env vars are the responsibility of the consuming Laravel project, not this base image. |
| 82 | +
|
| 83 | +## Usage |
| 84 | + |
| 85 | +### Build the image locally |
| 86 | + |
| 87 | +From the repository root: |
| 88 | + |
| 89 | +```bash |
| 90 | +# Build with defaults (PHP 8.4, FrankenPHP 1.11) |
| 91 | +docker build -t frankenphp-laravel:local . |
| 92 | + |
| 93 | +# Build overriding the versions |
| 94 | +docker build \ |
| 95 | + --build-arg PHP_VERSION=8.4 \ |
| 96 | + --build-arg FRANKENPHP_VERSION=1.11 \ |
| 97 | + -t frankenphp-laravel:local . |
| 98 | +``` |
| 99 | + |
| 100 | +### Publish via CI |
| 101 | + |
| 102 | +`.github/workflows/build-image.yml` builds and pushes the image automatically. It triggers on: |
| 103 | + |
| 104 | +- **Push to `main`** → tags `latest` and `php8.4-YYYYMMDD`. |
| 105 | +- **Push of a `v*` tag** (e.g. `v1.2.0`) → semver tags (`1.2.0`, `1.2`). |
| 106 | +- **Manual run** via the Actions tab (`workflow_dispatch`). |
| 107 | + |
| 108 | +The workflow logs in to GHCR using the built-in `GITHUB_TOKEN`, derives tags/labels with `docker/metadata-action`, and pushes with `docker/build-push-action@v6`. No additional secrets are required. |
| 109 | + |
| 110 | +To cut a versioned release: |
| 111 | + |
| 112 | +```bash |
| 113 | +git tag v1.2.0 |
| 114 | +git push origin v1.2.0 |
| 115 | +``` |
| 116 | + |
| 117 | +## Project Structure |
| 118 | + |
| 119 | +``` |
| 120 | +frankenphp-laravel/ |
| 121 | +├── Dockerfile # The image definition (base image, system deps, |
| 122 | +│ # PHP extensions, Composer, marker file, env) |
| 123 | +├── .github/ |
| 124 | +│ └── workflows/ |
| 125 | +│ └── build-image.yml # CI: build & push to ghcr.io on main / v* tags |
| 126 | +├── .gitignore # Ignores .DS_Store and *.log |
| 127 | +└── README.md # This file |
| 128 | +``` |
| 129 | + |
| 130 | +The entire project is intentionally minimal — its only deliverable is the Docker image produced from `Dockerfile`. |
| 131 | + |
| 132 | +## Notes |
| 133 | + |
| 134 | +- **This is a base image, not an app.** There is no Laravel codebase, `composer.json`, Caddyfile, or compose file in this repo. Application concerns (routes, migrations, env, FrankenPHP/Caddy config) live in the projects that extend this image. |
| 135 | +- **Why it exists:** baking extensions in saves the ~2 minute `install-php-extensions` step on every cold boot. A consuming project's entrypoint can short-circuit its extension-install logic by checking for the `/etc/frankenphp-laravel-extensions` marker (or via `php -m`). |
| 136 | +- **Known downstream consumers:** the `RandomSynergy17/laravel-docker-template` scaffold (`FROM ghcr.io/randomsynergy17/frankenphp-laravel`) and other internal Laravel apps (e.g. ECMS) build on this image. Keep extension/version changes here in sync with what those projects assume. |
| 137 | +- **Database orientation is PostgreSQL + Redis.** Only the `pgsql`/`pdo_pgsql` and `redis` drivers are bundled — there is no MySQL/MariaDB extension. Add `pdo_mysql` to the `install-php-extensions` list if a MySQL-based project ever needs this base. |
| 138 | +- **License:** the image is labeled MIT (`org.opencontainers.image.licenses="MIT"`), though no standalone `LICENSE` file is committed to this repo — add one if formal licensing is needed. |
| 139 | +- **Versions are pinned in the Dockerfile** (`PHP_VERSION=8.4`, `FRANKENPHP_VERSION=1.11`). Bumping either is a one-line change plus a fresh build/publish. |
0 commit comments