Skip to content

Commit 1b023fd

Browse files
Merge pull request #7 from php-debugger/docker-page
add docker page, resolve version at build time
2 parents afb583a + 4f7be18 commit 1b023fd

5 files changed

Lines changed: 249 additions & 17 deletions

File tree

docs/getting-started/docker.md

Lines changed: 0 additions & 13 deletions
This file was deleted.

docs/getting-started/docker.mdx

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
---
2+
title: Docker
3+
---
4+
5+
import ConsoleSample from '@site/src/components/ConsoleSample';
6+
7+
There are two ways to get PHP Debugger into a container: use a prebuilt image with
8+
the debugger already compiled into the interpreter, or install the extension into
9+
an official PHP image yourself.
10+
11+
The prebuilt images are the simpler route and the one to reach for unless you have
12+
a reason not to.
13+
14+
## Prebuilt images
15+
16+
The images on Docker Hub are drop-in replacements for the
17+
[official PHP images](https://hub.docker.com/_/php). Change one line:
18+
19+
```dockerfile
20+
# before
21+
FROM php:8.4-fpm
22+
23+
# after
24+
FROM phpdebugger/php:8.4-fpm
25+
```
26+
27+
That is the whole setup. There is no extension to install, nothing to enable, and
28+
no separate Dockerfile for development.
29+
30+
### Available tags
31+
32+
Each tag matches the official `php:` tag of the same name, for PHP **8.2** to
33+
**8.5**, on `linux/amd64` and `linux/arm64`:
34+
35+
| Tag | Distro |
36+
| --- | --- |
37+
| `8.x-cli` (also `8.x`) | Debian |
38+
| `8.x-fpm` | Debian |
39+
| `8.x-apache` | Debian |
40+
| `8.x-zts` | Debian |
41+
| `8.x-cli-alpine` (also `8.x-alpine`) | Alpine |
42+
| `8.x-fpm-alpine` | Alpine |
43+
| `8.x-zts-alpine` | Alpine |
44+
| `latest` | newest stable PHP, cli variant |
45+
46+
There are no patch-level tags such as `8.4.23`. Each tag always carries the latest
47+
patch release of its PHP minor version, rebuilt weekly and on every debugger
48+
release.
49+
50+
### What is different from the official image
51+
52+
Everything you already do keeps working — same entrypoints, same helper scripts,
53+
same config layout:
54+
55+
```dockerfile
56+
FROM phpdebugger/php:8.4-fpm
57+
58+
RUN docker-php-ext-install -j$(nproc) pdo_mysql bcmath
59+
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
60+
```
61+
62+
Two things are not the same:
63+
64+
- The debugger is compiled into the interpreter as a static extension. It does not
65+
appear in the `.ini` files, and it cannot be uninstalled.
66+
- The JIT compiler is switched off in the bundled opcache build, because it is
67+
incompatible with the debugger's engine hooks.
68+
69+
If you rebuild opcache yourself, JIT comes back unless you say otherwise:
70+
71+
```dockerfile
72+
RUN docker-php-ext-configure opcache --disable-opcache-jit \
73+
&& docker-php-ext-install -j$(nproc) opcache
74+
```
75+
76+
### Connecting your IDE
77+
78+
No INI configuration is needed. Debugging is on by default, every request starts a
79+
session, and the debugger connects whenever your IDE is listening — at near-zero
80+
cost when it is not.
81+
82+
```yaml
83+
services:
84+
app:
85+
image: phpdebugger/php:8.4-fpm
86+
environment:
87+
PHP_DEBUGGER_CONFIG: "client_host=host.docker.internal"
88+
PHP_IDE_CONFIG: "serverName=myapp"
89+
extra_hosts:
90+
- "host.docker.internal:host-gateway" # needed on Linux
91+
```
92+
93+
### Checking it worked
94+
95+
<ConsoleSample>{`$ docker run --rm phpdebugger/php:8.4-cli php -v
96+
PHP 8.4.24 (cli) (built: Aug 3 2026 12:08:27) (NTS)
97+
Copyright (c) The PHP Group
98+
Zend Engine v4.4.24, Copyright (c) Zend Technologies
99+
with Zend OPcache v8.4.24, Copyright (c), by Zend Technologies
100+
with PHP Debugger v__VERSION__, Copyright (c) 2002-2026, by Derick Rethans`}</ConsoleSample>
101+
102+
:::warning[Development images only]
103+
104+
Debugging is enabled by default in these images. A debugger gives anyone who can
105+
reach it full access to your source, your variables, and your runtime data, so a
106+
reachable production container is a serious risk. Keep production on the official
107+
`php:` images and use these only where you actually want to debug.
108+
109+
:::
110+
111+
### Removing an existing debugger
112+
113+
If the image you are switching already had a debugger installed, take the old one
114+
out. PHP Debugger presents the same interface for compatibility, so leaving the
115+
previous extension in place means two extensions competing for the same engine
116+
hooks.
117+
118+
From your Dockerfile and INI files, remove:
119+
120+
- the line that loads the old extension — `zend_extension=xdebug.so`, or a
121+
`docker-php-ext-enable xdebug` step;
122+
- any `xdebug.mode` setting — debugging is on by default here;
123+
- any `xdebug.start_with_request` setting — every request already starts a session.
124+
125+
Settings worth keeping can stay as they are. Both the `xdebug.*` and
126+
`php_debugger.*` prefixes are accepted, so an existing client host or port carries
127+
over untouched.
128+
129+
## Installing the extension with PIE
130+
131+
If you would rather keep the official image and add the debugger to it, install
132+
the extension with [PIE](https://github.com/php/pie), the PHP Foundation's
133+
extension installer.
134+
135+
```dockerfile
136+
FROM php:8.4-cli
137+
138+
RUN apt-get update \
139+
&& apt-get install -y --no-install-recommends $PHPIZE_DEPS unzip libtool \
140+
&& curl -fsSL https://github.com/php/pie/releases/latest/download/pie.phar \
141+
-o /usr/local/bin/pie \
142+
&& chmod +x /usr/local/bin/pie \
143+
&& pie install php-debugger/php-debugger \
144+
&& rm -rf /var/lib/apt/lists/*
145+
```
146+
147+
PIE compiles the extension against the PHP in the image and enables it for you.
148+
The defaults match the prebuilt images: debugging on, a session with every
149+
request, port 9003.
150+
151+
Build the image, then check the debugger is in it:
152+
153+
<ConsoleSample>{`$ docker build -t myapp .
154+
$ docker run --rm myapp php -v
155+
...
156+
with PHP Debugger v__VERSION__, Copyright (c) 2002-2026, by Derick Rethans`}</ConsoleSample>
157+
158+
The trade-off against the prebuilt images is build time and image size: you are
159+
compiling a C extension and carrying the build toolchain, rather than pulling an
160+
image that already has the debugger in it.
161+
162+
## Next steps
163+
164+
- [More install options](./install-options.md) — prebuilt binaries, package
165+
managers, and building from source
166+
- [Configuration](./configuration.md) — the settings you can change

docs/getting-started/installation.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ else.
1818

1919
:::tip[Prefer Docker?]
2020

21-
Use a container image instead — see [Docker](./docker.md).
21+
Use a container image instead — see [Docker](./docker.mdx).
2222

2323
:::
2424

docusaurus.config.js

Lines changed: 67 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,43 @@
55

66
import {themes as prismThemes} from 'prism-react-renderer';
77

8+
/* The released version is shown in the navbar and quoted in sample output on the
9+
docs. Read it from the extension's latest GitHub release at build time so a
10+
rebuild is all it takes to pick up a new release, rather than hunting down
11+
every place a version is written down.
12+
13+
FALLBACK_VERSION keeps builds working when the API cannot be reached -- offline,
14+
or rate limited, since this is an unauthenticated request. It is only a
15+
backstop: bump it when it drifts too far from reality. */
16+
const FALLBACK_VERSION = '0.3.0';
17+
18+
/* Stand-in written into the navbar config below and swapped for the real version
19+
in createConfig, so the version lives in exactly one place. */
20+
const VERSION_PLACEHOLDER = '__VERSION__';
21+
22+
async function latestDebuggerVersion() {
23+
const url =
24+
'https://api.github.com/repos/php-debugger/php-debugger/releases/latest';
25+
try {
26+
const response = await fetch(url, {
27+
headers: {Accept: 'application/vnd.github+json'},
28+
});
29+
if (!response.ok) {
30+
console.warn(
31+
`[version] GitHub returned ${response.status}; falling back to ${FALLBACK_VERSION}`,
32+
);
33+
return FALLBACK_VERSION;
34+
}
35+
const {tag_name: tag} = await response.json();
36+
return typeof tag === 'string' ? tag.replace(/^v/, '') : FALLBACK_VERSION;
37+
} catch (error) {
38+
console.warn(
39+
`[version] could not reach GitHub (${error.message}); falling back to ${FALLBACK_VERSION}`,
40+
);
41+
return FALLBACK_VERSION;
42+
}
43+
}
44+
845
/** @type {import('@docusaurus/types').Config} */
946
const config = {
1047
title: 'PHP Debugger',
@@ -107,11 +144,11 @@ const config = {
107144
},
108145
{
109146
type: 'dropdown',
110-
label: 'v1.3.0',
147+
label: VERSION_PLACEHOLDER,
111148
position: 'right',
112149
items: [
113150
{
114-
label: 'v1.3.0 (latest)',
151+
label: `${VERSION_PLACEHOLDER} (latest)`,
115152
href: 'https://github.com/php-debugger/php-debugger/releases/latest',
116153
},
117154
{
@@ -130,4 +167,31 @@ const config = {
130167
}),
131168
};
132169

133-
export default config;
170+
export default async function createConfig() {
171+
const debuggerVersion = await latestDebuggerVersion();
172+
const navbar = config.themeConfig.navbar;
173+
return {
174+
...config,
175+
/* Available to pages via useDocusaurusContext().siteConfig.customFields. */
176+
customFields: {...config.customFields, debuggerVersion},
177+
themeConfig: {
178+
...config.themeConfig,
179+
navbar: {
180+
...navbar,
181+
items: navbar.items.map((item) =>
182+
item.type === 'dropdown' && item.label === VERSION_PLACEHOLDER
183+
? {
184+
...item,
185+
label: `v${debuggerVersion}`,
186+
items: item.items.map((sub) =>
187+
sub.label === `${VERSION_PLACEHOLDER} (latest)`
188+
? {...sub, label: `v${debuggerVersion} (latest)`}
189+
: sub,
190+
),
191+
}
192+
: item,
193+
),
194+
},
195+
},
196+
};
197+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import CodeBlock from '@theme/CodeBlock';
2+
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
3+
4+
/* Console output with __VERSION__ swapped for the release the docs were built
5+
against. Sample output that quotes a version goes stale the moment a new one
6+
ships; this way a rebuild is enough to correct it. The version itself is
7+
resolved in docusaurus.config.js. */
8+
export default function ConsoleSample({children}) {
9+
const {siteConfig} = useDocusaurusContext();
10+
const text = String(children).replace(
11+
/__VERSION__/g,
12+
siteConfig.customFields.debuggerVersion,
13+
);
14+
return <CodeBlock language="console">{text}</CodeBlock>;
15+
}

0 commit comments

Comments
 (0)