Mezzio php framework – setting up with php-fpm and nginx reverse proxy (with docker containers and docker compose)

This article is about mezzio+php-fpm, if you are looking for mezzio+swoole -> see this post here.

There are many reasons why you may want to use nginx reverse proxy in front of your application – (such as mezzio php framework with php-fpm).

Reasons to use nginx with your php-fpm applications:

  • efficient serving of static assets – while php-fpm will serve it very efficiently, but it will never beat raw compiled performance of nginx at serving of static assets. Nginx will do it fast and with minimal memory/cpu overhead -especially if you add brotli/gzip/ssl requirements into the mix ( https://stackoverflow.com/questions/9967887/node-js-itself-or-nginx-frontend-for-serving-static-files)
  • ssl termination – while it’s possible to do so in php-fpm application – again this is a job nginx will do a lot more effectively with smaller cpu footprint. For production use – its very very common to terminate ssl at nginx (or higher reverse proxy like aws ALB) and relieve your application from such mundane task (https://docs.nginx.com/nginx/admin-guide/security-controls/terminating-ssl-http/)
  • caching – personally I’m a huge fan of varnish cache reverse proxy for caching. However nginx also comes with such capability. Think about it – why always hit the slow filesystem for your static files that never change when you can just keep them in RAM at nginx/varnish level.
  • others – load balancing, routing, extra security etc.

Let’s get started – clone the git repository

I’ve prepared ready to use mezzio app skeleton + php-fpm + nginx application preconfigured and ready to be launched – see this git repository: https://github.com/linuxd3v/mezzio-nginx-fpm-demo

Go ahead and clone this repository on your laptop/computer – it contains all of the required dockerfiles and docker-compose file along with mezzio skeleton application.

Note: do not run docker-compose up -d yet – there are still some configs to be done.

git clone https://github.com/linuxd3v/mezzio-nginx-fpm-demo

Cloned repository directory (mezzio-nginx-fpm-demo) will contain only these assets:

  • /stack directory – all of the docker related files, dockerfiles, docker-compose, nginx, php and fpm configs
  • /mezzio directory – mezzio php application files only
  • /readme.md file – short readme file

Alternatively: create mezzio skeleton application yourself

If you prefer to create mezzio application yourself – instead of using what is in the repo – just follow official instructions in git repo.

Remove shipped mezzio directory and install the mezzio skeleton application project (all on the same level as ./stack directory):

rm -rf ./mezzio
composer create-project --ignore-platform-reqs mezzio/mezzio-skeleton mezzio

Note that we use --ignore-platform-reqs option – as you may not necessarily have all of the php extensions on your computer (they are present in docker container however).

You will be presented with some choices you need to pick, I would recommend these:

  • What type of installation would you like? modular
  • Which container do you want to use for dependency injection? pimple
  • Which router do you want to use? FastRoute
  • Which template engine do you want to use? Plates
  • Which error handler do you want to use during development? Whoops

See this terminal output (yours may vary slightly):

 linuxdev@hs-dev1:/mnt/480g_drive/projects/mezzio-nginx-fpm-demo$ 
composer create-project --ignore-platform-reqs mezzio/mezzio-skeleton mezzio
Creating a "mezzio/mezzio-skeleton" project at "./mezzio"
Info from https://repo.packagist.org: 
Installing mezzio/mezzio-skeleton (3.11.0)
  - Installing mezzio/mezzio-skeleton (3.11.0): Extracting archive
Created project in /mnt/480g_drive/projects/mezzio-nginx-fpm-demo/mezzio
> MezzioInstaller\OptionalPackages::install
Setting up optional packages
Setup data and cache dir
Removing installer development dependencies

  What type of installation would you like?
  [1] Minimal (no default middleware, templates, or assets; configuration only)
  [2] Flat (flat source code structure; default selection)
  [3] Modular (modular source code structure; recommended)
  Make your selection (2): 3
  - Copying src/App/src/ConfigProvider.php

  Which container do you want to use for dependency injection?
  [1] Pimple (supported by laminas)
  [2] laminas-servicemanager (supported by laminas)
  [3] Symfony DI Container
  [4] PHP-DI
  [5] chubbyphp-container
  Make your selection or type a composer package name and version (laminas-servicemanager (supported by laminas)): 1
  - Adding package laminas/laminas-pimple-config (^1.1.1)
  - Copying config/container.php

  Which router do you want to use?
  [1] FastRoute (supported by laminas)
  [2] laminas-router (supported by laminas)
  Make your selection or type a composer package name and version (FastRoute (supported by laminas)): 1
  - Adding package mezzio/mezzio-fastroute (^3.0.3)
  - Whitelist package mezzio/mezzio-fastroute
  - Copying config/routes.php

  Which template engine do you want to use?
  [1] Plates (supported by laminas)
  [2] Twig (supported by laminas)
  [3] laminas-view installs laminas-servicemanager (supported by laminas)
  [n] None of the above
  Make your selection or type a composer package name and version (n): 1
  - Adding package mezzio/mezzio-platesrenderer (^2.2)
  - Whitelist package mezzio/mezzio-platesrenderer
  - Copying src/App/templates/error/404.phtml
  - Copying src/App/templates/error/error.phtml
  - Copying src/App/templates/layout/default.phtml
  - Copying src/App/templates/app/home-page.phtml

  Which error handler do you want to use during development?
  [1] Whoops (supported by laminas)
  [n] None of the above
  Make your selection or type a composer package name and version (Whoops (supported by laminas)): 1
  - Adding package filp/whoops (^2.7.1)
  - Copying config/autoload/development.local.php.dist
Remove installer
Removing composer.lock from .gitignore
Removing Mezzio installer classes, configuration, tests and docs
Installing dependencies from lock file (including require-dev)
Verifying lock file contents can be installed on current platform.
Package operations: 135 installs, 0 updates, 0 removals
  - Installing laminas/laminas-component-installer (2.6.0): Extracting archive
  - Installing composer/package-versions-deprecated (1.11.99.4): Extracting archive
  - Installing squizlabs/php_codesniffer (3.6.2): Extracting archive
  - Installing dealerdirect/phpcodesniffer-composer-installer (v0.7.1): Extracting archive
  - Installing psr/container (1.1.2): Extracting archive
  - Installing chubbyphp/chubbyphp-container (2.0.2): Extracting archive
  - Installing chubbyphp/chubbyphp-laminas-config (1.2.2): Extracting archive
  - Installing symfony/polyfill-php80 (v1.23.1): Extracting archive
  - Installing symfony/process (v5.4.2): Extracting archive
  - Installing symfony/deprecation-contracts (v2.5.0): Extracting archive
  - Installing symfony/finder (v5.4.2): Extracting archive
  - Installing symfony/polyfill-mbstring (v1.23.1): Extracting archive
  - Installing symfony/polyfill-ctype (v1.23.0): Extracting archive
  - Installing symfony/filesystem (v5.4.0): Extracting archive
  - Installing symfony/polyfill-intl-normalizer (v1.23.0): Extracting archive
  - Installing symfony/polyfill-intl-grapheme (v1.23.1): Extracting archive
  - Installing symfony/string (v5.4.2): Extracting archive
  - Installing symfony/service-contracts (v2.5.0): Extracting archive
  - Installing symfony/polyfill-php73 (v1.23.0): Extracting archive
  - Installing symfony/console (v5.4.2): Extracting archive
  - Installing seld/phar-utils (1.2.0): Extracting archive
  - Installing seld/jsonlint (1.8.3): Extracting archive
  - Installing react/promise (v2.8.0): Extracting archive
  - Installing psr/log (1.1.4): Extracting archive
  - Installing justinrainbow/json-schema (5.2.11): Extracting archive
  - Installing composer/pcre (1.0.0): Extracting archive
  - Installing composer/xdebug-handler (2.0.3): Extracting archive
  - Installing composer/spdx-licenses (1.5.6): Extracting archive
  - Installing composer/semver (3.2.6): Extracting archive
  - Installing composer/metadata-minifier (1.0.0): Extracting archive
  - Installing composer/ca-bundle (1.3.1): Extracting archive
  - Installing composer/composer (2.2.3): Extracting archive
  - Installing php-di/phpdoc-reader (2.2.1): Extracting archive
  - Installing php-di/invoker (2.3.3): Extracting archive
  - Installing opis/closure (3.6.2): Extracting archive
  - Installing php-di/php-di (6.3.5): Extracting archive
  - Installing laminas/laminas-stdlib (3.6.4): Extracting archive
  - Installing elie29/zend-phpdi-config (v6.0.0): Extracting archive
  - Installing filp/whoops (2.14.4): Extracting archive
  - Installing symfony/polyfill-php81 (v1.23.0): Extracting archive
  - Installing symfony/dependency-injection (v5.4.2): Extracting archive
  - Installing jsoumelidis/zend-sf-di-config (0.5.1): Extracting archive
  - Installing webimpress/coding-standard (1.2.3): Extracting archive
  - Installing phpstan/phpdoc-parser (1.2.0): Extracting archive
  - Installing slevomat/coding-standard (7.0.18): Extracting archive
  - Installing laminas/laminas-coding-standard (2.3.0): Extracting archive
  - Installing webimpress/safe-writer (2.2.0): Extracting archive
  - Installing nikic/php-parser (v4.13.2): Extracting archive
  - Installing brick/varexporter (0.3.5): Extracting archive
  - Installing laminas/laminas-config-aggregator (1.7.0): Extracting archive
  - Installing laminas/laminas-development-mode (3.6.0): Extracting archive
  - Installing laminas/laminas-eventmanager (3.4.0): Extracting archive
  - Installing container-interop/container-interop (1.2.0): Extracting archive
  - Installing laminas/laminas-validator (2.15.1): Extracting archive
  - Installing laminas/laminas-escaper (2.9.0): Extracting archive
  - Installing laminas/laminas-uri (2.9.1): Extracting archive
  - Installing laminas/laminas-loader (2.8.0): Extracting archive
  - Installing laminas/laminas-http (2.15.1): Extracting archive
  - Installing psr/http-message (1.0.1): Extracting archive
  - Installing psr/http-server-handler (1.0.1): Extracting archive
  - Installing psr/http-factory (1.0.1): Extracting archive
  - Installing laminas/laminas-diactoros (2.8.0): Extracting archive
  - Installing laminas/laminas-httphandlerrunner (2.1.0): Extracting archive
  - Installing laminas/laminas-json (3.3.0): Extracting archive
  - Installing pimple/pimple (v3.5.0): Extracting archive
  - Installing laminas/laminas-pimple-config (1.4.0): Extracting archive
  - Installing nikic/fast-route (v1.3.0): Extracting archive
  - Installing webmozart/assert (1.10.0): Extracting archive
  - Installing psr/http-server-middleware (1.0.1): Extracting archive
  - Installing fig/http-message-util (1.1.5): Extracting archive
  - Installing mezzio/mezzio-router (3.7.0): Extracting archive
  - Installing mezzio/mezzio-fastroute (3.4.0): Extracting archive
  - Installing laminas/laminas-servicemanager (3.10.0): Extracting archive
  - Installing laminas/laminas-router (3.5.0): Extracting archive
  - Installing laminas/laminas-psr7bridge (1.6.0): Extracting archive
  - Installing mezzio/mezzio-laminasrouter (3.3.0): Extracting archive
  - Installing mezzio/mezzio-template (2.4.0): Extracting archive
  - Installing mezzio/mezzio-helpers (5.7.0): Extracting archive
  - Installing laminas/laminas-view (2.16.0): Extracting archive
  - Installing mezzio/mezzio-laminasviewrenderer (2.4.0): Extracting archive
  - Installing league/plates (v3.4.0): Extracting archive
  - Installing mezzio/mezzio-platesrenderer (2.4.0): Extracting archive
  - Installing laminas/laminas-stratigility (3.5.0): Extracting archive
  - Installing mezzio/mezzio (3.8.0): Extracting archive
  - Installing laminas/laminas-code (4.5.1): Extracting archive
  - Installing psr/event-dispatcher (1.0.0): Extracting archive
  - Installing symfony/event-dispatcher-contracts (v2.5.0): Extracting archive
  - Installing symfony/event-dispatcher (v5.4.0): Extracting archive
  - Installing laminas/laminas-cli (1.4.0): Extracting archive
  - Installing mezzio/mezzio-tooling (2.4.0): Extracting archive
  - Installing twig/twig (v3.3.6): Extracting archive
  - Installing mezzio/mezzio-twigrenderer (2.9.0): Extracting archive
  - Installing mikey179/vfsstream (v1.6.10): Extracting archive
  - Installing phpdocumentor/reflection-common (2.2.0): Extracting archive
  - Installing phpdocumentor/type-resolver (1.5.1): Extracting archive
  - Installing phpdocumentor/reflection-docblock (5.3.0): Extracting archive
  - Installing sebastian/version (3.0.2): Extracting archive
  - Installing sebastian/type (2.3.4): Extracting archive
  - Installing sebastian/resource-operations (3.0.3): Extracting archive
  - Installing sebastian/recursion-context (4.0.4): Extracting archive
  - Installing sebastian/object-reflector (2.0.4): Extracting archive
  - Installing sebastian/object-enumerator (4.0.4): Extracting archive
  - Installing sebastian/global-state (5.0.3): Extracting archive
  - Installing sebastian/exporter (4.0.4): Extracting archive
  - Installing sebastian/environment (5.1.3): Extracting archive
  - Installing sebastian/diff (4.0.4): Extracting archive
  - Installing sebastian/comparator (4.0.6): Extracting archive
  - Installing sebastian/code-unit (1.0.8): Extracting archive
  - Installing sebastian/cli-parser (1.0.1): Extracting archive
  - Installing phpunit/php-timer (5.0.3): Extracting archive
  - Installing phpunit/php-text-template (2.0.4): Extracting archive
  - Installing phpunit/php-invoker (3.1.1): Extracting archive
  - Installing phpunit/php-file-iterator (3.0.6): Extracting archive
  - Installing theseer/tokenizer (1.2.1): Extracting archive
  - Installing sebastian/lines-of-code (1.0.3): Extracting archive
  - Installing sebastian/complexity (2.0.2): Extracting archive
  - Installing sebastian/code-unit-reverse-lookup (2.0.3): Extracting archive
  - Installing phpunit/php-code-coverage (9.2.10): Extracting archive
  - Installing doctrine/instantiator (1.4.0): Extracting archive
  - Installing phpspec/prophecy (v1.15.0): Extracting archive
  - Installing phar-io/version (3.1.0): Extracting archive
  - Installing phar-io/manifest (2.0.3): Extracting archive
  - Installing myclabs/deep-copy (1.10.2): Extracting archive
  - Installing phpunit/phpunit (9.5.11): Extracting archive
  - Installing webmozart/path-util (2.3.0): Extracting archive
  - Installing openlss/lib-array2xml (1.0.0): Extracting archive
  - Installing netresearch/jsonmapper (v4.0.0): Extracting archive
  - Installing felixfbecker/language-server-protocol (1.5.1): Extracting archive
  - Installing felixfbecker/advanced-json-rpc (v3.2.1): Extracting archive
  - Installing dnoegel/php-xdg-base-dir (v0.1.1): Extracting archive
  - Installing amphp/amp (v2.6.1): Extracting archive
  - Installing amphp/byte-stream (v1.8.1): Extracting archive
  - Installing vimeo/psalm (4.17.0): Extracting archive
  - Installing psalm/plugin-phpunit (0.16.1): Extracting archive
  - Installing roave/security-advisories (dev-master 31d9d9e)
Deprecation Notice: Not passing a repository manager when calling defaultRepos is deprecated since Composer 2.3.6, use defaultReposWithDefaultManager() instead if you cannot get a manager. in phar:///usr/local/bin/composer/src/Composer/Repository/RepositoryFactory.php:83

  Please select which config file you wish to inject 'Laminas\Validator\ConfigProvider' into:
  [0] Do not inject
  [1] config/config.php
  Make your selection (default is 1):1

  Remember this option for other packages of the same type? (Y/n)y
    Installing Laminas\Validator\ConfigProvider from package laminas/laminas-validator
Deprecation Notice: Not passing a repository manager when calling defaultRepos is deprecated since Composer 2.3.6, use defaultReposWithDefaultManager() instead if you cannot get a manager. in phar:///usr/local/bin/composer/src/Composer/Repository/RepositoryFactory.php:83
Deprecation Notice: Not passing a repository manager when calling defaultRepos is deprecated since Composer 2.3.6, use defaultReposWithDefaultManager() instead if you cannot get a manager. in phar:///usr/local/bin/composer/src/Composer/Repository/RepositoryFactory.php:83
    Installing Laminas\HttpHandlerRunner\ConfigProvider from package laminas/laminas-httphandlerrunner
Deprecation Notice: Not passing a repository manager when calling defaultRepos is deprecated since Composer 2.3.6, use defaultReposWithDefaultManager() instead if you cannot get a manager. in phar:///usr/local/bin/composer/src/Composer/Repository/RepositoryFactory.php:83
Deprecation Notice: Not passing a repository manager when calling defaultRepos is deprecated since Composer 2.3.6, use defaultReposWithDefaultManager() instead if you cannot get a manager. in phar:///usr/local/bin/composer/src/Composer/Repository/RepositoryFactory.php:83
    Installing Mezzio\Router\FastRouteRouter\ConfigProvider from package mezzio/mezzio-fastroute
Deprecation Notice: Not passing a repository manager when calling defaultRepos is deprecated since Composer 2.3.6, use defaultReposWithDefaultManager() instead if you cannot get a manager. in phar:///usr/local/bin/composer/src/Composer/Repository/RepositoryFactory.php:83
    Installing Laminas\Router\ConfigProvider from package laminas/laminas-router
Deprecation Notice: Not passing a repository manager when calling defaultRepos is deprecated since Composer 2.3.6, use defaultReposWithDefaultManager() instead if you cannot get a manager. in phar:///usr/local/bin/composer/src/Composer/Repository/RepositoryFactory.php:83
    Installing Mezzio\Router\LaminasRouter\ConfigProvider from package mezzio/mezzio-laminasrouter
Deprecation Notice: Not passing a repository manager when calling defaultRepos is deprecated since Composer 2.3.6, use defaultReposWithDefaultManager() instead if you cannot get a manager. in phar:///usr/local/bin/composer/src/Composer/Repository/RepositoryFactory.php:83
    Installing Mezzio\Helper\ConfigProvider from package mezzio/mezzio-helpers
Deprecation Notice: Not passing a repository manager when calling defaultRepos is deprecated since Composer 2.3.6, use defaultReposWithDefaultManager() instead if you cannot get a manager. in phar:///usr/local/bin/composer/src/Composer/Repository/RepositoryFactory.php:83
    Installing Mezzio\LaminasView\ConfigProvider from package mezzio/mezzio-laminasviewrenderer
Deprecation Notice: Not passing a repository manager when calling defaultRepos is deprecated since Composer 2.3.6, use defaultReposWithDefaultManager() instead if you cannot get a manager. in phar:///usr/local/bin/composer/src/Composer/Repository/RepositoryFactory.php:83
    Installing Mezzio\Plates\ConfigProvider from package mezzio/mezzio-platesrenderer
Deprecation Notice: Not passing a repository manager when calling defaultRepos is deprecated since Composer 2.3.6, use defaultReposWithDefaultManager() instead if you cannot get a manager. in phar:///usr/local/bin/composer/src/Composer/Repository/RepositoryFactory.php:83
Deprecation Notice: Not passing a repository manager when calling defaultRepos is deprecated since Composer 2.3.6, use defaultReposWithDefaultManager() instead if you cannot get a manager. in phar:///usr/local/bin/composer/src/Composer/Repository/RepositoryFactory.php:83
    Installing Mezzio\Tooling\ConfigProvider from package mezzio/mezzio-tooling
Deprecation Notice: Not passing a repository manager when calling defaultRepos is deprecated since Composer 2.3.6, use defaultReposWithDefaultManager() instead if you cannot get a manager. in phar:///usr/local/bin/composer/src/Composer/Repository/RepositoryFactory.php:83
    Installing Mezzio\Twig\ConfigProvider from package mezzio/mezzio-twigrenderer
Package container-interop/container-interop is abandoned, you should avoid using it. Use psr/container instead.
Package webmozart/path-util is abandoned, you should avoid using it. Use symfony/filesystem instead.
Generating autoload files
composer/package-versions-deprecated: Generating version class...
composer/package-versions-deprecated: ...done generating version class
93 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
PHP CodeSniffer Config installed_paths set to ../../laminas/laminas-coding-standard/src,../../slevomat/coding-standard,../../webimpress,../../webimpress/coding-standard/src
Found 3 security vulnerability advisories affecting 3 packages.
Run composer audit for a full list of advisories.
> laminas-development-mode enable
You are now in development mode.

I would also immediately run a composer update command:

composer update --ignore-platform-reqs

Quick review of the nginx + mezzio/php-fpm docker-compose stack

./dockerfiles directory

nginx-sandbox.Dockerfile – nginx container (based on official docker nginx image) with brotli extension included. Here we are using multistage build (see FROM nginx:stable as builder) purely to demonstrate how to add additional modules to nginx container (such as brotli module in our case).

Note how we inject nginx site configs into container from ./stack/env-sandbox/nginx directory:

# Nginx: Clearout any domain configs
RUN rm -f /etc/nginx/conf.d/*

# Nginx: copying our configuration files
RUN mv /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak
ADD stack/env-${ENV_NAME}/nginx/site.conf /etc/nginx/conf.d/site.conf
ADD stack/env-${ENV_NAME}/nginx/nginx.conf /etc/nginx/nginx.conf

Also note how we use sed to fill in specific environmental variables from ./stack/env-sandbox/.env file (we will get to that file in one of the next segments):

# Nginx: filling in specific configurations
RUN sed -i "s/ENV_UP_HOST/${UP_HOST}/" /etc/nginx/conf.d/site.conf
RUN sed -i "s/ENV_SERVER_NAME/${SERVER_NAME}/" /etc/nginx/conf.d/site.conf
RUN sed -i "s/ENV_SERVER_ALIAS/${SERVER_ALIAS}/" /etc/nginx/conf.d/site.conf
RUN sed -i "s/ENV_PROJECT_NAME/${PROJECT_NAME}/" /etc/nginx/conf.d/site.conf
RUN sed -i "s/ENV_NAME/${ENV_NAME}/" /etc/nginx/conf.d/site.conf
RUN sed -i "s#ENV_SRV_DOC_ROOT#${SRV_DOC_ROOT}#" /etc/nginx/conf.d/site.conf
RUN sed -i "s#ENV_PHP_VER#${PHP_VER}#" /etc/nginx/conf.d/site.conf

Of specific interest is this env variable: ENV_UP_HOST – that is a variable that should be the container name/ID of the php-fpm container. That’s because in docker – a container’s hostname defaults to be the container’s ID (see docker docs here). You see what’s happening here? – nginx container will talk to php-fpm container using php-fpm container hostname (which is it’s container id) – how cool is that!

php-8.1-sandbox.Dockerfile – php 8.1 container with php-fpm included as well as a lot of other common php extensions included. Container is based on Ubuntu 22.04 LTS. We do very similar things as in nginx container – inject config files from ./stack/env-sandbox/php8.1 directory, then sed is used to environmentalize one thing or another.

Note that we expose 2 volumes in that dockerfile:

  • /app volume – for actual mezzio application (you should not write any data into it. In production you should use docker’s COPY or ADD commands to embed code inside of the container instead of mounting)
  • /appdata volume – for any FS writes we may want to do from our php mezzio application. As you know – we cannot just write anywhere inside of the container – we have to use these specially mounted directories.

Also note how we setup the entrypoint in mezzio + php-fpm:

ENTRYPOINT ["php-fpm8.1"]

docker-compose.yml

Docker-compose is what allows us to run several services as one cohesive application. I will not be going in depth here as that’s outside of scope of this tutorial. Note that nginx container is set to depend on phpfpm container – so if phpfpm container doesn’t start – neither will nginx.

Also note that we require a bridge network called infranet (we will set it up later):

networks:
  default:
    external: true
    name: infranet

Why use a bridge network? That’s because in real life we should only expose ports on our reverse proxy and not allow any web users to access our php-fpm application directly without nginx. That’s why docker’s bridge network is there for – php-fpm container runs only inside that network and nginx is the only exposed container from that network.

Launch nginx and php-fpm containers using docker-compose

Whether you installed mezzio skeleton application yourself or used mezzio directory that came with this repo – now we need to perform several more steps before we launch our containerized phpfpm + nginx stack .

Step 1: Rename the ./stack/env-sandbox/.env.template file to ./stack/env-sandbox/.env file and make sure that FS_DIR variable points to some empty directory on your computer. This is because we need to mount some directory into the mezzio/php-fpm container as mezzio/php-fpm container needs to write onto the filesystem (things like session files or any other content like images, pdf, documents etc) – and as we know when we use containers we cannot just write into container – we have to mount a writable directory into the container, ex:

# here - change to use your directory path
mkdir /mnt/480g_drive/dockervolumes/mezzio-finland

# Make sure directory is writable.
# I'm doing chmod 777 here merely for illustration purposes for this article,
# but in production you should use a specific user or less open
#permissions typically
chmod 777 mkdir /mnt/480g_drive/dockervolumes/mezzio-finland

Step 2: Edit the stack/env-sandbox/.env file and make sure that CODE_DIR variable is pointing to the repository directory you checked out for this article, ex:

CODE_DIR=/mnt/480g_drive/projects/mezzio-nginx-fpm-demo

Step 3: create a separate docker bridge network (friends don’t let friend use docker’s default bridge network). This is per dockers’ best practices recommendation:

 docker network create  \
--opt com.docker.network.bridge.name=br_infranet \
--subnet=172.21.0.0/16 \
--ip-range=172.21.11.0/24 \
--gateway=172.21.11.255 \
--attachable -d bridge infranet

Step 4: Now you are ready to launch your containerized nginx and php-fpm stack. Go ahead and execute docker-compose command to launch your stack. Note that this has to be done from directory where docker-compose.yml file is:

cd stack/env-sandbox && docker-compose up -d  
Creating sandbox-mezzio-finland-phpfpm8.1 ... done
Creating sandbox-mezzio-finland-nginx     ... done

This command uses the provided docker-compose.yml file (that itself uses .env file) and launches 2 docker containers:

  • sandbox-mezzio-finland-phpfpm8.1
  • sandbox-mezzio-finland-nginx

Now – if everything went right – you should see php-fpm and nginx powered mezzio framework site if you open the browser on this address: http://YOUR_IP:3112, for example this is what I see:

mezzio php framework with nginx reverse proxy running in the browser

And to prove even further – that we are indeed using nginx reverse proxy in front of the mezzio application – you could simply look at the headers:

mezzio with phpfpm and nginx reverse proxy

That is all there is to it. If you have questions on this article – Ill try to answer them and update the article (if I have time).

Thank you for reading.

Leave a Comment