We can deploy apache and php in separate docker containers and then link them.
But is there any way to install apache locally (using apt-get install apache2) and php-fpm in docker container and then link them?
Thanks
Yes. Since you are using php-fpm with Apache as you should (instead of mod_php), you will have something similar to this in your Docker-based Apache site configurations:
<FilesMatch \.php$>
SetHandler "proxy:fcgi://php-fpm-container:9000"
</FilesMatch>
The above works when both php-fpm and apache are running in separate docker containers; php-fpm-container refers to the php-fpm container.
So long as your Docker php-fpm container exposes port 9000 to the host, Apache won't know or care whether that is served from the host or from inside docker.
Your apache site configs will need to be modified to point at localhost:
<FilesMatch \.php$>
SetHandler "proxy:fcgi://localhost:9000"
</FilesMatch>
Incidentally this is a pretty neat way to run multiple different PHP versions on one host and one Apache server. Just expose each php-fpm container on a different port (perhaps 9001, 9002 etc).
Here is a guide on how to set up php-fpm in a docker container, while the host system runs Apache (and optionally: mysql, memcached, etc).
This guide is specifically tailored around setting up a development environment as opposed to for production. If running in production, you may want to investigate a method for keeping the container updated (ie: in an automated build pipeline) and configure PHP settings to be production-appropriate (ie: hiding error messages and other production configuration)
Create a new folder for your custom php-fpm image (ex: sitename-php74-fpm). Replace sitename and the php version as appropriate.
Inside, create a Dockerfile:
FROM php:7.4-fpm
# These pages may be helpful for customizing the below run lines:
# https://github.com/docker-library/docs/tree/master/php
# https://github.com/mlocati/docker-php-extension-installer
# Easy installer allows for easier dependency installation
ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/
RUN \
apt-get update && \
apt-get install -y telnet && \
\
printf " \n\
[www] \n\
listen = 127.0.0.1:7474 \n\
php_flag[log_errors] = on \n\
\n\
[global] \n\
error_log = /var/log/php74-sitename/error.log \n\
" >> /usr/local/etc/php-fpm.conf && \
\
chmod +x /usr/local/bin/install-php-extensions && \
install-php-extensions gd xdebug mysqli pdo pdo_mysql \
memcache bz2 zip
Customize the file as appropriate for your desired PHP version and extensions needed. Some notes:
/var/log/php74-sitename/error.log, which we will set up in the subsequent steps127.0.0.1 only to prevent other devices on the network/internet from connecting to php-fpm (if you only specify a port, it will listen on all interfaces).Now build the docker image with docker build -t sitename-php74-fpm .
Prerequisite: I will assume you already have Apache set up and serving some static paths. If not, please do that first before continuing.
apt-get install libapache2-mod-fcgid
a2enmod proxy_fcgi
Update the configuration for the site that should use php-fpm (ex: /etc/apache2/sites-enabled/default-ssl.conf:
<VirtualHost _default_:443>
ServerAdmin webmaster@localhost
DocumentRoot /path/to/website
...
<FilesMatch \.php$>
SetHandler "proxy:fcgi://127.0.0.1:7474"
</FilesMatch>
</VirtualHost>
This will allow Apache to forward the request to Docker. Restart Apache /etc/init.d/apache2 restart
mkdir /var/log/php74-sitename
chown www-data:www-data /var/log/php74-sitename
Start the php-fpm server:
docker run \
--user 33:33 \
--network host \
--restart always \
--detach \
--name sitename-php74-fpm \
--volume=/path/to/web:/path/to/web \
--volume=/var/log/php74-sitename:/var/log/php74-sitename \
sitename-php74-fpm
Notes:
-p 127.0.0.1:7474:7474 to share the php-fpm port, and --add-host=host.docker.internal:host-gateway to share the host's ports. In that case, you'd need to have your app connect to host.docker.internal instead of localhost, and update user permissions in mysql for the docker IP.You should now be able to access your PHP website, though you might get some MySQL errors (see below MySQL section).
It can be challenging to pinpoint where problems arise inside or outside the container, so here are some general troubleshooting tips and tools.
Checking the docker instance can give some hints, especially for Apache connecting to php-fpm. Run this in a window while trying to access your site:
docker logs --follow sitename-php74-fpm
It should output access log information as you refresh the page.
You can check logs where you specified them earlier (ie: /var/log/php74-sitename/error.log)
Enter the container as follows and check it has appropriate permissions:
docker exec -it sitename-php74-fpm /bin/bash
ls -lth /path/to/web
cat /path/to/web/index.php
If you've previously been connecting to localhost, you will likely find you are now getting a 'File Not Found' error. This is because the PHP MySQL client actually aliases that to a socket connection. To work around this, simply update your app config to connect to 127.0.0.1 instead of localhost.
This simple test ensures php-fpm can connect to MySQL (or some other service running on the host). A more advanced version could install the mysql client, though it is not included in Debian's repos so a custom install would be needed.
Enter the container as follows and check basic port access to mysql:
docker exec -it sitename-php74-fpm /bin/bash
telnet 127.0.0.1 3306
you can build your own image and in the Dockerfile you can apt install ...
but there is also an official image with apache + php-fpm here: https://hub.docker.com/_/php
so you dont have to. its ready to go.
but i believe it could work by exposing your php-fpm port and configuring your apache FastCgiExternalServer to this port instead of a unix socket.