Skip to content

Commit 0ac11f1

Browse files
dunglasCopilot
andauthored
docs: improve Dockerfile for hardened images (#2270)
Prevents errors like this one when using Mercure: `php-1 | Error: loading initial config: loading new config: loading frankenphp app module: provision frankenphp: failed to provision caddy http: loading http app module: provision http: server srv0: setting up route handlers: route 2: loading handler modules: position 2: loading module 'mercure': provision http.handlers.mercure: provision http.handlers.mercure.bolt: "": invalid transport: open /data/caddy/mercure.db: permission denied` --------- Signed-off-by: Kévin Dunglas <kevin@dunglas.fr> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 16fdfa2 commit 0ac11f1

File tree

1 file changed

+31
-43
lines changed

1 file changed

+31
-43
lines changed

docs/docker.md

Lines changed: 31 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -158,13 +158,14 @@ FROM dunglas/frankenphp
158158
159159
ARG USER=appuser
160160
161-
RUN \
161+
RUN <<-EOF
162162
# Use "adduser -D ${USER}" for alpine based distros
163-
useradd ${USER}; \
163+
useradd ${USER}
164164
# Add additional capability to bind to port 80 and 443
165-
setcap CAP_NET_BIND_SERVICE=+eip /usr/local/bin/frankenphp; \
165+
setcap CAP_NET_BIND_SERVICE=+eip /usr/local/bin/frankenphp
166166
# Give write access to /config/caddy and /data/caddy
167167
chown -R ${USER}:${USER} /config/caddy /data/caddy
168+
EOF
168169
169170
USER ${USER}
170171
```
@@ -182,13 +183,14 @@ FROM dunglas/frankenphp
182183
183184
ARG USER=appuser
184185
185-
RUN \
186+
RUN <<-EOF
186187
# Use "adduser -D ${USER}" for alpine based distros
187-
useradd ${USER}; \
188+
useradd ${USER}
188189
# Remove default capability
189-
setcap -r /usr/local/bin/frankenphp; \
190+
setcap -r /usr/local/bin/frankenphp
190191
# Give write access to /config/caddy and /data/caddy
191192
chown -R ${USER}:${USER} /config/caddy /data/caddy
193+
EOF
192194
193195
USER ${USER}
194196
```
@@ -223,58 +225,44 @@ RUN install-php-extensions pdo_mysql pdo_pgsql #...
223225
224226
# Copy shared libs of frankenphp and all installed extensions to temporary location
225227
# You can also do this step manually by analyzing ldd output of frankenphp binary and each extension .so file
226-
RUN apt-get update && apt-get install -y libtree && \
227-
EXT_DIR="$(php -r 'echo ini_get("extension_dir");')" && \
228-
FRANKENPHP_BIN="$(which frankenphp)"; \
229-
LIBS_TMP_DIR="/tmp/libs"; \
230-
mkdir -p "$LIBS_TMP_DIR"; \
231-
for target in "$FRANKENPHP_BIN" $(find "$EXT_DIR" -maxdepth 2 -type f -name "*.so"); do \
232-
libtree -pv "$target" | sed 's/.*── \(.*\) \[.*/\1/' | grep -v "^$target" | while IFS= read -r lib; do \
233-
[ -z "$lib" ] && continue; \
234-
base=$(basename "$lib"); \
235-
destfile="$LIBS_TMP_DIR/$base"; \
236-
if [ ! -f "$destfile" ]; then \
237-
cp "$lib" "$destfile"; \
238-
fi; \
239-
done; \
240-
done
241-
242-
243-
# Distroless debian base image, make sure this is the same debian version as the base image
228+
RUN <<-EOF
229+
apt-get update
230+
apt-get install -y --no-install-recommends libtree
231+
mkdir -p /tmp/libs
232+
for target in $(which frankenphp) \
233+
$(find "$(php -r 'echo ini_get("extension_dir");')" -maxdepth 2 -name "*.so"); do
234+
libtree -pv "$target" 2>/dev/null | grep -oP '(?:── )\K/\S+(?= \[)' | while IFS= read -r lib; do
235+
[ -f "$lib" ] && cp -n "$lib" /tmp/libs/
236+
done
237+
done
238+
EOF
239+
240+
241+
# Distroless Debian base image, make sure this matches the Debian version of the builder
244242
FROM gcr.io/distroless/base-debian13
245243
# Docker hardened image alternative
246244
# FROM dhi.io/debian:13
247245
248-
# Location of your app and Caddyfile to be copied into the container
249-
ARG PATH_TO_APP="."
250-
ARG PATH_TO_CADDYFILE="./Caddyfile"
251-
252-
# Copy your app into /app
253-
# For further hardening make sure only writable paths are owned by the nonroot user
254-
COPY --chown=nonroot:nonroot "$PATH_TO_APP" /app
255-
COPY "$PATH_TO_CADDYFILE" /etc/caddy/Caddyfile
256-
257-
# Copy frankenphp and necessary libs
258246
COPY --from=builder /usr/local/bin/frankenphp /usr/local/bin/frankenphp
259247
COPY --from=builder /usr/local/lib/php/extensions /usr/local/lib/php/extensions
260248
COPY --from=builder /tmp/libs /usr/lib
261249
262-
# Copy php.ini configuration files
263250
COPY --from=builder /usr/local/etc/php/conf.d /usr/local/etc/php/conf.d
264251
COPY --from=builder /usr/local/etc/php/php.ini-production /usr/local/etc/php/php.ini
265252
266-
# Caddy data dirs — must be writable for nonroot, even on a read-only root filesystem
267-
ENV XDG_CONFIG_HOME=/config \
268-
XDG_DATA_HOME=/data
269-
COPY --from=builder --chown=nonroot:nonroot /data/caddy /data/caddy
270-
COPY --from=builder --chown=nonroot:nonroot /config/caddy /config/caddy
253+
# Config and data dirs must be writable for nonroot, even on a read-only root filesystem
254+
ENV XDG_CONFIG_HOME=/config XDG_DATA_HOME=/data
255+
COPY --from=builder --chown=nonroot:nonroot /data /data
256+
COPY --from=builder --chown=nonroot:nonroot /config /config
271257
272-
USER nonroot
258+
# Copy your app (kept root-owned) and Caddyfile
259+
COPY . /app
260+
COPY Caddyfile /etc/caddy/Caddyfile
273261
262+
USER nonroot
274263
WORKDIR /app
275264
276-
# entrypoint to run frankenphp with the provided Caddyfile
277-
ENTRYPOINT ["/usr/local/bin/frankenphp", "run", "-c", "/etc/caddy/Caddyfile"]
265+
ENTRYPOINT ["/usr/local/bin/frankenphp", "run", "--config", "/etc/caddy/Caddyfile"]
278266
```
279267

280268
## Development Versions

0 commit comments

Comments
 (0)