How to install additional PHP extensions

We provide a number of PHP packages by default, but there will be times where you'll need to add additional PHP extensions in order to support a certain PHP library in your application. By default, we've included a popular tool called install-php-extensions that allows you to install almost any PHP module that you'll need.

Installing extensions is easy. All you need to do is find the extension you'd like to install on the docker-php-extension installer README. Once you have the name of the extensions, you'll need to add it to the Dockerfile in your project.

Example: Installing the "intl" extension

FROM serversideup/php:8.2.12-fpm-nginx-bookworm

# Switch to root so we can do root things
USER root

# Install the intl extension with root permissions
RUN install-php-extensions intl

# Drop back to our unprivileged user
USER www-data

It's really that simple. The install-php-extensions tool will automatically install the operating system packages that are required for the PHP extension to work and add the extension to PHP.

For more details on this script, we encourage you to check out the GitHub repository for this project.

View the "docker-php-extension-installer" Project on GitHub →

Docker Compose

If you're using Docker Compose, you'll want to make sure that you're not calling our image directly with the image: key. Instead, you'll want to use the build: key and point to a Dockerfile in your project.

Original docker-compose.yml file

services:
  php:
    image: serversideup/php:8.2.12-fpm-nginx-bookworm
    volumes:
      - .:/var/www/html/:cached

Updated docker-compose.yml

services:
  php:
    build:
      context: .
      dockerfile: Dockerfile
    volumes:
      - .:/var/www/html/:cached

New File: Dockerfile

FROM serversideup/php:8.2.12-fpm-nginx-bookworm

# Switch to root so we can do root things
USER root

# Install the imagick extension with root permissions
RUN install-php-extensions imagick

# Drop back to our unprivileged user
USER www-data

Notice the services.php.build options. We set a . to look for a dockerfile called Dockerfile within the same directory as our docker-compose.yml file. If your project is large, you may also want to include .dockerignore to ignore files that you do not want to include in your image.

For extra clarity, my project directory would look like this:

Project File Structure

.
├── Dockerfile
├── docker-compose.yml
└── public
    └── index.php

The Dockerfile is where all the magic will happen. This is where we pull the Server Side Up image as a dependency, then run standard shell commands to add the extension that we need.

The next time you run docker compose up, Docker will build and cache the image for you automatically.

You can verify the CLI option installed correctly by using php -i in CLI or phpinfo() in a PHP file.

⚠️ Important note about caching

  • You'll notice Docker likes to cache image builds (which is great for most functions)
  • If you make changes to your Dockerfile, you may need to include --build with your Docker compose command (read more here)

If you want to rebuild, then you would run this:

Rebuild on Docker Compose Initialization

docker compose up --build

Real-life example showing development to production

Here's an example showing a single Dockerfile with "multi-stage builds" so you can call certain targets as appropriate. This file is structured to centralize the PHP extension management in a single location.

Dockerfile

############################################
# Base Image
############################################

# Learn more about the Server Side Up PHP Docker Images at:
# https://serversideup.net/open-source/docker-php/
FROM serversideup/php:8.3-fpm-nginx as base

# Switch to root before installing our PHP extensions
USER root
RUN install-php-extensions bcmath gd

############################################
# Development Image
############################################
FROM base as development

# We can pass USER_ID and GROUP_ID as build arguments
# to ensure the www-data user has the same UID and GID
# as the user running Docker.
ARG USER_ID
ARG GROUP_ID

# Switch to root so we can set the user ID and group ID
USER root
RUN docker-php-serversideup-set-id www-data $USER_ID:$GROUP_ID  && \
    docker-php-serversideup-set-file-permissions --owner $USER_ID:$GROUP_ID --service nginx

# Switch back to the unprivileged www-data user
USER www-data

############################################
# CI image
############################################
FROM base as ci

# Sometimes CI images need to run as root
# so we set the ROOT user and configure
# the PHP-FPM pool to run as www-data
USER root
RUN echo "user = www-data" >> /usr/local/etc/php-fpm.d/docker-php-serversideup-pool.conf && \
    echo "group = www-data" >> /usr/local/etc/php-fpm.d/docker-php-serversideup-pool.conf

############################################
# Production Image
############################################
FROM base as deploy
COPY --chown=www-data:www-data . /var/www/html
USER www-data

Common PHP extensions that you might need

We compiled a list of extensions for you to reference.

intl

intl is a PHP module that provides internationalization functions. You may want to install this module if you're using Laravel, specifically if you are validating emails with "DNS" or "spoof" validation.

Our tests showed this module will add about 40 MB of space to the Docker image, so we decided to not include it by default.

Learn more about the "intl" requirement for Laravel →

Don't see the extension you need?

If you're having trouble, open a discussion on GitHub →