Skip to content

Commit c020b28

Browse files
Add comprehensive project README
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UQoBqonc9qeRXk39VM9VLX
1 parent 27c15d9 commit c020b28

1 file changed

Lines changed: 139 additions & 0 deletions

File tree

README.md

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
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

Comments
 (0)