Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
5b27e89
Add TRUSTED_PROXY support for all variations & Caddy global imports (…
jaydrogers Jan 27, 2026
9ad2270
Do not generate SSL if DISABLE_DEFAULT_CONFIG is set (#644)
5ergiu Jan 27, 2026
595c3b7
Refactor Laravel migration script to improve isolation handling and d…
jaydrogers Jan 27, 2026
096b1ba
Add Nightwatch health check script (#572)
arnaud-ritti Jan 27, 2026
d8dc11a
Update S6 version to v3.2.2.0
jaydrogers Jan 27, 2026
4a43e49
Merge branch 'main' into release/webserver-improvements-and-fixes
jaydrogers Feb 6, 2026
0a847a0
Merge branch 'main' into release/webserver-improvements-and-fixes
jaydrogers Feb 20, 2026
f6f7925
Merge branch 'main' into release/webserver-improvements-and-fixes
jaydrogers Mar 3, 2026
03dc541
Implement retry logic and JSON validation for fetching PHP versions i…
jaydrogers Mar 3, 2026
f51ee32
Update user agent in PHP versions fetch script for improved request h…
jaydrogers Mar 3, 2026
ba1734f
Update GitHub Actions workflow to use 'ubuntu-24.04' for the build en…
jaydrogers Mar 3, 2026
53ed0f0
Update GitHub Actions workflow to use 'depot-ubuntu-24.04' for the bu…
jaydrogers Mar 5, 2026
cca4efc
Merge branch 'main' into release/webserver-improvements-and-fixes
jaydrogers Apr 13, 2026
e49228a
Merge branch 'main' into release/webserver-improvements-and-fixes
jaydrogers Apr 13, 2026
8203769
Add redirect rules to prevent SEO duplicate content across web server…
jaydrogers Apr 14, 2026
7e9a7f8
Apache: Change DirectoryMatch to LocationMatch in Apache security con…
jaydrogers Apr 14, 2026
464a036
Update PHP extension installer version from 2.9.27 to 2.10.12
jaydrogers Apr 14, 2026
a64e1bf
Improved AI agent context
jaydrogers Apr 14, 2026
92cbf92
Add import for DB facade (#673)
victorlap Apr 16, 2026
fc64ec2
Update PHP extension installer version from 2.10.12 to 2.10.15
jaydrogers Apr 16, 2026
40ec603
Merge branches 'release/webserver-improvements-and-fixes' and 'releas…
jaydrogers Apr 16, 2026
14853be
Improve verbosity for log output (#671)
jaydrogers Apr 16, 2026
a7fb85e
Changed sponsor URL
jaydrogers Apr 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/scheduled-task_update-sponsors.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
organization: true
minimum: 4900
maximum: 5100
fallback: 'No bronze sponsors yet. <a href="https://github.com/sponsors/serversideup">Become a sponsor β†’</a>'
fallback: 'No bronze sponsors yet. <a href="https://serversideup.net/sponsor/">Become a sponsor β†’</a>'
token: ${{ secrets.SPONSORS_README_ACTION_PERSONAL_ACCESS_TOKEN }}
marker: 'bronze'
template: '<a href="https://github.com/{{{ login }}}"><img src="https://github.com/{{{ login }}}.png" width="40px" alt="{{{ login }}}" /></a>&nbsp;&nbsp;'
Expand All @@ -27,7 +27,7 @@ jobs:
with:
organization: true
maximum: 500
fallback: '<p align="center"><a href="https://github.com/sponsors/serversideup"><img src="https://521public.s3.amazonaws.com/serversideup/sponsors/sponsor-empty-state.png" alt="Sponsors"></a></p>'
fallback: '<p align="center"><a href="https://serversideup.net/sponsor/"><img src="https://521public.s3.amazonaws.com/serversideup/sponsors/sponsor-empty-state.png" alt="Sponsors"></a></p>'
token: ${{ secrets.SPONSORS_README_ACTION_PERSONAL_ACCESS_TOKEN }}
marker: 'supporters'
template: '<a href="https://github.com/{{{ login }}}"><img src="https://github.com/{{{ login }}}.png" width="40px" alt="{{{ login }}}" /></a>&nbsp;&nbsp;'
Expand Down
150 changes: 127 additions & 23 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,127 @@
You are a highly skilled PHP system administrator tasked with maintaining open source PHP Docker images for Laravel applications. Your goal is to assist in creating production-ready Docker images that follow best practices for security, performance, and developer experience using the guidelines below.

1. Skills you posses deep knowledge and best practices of:
- Docker
- PHP
- Laravel
- GitHub Actions
- Shell scripting
- S6 Overlay
- Nginx
- Apache
- PHP-FPM

2. Development Guidelines:

- Follow the best practices for security, performance, and developer experience.
- Write clean, maintainable and technically accurate code.
- All entrypoint scripts for the Docker images must be POSIX compliant and able to be executed with /bin/sh.
- Any /bin/sh scripts must be compatible with Debian and Alpine Linux.
- For any /bin/bash scripts, these should work with MacOS, Linux, and WSL2.
- Never use an approach you're not confident about. If you're unsure about something, ask for clarity.

This project is open source and the code is available on GitHub, so be sure to follow best practices to make it easy for others to understand, modify, and contribute to the project.
# AI Agent Guidelines

This project maintains open source PHP Docker images (`serversideup/php`) for Laravel and other PHP applications. Images are published to Docker Hub and GitHub Packages. These images build on top of the official PHP Docker images with production-grade defaults, security hardening, and a superior developer experience through environment-variable-driven configuration. See `docs/content/docs/1.getting-started/4.these-images-vs-others.md` for the full philosophy.

## Project Structure

```
src/
variations/ # One Dockerfile per image variation (cli, fpm, fpm-apache, fpm-nginx, frankenphp)
common/ # Shared scripts and configs copied into ALL variations
usr/local/bin/ # Entrypoint and helper scripts (POSIX /bin/sh)
etc/entrypoint.d/# Numbered priority entrypoint scripts (00-*, 50-*, etc.)
s6/ # Shared S6 Overlay service definitions and install script
php-fpm.d/ # Shared PHP-FPM pool configuration templates
utilities-webservers/ # Shared web server entrypoint utilities (SSL, etc.)
scripts/ # Build tooling (Bash, not POSIX)
dev.sh # Local image builds
conf/ # PHP version matrix and base config (YAML)
generate-matrix.sh # Generates CI build matrix from YAML config
assemble-docker-tags.sh
docs/ # Nuxt 4 documentation site (see docs/AGENTS.md for docs-specific guidelines)
.github/workflows/ # CI/CD with GitHub Actions + Depot for multi-arch builds
```

## Shell Script Rules

**IMPORTANT:** There are two distinct shell environments in this project. Getting this wrong breaks images.

- **`src/` scripts** (entrypoint, healthcheck, helper scripts): MUST be POSIX-compliant `/bin/sh`. These run inside Docker containers on both **Debian** and **Alpine** Linux. No bashisms (`[[ ]]`, arrays, `local -n`, process substitution, etc.).
- **`scripts/` directory** (build tooling): Bash (`/bin/bash`). Must work on macOS, Linux, and WSL2.

### Common gotchas
- Alpine uses BusyBox `sh`, not `bash`. Commands like `readlink -f`, `sed -i` (without backup extension), and `which` behave differently.
- Use `command -v` instead of `which` in POSIX scripts.
- Use `$(...)` not backticks for command substitution.
- Test OS detection with `[ -f /etc/alpine-release ]` (Alpine) or `[ -f /etc/debian_version ]` (Debian).

## Naming Conventions

- Container scripts in `src/common/usr/local/bin/` follow the prefix pattern: `docker-php-serversideup-*` (e.g., `docker-php-serversideup-entrypoint`, `docker-php-serversideup-set-file-permissions`).
- Healthcheck scripts use: `healthcheck-*` (e.g., `healthcheck-horizon`, `healthcheck-queue`).
- Entrypoint.d scripts use numbered prefixes for execution order: `0-container-info.sh`, `1-log-output-level.sh`, `50-laravel-automations.sh`.

## Image Architecture

**There is exactly one Dockerfile per variation.** Each Dockerfile must work across all supported OS bases (Debian and Alpine). OS-specific logic is pushed into shared helper scripts (e.g., `docker-php-serversideup-dep-install-debian`, `docker-php-serversideup-dep-install-alpine`) rather than duplicating Dockerfiles. This keeps maintenance manageable across 8,000+ image tags.

Each variation Dockerfile uses multi-stage builds:
1. Shared assets are `COPY`ed from `src/common/`, `src/s6/`, `src/php-fpm.d/`, and `src/utilities-webservers/`
2. Variation-specific configs live in `src/variations/<variation>/etc/`
3. The build context is the **project root** (not `src/`), so COPY paths are relative to root: `COPY --chmod=755 src/common/ /`

### Build args used across Dockerfiles
- `PHP_VERSION`, `BASE_OS_VERSION`, `PHP_VARIATION` -- set by CI matrix or `scripts/dev.sh`
- `NGINX_VERSION` -- resolved per-OS from `scripts/conf/php-versions-base-config.yml`
- `REPOSITORY_BUILD_VERSION` -- image version label

### Variations
| Variation | Web Server | Process Manager | S6 Overlay |
|-----------|-----------|----------------|------------|
| cli | None | None | No |
| fpm | None | PHP-FPM | No |
| fpm-apache | Apache | PHP-FPM | Yes |
| fpm-nginx | NGINX | PHP-FPM | Yes |
| frankenphp | Caddy (FrankenPHP) | Built-in | No |

## Building Locally
There is a helper script in the `scripts/` directory that will build the image locally. If you attempt to build the image and Docker is not running, tell the user to start Docker Desktop or ensure that the Docker daemon is running before trying again.

```sh
# Requires: Docker with buildx, yq (for fpm-nginx NGINX version resolution)
scripts/dev.sh --variation fpm-nginx --version 8.4 --os bookworm

# Other examples
scripts/dev.sh --variation cli --version 8.5 --os alpine3.22
scripts/dev.sh --variation fpm-nginx --version 8.4 --os bookworm --no-cache
scripts/dev.sh --variation frankenphp --version 8.5 --os bookworm --push
```

## PHP Version Pipeline

PHP versions are NOT hardcoded. The pipeline works like this:
1. `scripts/get-php-versions.sh` fetches the latest active PHP releases from `https://www.php.net/releases/active.php`
2. It validates each version actually exists on DockerHub (with automatic fallback to previous patch if not yet published)
3. The fetched versions are merged with the base config (`scripts/conf/php-versions-base-config.yml`) which defines OS bases, variations, and NGINX versions
4. The merged result is written to `scripts/conf/php-versions.yml` -- this is the source of truth for CI builds
5. `scripts/generate-matrix.sh` reads the final YAML and produces the GitHub Actions matrix JSON

When modifying the version pipeline, the base config (`php-versions-base-config.yml`) is the file you edit. Never edit `php-versions.yml` directly -- it's generated.

## CI/CD

- Builds run via GitHub Actions using **Depot** (`depot/build-push-action`) for multi-arch (`linux/amd64` + `linux/arm64/v8`).
- The reusable workflow is `.github/workflows/service_docker-build-and-publish.yml`.
- The build matrix is generated from the PHP version pipeline described above.
- Image tags follow the pattern: `serversideup/php:{version}-{variation}` (Debian default) or `serversideup/php:{version}-{variation}-{os}` (Alpine/specific OS).

## Verification

There is no automated test suite for image logic. To verify changes:
1. Build the affected variation locally with `scripts/dev.sh`
2. Run the built image and confirm the change works: `docker run --rm -it serversideup/php:8.4-fpm-nginx-bookworm sh`
3. For entrypoint script changes, test on both Debian and Alpine builds
4. Run `shellcheck` on any modified shell scripts when available

## Key Design Decisions

- **Unprivileged by default**: Images run as `www-data`, not root. Web servers listen on `8080`/`8443` (unprivileged ports).
- **Lightweight images**: Only install dependencies that are truly necessary. See `docs/content/docs/1.getting-started/6.default-configurations.md` for what's included and why. When adding packages or extensions, justify the inclusion and keep image size minimal.
- **Environment-variable-driven**: All PHP/FPM/web server configuration is controlled via env vars -- no config file editing at runtime.
- **S6 Overlay** manages multiple processes in web server variations (FPM + web server).
- **Laravel automations** (migrations, caching, etc.) are opt-in via `AUTORUN_ENABLED`.
- **SSL support** is built-in with `SSL_MODE` (off/full) and self-signed cert generation.
- **One Dockerfile per variation**: OS-specific logic belongs in helper scripts, not Dockerfile conditionals or duplicate files.

## Documentation

The documentation and marketing site lives in `docs/` and has its own `docs/AGENTS.md` with guidelines specific to the Nuxt 4 content site. When working in `docs/`, follow that file instead of this one.

## Reference

When you need details beyond what's in this file, read these local sources rather than guessing:

- **Environment variables** (the canonical reference for ALL env vars, their defaults, and which variations they apply to): `docs/content/docs/8.reference/1.environment-variable-specification.md`
- **Default configurations** (what packages, extensions, and settings ship with each image): `docs/content/docs/1.getting-started/6.default-configurations.md`
- **All documentation**: `docs/content/docs/` contains the full docs in markdown. Browse this directory for guides on image variations, framework integrations, deployment, customization, and troubleshooting. There is also a dedicated `docs/AGENTS.md` file for the documentation site itself
- **LLM-optimized docs** (for AI tools that can fetch URLs): https://serversideup.net/open-source/docker-php/llms.txt and https://serversideup.net/open-source/docker-php/llms-full.txt to view the latest stable versions of the documentation.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<p align="center">
<a href="https://github.com/serversideup/docker-php/actions/workflows/action_publish-images-production.yml"><img alt="Build Status" src="https://img.shields.io/github/actions/workflow/status/serversideup/docker-php/.github%2Fworkflows%2Faction_publish-images-production.yml"></a>
<a href="https://github.com/serversideup/docker-php/blob/main/LICENSE" target="_blank"><img src="https://badgen.net/github/license/serversideup/docker-php" alt="License"></a>
<a href="https://github.com/sponsors/serversideup"><img src="https://badgen.net/badge/icon/Support%20Us?label=GitHub%20Sponsors&color=orange" alt="Support us"></a>
<a href="https://serversideup.net/sponsor/"><img src="https://badgen.net/badge/icon/Support%20Us?label=GitHub%20Sponsors&color=orange" alt="Support us"></a>
<br />
<a href="https://hub.docker.com/r/serversideup/php/"><img alt="Docker Hub Pulls" src="https://img.shields.io/docker/pulls/serversideup/php"></a>
<a href="https://serversideup.net/discord"><img alt="Discord" src="https://img.shields.io/discord/910287105714954251?color=blueviolet"></a>
Expand Down Expand Up @@ -141,13 +141,13 @@ Need help getting started? Join our Discord community and we'll help you out!
## Our Sponsors
All of our software is free and open to the world. None of this can be brought to you without the financial backing of our sponsors.

<p align="center"><a href="https://github.com/sponsors/serversideup"><img src="https://521public.s3.amazonaws.com/serversideup/sponsors/sponsor-box.png" alt="Sponsors"></a></p>
<p align="center"><a href="https://serversideup.net/sponsor/"><img src="https://521public.s3.amazonaws.com/serversideup/sponsors/sponsor-box.png" alt="Sponsors"></a></p>

### Black Level Sponsors
<a href="https://sevalla.com"><img src="https://serversideup.net/wp-content/uploads/2024/10/sponsor-image.png" alt="Sevalla" width="546px"></a>

#### Bronze Sponsors
<!-- bronze -->No bronze sponsors yet. <a href="https://github.com/sponsors/serversideup">Become a sponsor β†’</a><!-- bronze -->
<!-- bronze -->No bronze sponsors yet. <a href="https://serversideup.net/sponsor/">Become a sponsor β†’</a><!-- bronze -->

#### Infrastructure Sponsors
This project requires significant computing power to build and maintain over 8,000 different Docker image tags. We're extremely grateful for the following sponsors:
Expand Down Expand Up @@ -176,7 +176,7 @@ We're [Dan](https://x.com/danpastori) and [Jay](https://x.com/jaydrogers) - a tw
* **πŸ’» [GitHub](https://github.com/serversideup)** - Check out our other open source projects.
* **πŸ“« [Newsletter](https://serversideup.net/subscribe)** - Skip the algorithms and get quality content right to your inbox.
* **πŸ₯ [Twitter](https://x.com/serversideup)** - You can also follow [Dan](https://x.com/danpastori) and [Jay](https://x.com/jaydrogers).
* **❀️ [Sponsor Us](https://github.com/sponsors/serversideup)** - Please consider sponsoring us so we can create more helpful resources.
* **❀️ [Sponsor Us](https://serversideup.net/sponsor/)** - Please consider sponsoring us so we can create more helpful resources.

## Our Products
If you appreciate this project, be sure to check out our other projects.
Expand Down
2 changes: 1 addition & 1 deletion docs/app/app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ export default defineAppConfig({
},{
'trailingIcon': 'i-lucide-heart',
'label': 'Sponsor',
'to': 'https://github.com/sponsors/serversideup',
'to': 'https://serversideup.net/sponsor/',
'target': '_blank',
'aria-label': 'Sponsor',
'size': 'xl',
Expand Down
2 changes: 1 addition & 1 deletion docs/app/components/Badges.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
<a href="https://github.com/serversideup/docker-php/blob/main/LICENSE" target="_blank"><img src="https://badgen.net/github/license/serversideup/docker-php" alt="License"></a>
<a href="https://hub.docker.com/r/serversideup/php/"><img alt="Docker Pulls" src="https://img.shields.io/docker/pulls/serversideup/php"></a>
<a href="https://serversideup.net/discord"><img alt="Discord" src="https://img.shields.io/discord/910287105714954251?color=blueviolet"></a>
<a href="https://github.com/sponsors/serversideup"><img src="https://badgen.net/badge/icon/Support%20Us?label=GitHub%20Sponsors&color=orange" alt="Support us"></a>
<a href="https://serversideup.net/sponsor/"><img src="https://badgen.net/badge/icon/Support%20Us?label=GitHub%20Sponsors&color=orange" alt="Support us"></a>
</div>
</template>
2 changes: 1 addition & 1 deletion docs/app/components/Sponsors.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<img src="/assets/icons/hosts/sevalla.svg" alt="Sponsor" class="w-64 md:w-full object-contain" />
</NuxtLink>

<NuxtLink target="_blank" to="https://github.com/sponsors/serversideup" class="p-[10px] rounded bg-[#13161B] h-32 flex items-center justify-center text-[#94979C] font-medium font-sans hover:bg-[#22262F] transition-all duration-200">
<NuxtLink target="_blank" to="https://serversideup.net/sponsor/" class="p-[10px] rounded bg-[#13161B] h-32 flex items-center justify-center text-[#94979C] font-medium font-sans hover:bg-[#22262F] transition-all duration-200">
Become a Sponsor
</NuxtLink>

Expand Down
2 changes: 1 addition & 1 deletion docs/app/pages/[...slug].vue
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
:links="[{
label: 'Become a Sponsor',
icon: 'i-lucide-heart',
to: 'https://github.com/sponsors/serversideup',
to: 'https://serversideup.net/sponsor/',
target: '_blank'
}]"
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ Our images run as the `www-data` user by default, following the principle of lea
We also include additional security hardening:
- Disabled dangerous PHP functions by default (but you control them)
- Proper file permissions out of the box
- CloudFlare trusted proxy support for accurate IP logging
- Customizable trusted proxy configuration (Cloudflare, Sucuri, local, or off) for accurate IP logging
- Regular security updates from official PHP base images

### Performance Optimized
Expand Down
2 changes: 1 addition & 1 deletion docs/content/docs/1.getting-started/9.about.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ We're [Dan](https://x.com/danpastori){target="_blank"} and [Jay](https://x.com/j
* **πŸ’» [GitHub](https://github.com/serversideup){target="_blank"}** - Check out our other open source projects.
* **πŸ“« [Newsletter](https://serversideup.net/subscribe){target="_blank"}** - Skip the algorithms and get quality content right to your inbox.
* **πŸ₯ [Twitter](https://x.com/serversideup){target="_blank"}** - You can also follow [Dan](https://x.com/danpastori){target="_blank"} and [Jay](https://x.com/jaydrogers){target="_blank"}.
* **❀️ [Sponsor Us](https://github.com/sponsors/serversideup){target="_blank"}** - Please consider sponsoring us so we can create more helpful resources.
* **❀️ [Sponsor Us](https://serversideup.net/sponsor/){target="_blank"}** - Please consider sponsoring us so we can create more helpful resources.

## Our products
If you appreciate this project, be sure to check out our other projects.
Expand Down
Loading