Skip to content
Open
Changes from all commits
Commits
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
60 changes: 22 additions & 38 deletions docs/docker.md
Original file line number Diff line number Diff line change
Expand Up @@ -223,58 +223,42 @@ RUN install-php-extensions pdo_mysql pdo_pgsql #...

# Copy shared libs of frankenphp and all installed extensions to temporary location
# You can also do this step manually by analyzing ldd output of frankenphp binary and each extension .so file
RUN apt-get update && apt-get install -y libtree && \
EXT_DIR="$(php -r 'echo ini_get("extension_dir");')" && \
FRANKENPHP_BIN="$(which frankenphp)"; \
LIBS_TMP_DIR="/tmp/libs"; \
mkdir -p "$LIBS_TMP_DIR"; \
for target in "$FRANKENPHP_BIN" $(find "$EXT_DIR" -maxdepth 2 -type f -name "*.so"); do \
libtree -pv "$target" | sed 's/.*── \(.*\) \[.*/\1/' | grep -v "^$target" | while IFS= read -r lib; do \
[ -z "$lib" ] && continue; \
base=$(basename "$lib"); \
destfile="$LIBS_TMP_DIR/$base"; \
if [ ! -f "$destfile" ]; then \
cp "$lib" "$destfile"; \
fi; \
done; \
done


# Distroless debian base image, make sure this is the same debian version as the base image
RUN apt-get update; \
apt-get install -y --no-install-recommends libtree; \
mkdir -p /tmp/libs; \
Comment on lines +226 to +228
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The RUN line chains commands with ; rather than &&, so a failed apt-get update (or apt-get install) won’t reliably stop the build at the point of failure. For Dockerfile examples, it’s better to use && (or enable set -e) so failures abort immediately and don’t produce confusing downstream errors.

Suggested change
RUN apt-get update; \
apt-get install -y --no-install-recommends libtree; \
mkdir -p /tmp/libs; \
RUN apt-get update && \
apt-get install -y --no-install-recommends libtree && \
mkdir -p /tmp/libs && \

Copilot uses AI. Check for mistakes.
for target in $(which frankenphp) \
$(find "$(php -r 'echo ini_get("extension_dir");')" -maxdepth 2 -name "*.so"); do \
libtree -pv "$target" 2>/dev/null | grep -oP '(?:── )\K/\S+(?= \[)' | while IFS= read -r lib; do \
[ -f "$lib" ] && cp -n "$lib" /tmp/libs/; \
done; \
done;


# Distroless Debian base image, make sure this matches the Debian version of the builder
FROM gcr.io/distroless/base-debian13
# Docker hardened image alternative
# Docker hardened image alternative:
# FROM dhi.io/debian:13

Comment on lines +237 to 241
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This Dockerfile snippet changed (removed PATH_TO_APP/PATH_TO_CADDYFILE args and switched -c to --config), but the translated docs/*/docker.md files still document the old version. That leaves the hardening instructions inconsistent across languages; consider updating the translations (or documenting that only the English page is current) to avoid confusing users following non-English docs.

Copilot uses AI. Check for mistakes.
# Location of your app and Caddyfile to be copied into the container
ARG PATH_TO_APP="."
ARG PATH_TO_CADDYFILE="./Caddyfile"

# Copy your app into /app
# For further hardening make sure only writable paths are owned by the nonroot user
COPY --chown=nonroot:nonroot "$PATH_TO_APP" /app
COPY "$PATH_TO_CADDYFILE" /etc/caddy/Caddyfile

# Copy frankenphp and necessary libs
COPY --from=builder /usr/local/bin/frankenphp /usr/local/bin/frankenphp
COPY --from=builder /usr/local/lib/php/extensions /usr/local/lib/php/extensions
COPY --from=builder /tmp/libs /usr/lib

# Copy php.ini configuration files
COPY --from=builder /usr/local/etc/php/conf.d /usr/local/etc/php/conf.d
COPY --from=builder /usr/local/etc/php/php.ini-production /usr/local/etc/php/php.ini

# Caddy data dirs — must be writable for nonroot, even on a read-only root filesystem
ENV XDG_CONFIG_HOME=/config \
XDG_DATA_HOME=/data
COPY --from=builder --chown=nonroot:nonroot /data/caddy /data/caddy
COPY --from=builder --chown=nonroot:nonroot /config/caddy /config/caddy
# Config and data dirs must be writable for nonroot, even on a read-only root filesystem
ENV XDG_CONFIG_HOME=/config XDG_DATA_HOME=/data
COPY --from=builder --chown=nonroot:nonroot /data /data
COPY --from=builder --chown=nonroot:nonroot /config /config

USER nonroot
# Copy your app and Caddyfile
COPY --chown=nonroot:nonroot . /app
Comment on lines +254 to +255
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This copies the entire app tree into /app owned by nonroot. For a hardening example, it’s safer to keep application code owned by root (read-only to nonroot) and only chown the specific writable paths (e.g., /data, /config, /tmp). Owning /app as nonroot makes it easier for a compromised app to modify its own code if the filesystem isn’t mounted read-only.

Suggested change
# Copy your app and Caddyfile
COPY --chown=nonroot:nonroot . /app
# Copy your app (kept root-owned) and Caddyfile
COPY . /app

Copilot uses AI. Check for mistakes.
COPY Caddyfile /etc/caddy/Caddyfile

USER nonroot
WORKDIR /app

# entrypoint to run frankenphp with the provided Caddyfile
ENTRYPOINT ["/usr/local/bin/frankenphp", "run", "-c", "/etc/caddy/Caddyfile"]
ENTRYPOINT ["/usr/local/bin/frankenphp", "run", "--config", "/etc/caddy/Caddyfile"]
```

## Development Versions
Expand Down
Loading