Tangible Bytes

A Web Developer’s Blog

PHP Docker for Dev

I’m staring a new PHP project and I wanted a clean docker image to work from.

I inherited one on my last project and wanted to improve image size, security and production alignment.

Image Size

Especially in my CI environment I’d like builds to be as quick as possible and most of the time is spent loading the image.

To get a smaller image I start with Alpine Linux: a security-oriented, lightweight Linux distribution based on musl libc and busybox.

The only things I notice missing from are that it uses /bin/sh instead of /bin/bash and vi instead of vim or nano.

I saved more space by multi-stage build

What this lets me do is

  1. Install build tools
  2. Build php modules like xdebug and postgresql
  3. Discard all the build tools and keep just the output

Some people seem to install a lot of stuff on the docker image - like: git, curl, image libraries etc. I install only what I need. This isn’t a VM - it has one job as a web server.

Finally I don’t install composer here. I use a separate image here (the official composer image) which only runs when I do an update via docker run

I went from over 600Mb to 124Mb

Security

Some people might argue that security in dev is unimportant

Security is a habit:

By always practising good security you are less likely to forget it later and more likely to notice if something is amiss

If you get used to ignoring security warnings in dev you may not notice them in prod
Block whatever you don’t want to use

That way you are sure it isn’t being used and don’t get caught out by third party libraries

In my php-fpm.cong I have

php_admin_value[disable_functions] = exec,passthru,shell_exec,system
php_admin_flag[allow_url_fopen] = off

Production Alignment

The closer I can make my dev system to production the easier it is to catch problems early and the less effort will be taken to fix them.

I won’t run composer updates in production

I wont have a full build environment in production (see the NIST Guide to General Server Security)

Code changes happen on my host computer whether that is got or editing.

Composer and npm updates are also something I see as primarily the responsibility of the host not the dev server - I use helper containers for these so that the only tools developers need to work on the project are git, docker, and an editor. Any project dependencies are within docker - ensuring everyone has teh same versions.

Dockerfile

https://gitlab.com/tangiblebytes/dev-docker/-/blob/main/php/Dockerfile

FROM php:8.2.0-fpm-alpine3.16 AS builder

RUN apk add --update postgresql-dev icu-data-full autoconf build-base linux-headers

RUN docker-php-ext-install pdo_pgsql 

RUN pecl install xdebug  \
	&& docker-php-ext-enable  xdebug

# copy what was built - but go back to the original image without all the build tools
# this reduces final image size from 648MB to 124MB
FROM php:8.2.0-fpm-alpine3.16 
COPY --from=builder /usr/local /usr/local

# the php pgsql module needs the postgres libs (not all of postgresql-dev though)
RUN apk update && \
	apk add postgresql-libs && \
   	rm -rf /var/cache/apk/*

# setup user/group to a cross-image consistent 1000:1000
RUN addgroup --gid=1000 www
RUN adduser -h /app -s /bin/sh -u 1000 -G www -D www
USER www

COPY www.conf /usr/local/etc/php-fpm.d/www.conf
#COPY php-fpm.conf /usr/local/etc/php-fpm.conf


# makes no difference to php-fpm - but sets the default on exec
WORKDIR /app/

EXPOSE 9000
CMD ["php-fpm"]

UPDATE : 07/01/2023

While working on this process I struggled to find an up-to-date set of recommendations for securing PHP

I have since found the OWASP PHP Configuration Cheat Sheet which is great and I will review the above in consideration of this authoritative document. If anything I have written above contradicts with the OWASP document - you should probably follow their advice not mine.