Before we start…
Before we start, we have to agree on one thing – Docker is super cool! If you are not familiar with Docker, I suggest to have a look at the tons of 'Getting starting with Docker' or 'What is Docker?' articles and then come back here. :)
Since you keep reading, I will assume that you already have some Docker experience and you want to run your PHP applications in containers. Because who wants the trouble of installing all the dependencies on their local environment or manage a number of virtual machines for their different projects, right? Right!
Sending emails from PHP in a docker container This should be a trivial task but there are several issues that trip you up when trying to get this to work. I'm using the official php image php:7-latest as the base. Running a PHP Web App in a Docker Container Written on August 30th, 2017 by Karl Hughes If you're familiar with the process for creating a simple website using PHP, then adding Docker to the mix should be relatively easy. The great thing about using Docker is that you have better portability over your code. FROM php:7.4-apache RUN docker-php-ext-install mysqli. I know that's a lot of code to process. So let's take it line-by-line. The first line uses the php:7.4-apache image to build the container. The second line runs a command to install the mysqli extension inside the container.
The goal that we will try to achieve is to run a simple PHP application using the official Docker repositories for both PHP and Nginx. There are several docker repositories combining PHP-FPM with Nginx, but depending on the official repositories gives you several benefits, like using a service which is configured by its maintainers and you can always choose between the latest and greatest or different versions of both services, instead of relying on someone else's choices.
The first thing you have to do is, of course, install Docker (if you haven't already). The second prerequisite is getting Docker Compose (it is included in the Mac toolbox). Now that we know what we want to achieve and have the tools to accomplish it – let's get our hands dirty!
Setting up Nginx
We'll start by getting ourselves a web server and based on our requirements this will be a container running the official Nginx image. Since we'll be using Docker Compose, we will create the following docker-compose.yml file, which will run the latest Nginx image and will expose its port 80 to port 8080:
Getting Started With Docker for PHP First, make sure you have Docker installed on your local system. I think the documentation on the website is clear for all operating systems. The other thing you're going to need for this tutorial is the PHP package management system called composer. Docker provides regularly updated PHP Images that can be pulled straight from the Dockerhub and can be customized using Dockerfiles. The Docker PHP Image allows you to build and run PHP applications and to access such applications on your localhost, you can use the -p flag to connect and publish ports.
Now we can run
This should give you the default Nginx screen on port 8080 for localhost or the IP of your docker machine.
Now that we have a server let's add some code. First we have to update the docker-compose.yml to mount a local directory. I will use a folder called code, which is in the same directory as my docker-compose.yml file, and it will be mounted as root folder code in the container.
The next step is to let Nginx know that this folder exists.
Let's create the following site.conf on the same level as the docker-compose.yml file:
If you don't have a lot of experience with Nginx, this is what we define here – index.html will be our default index, the server name is php-docker.local and it should be pointing (update your hosts file) to your Docker environment (localhost if you are on Linux or the docker machine if you are on Mac or Windows), we point the error logs to be the ones exposed by the default container, so that we will see the errors in our docker compose log, and finally we specify the root folder to be the one that we mounted in the container.
To activate this setup we need to apply yet another modification to our docker-compose.yml file:
This will add site.conf to the directory where Nginx is looking for configuration files to include. You can now place an index.html file in the code folder with contents that is to your heart's delight. And if we run
again, the index.html file should be available on php-docker.local:8080.
Yeey! We are half way there
Adding PHP-FPM
Now that we have Nginx up and running let's add the PHP in the game. The first thing we'll do is pull the official PHP7-FPM repo and link it to our Nginx container. Our docker-compose.yml will look like this now:
The next thing to do is configure Nginx to use the PHP-FPM container for interpreting PHP files. Your updated site.conf should look like this:
In order to test this let's rename the index.html file to index.php and replace its content with the standard:
One final
Drive up the hill to Oliver Winery,. Feel transported to a California vineyard. Site Map; Address & Phone. 200 East Winery Road, Bloomington, IN 47404 (812. Oliver winery position.
And we should be good to go.. but
Instead of getting the proper PHP info page we receive the rather unsettling
Since PHP is running in its own environment (container) it doesn't have access to the code. In order to fix this, we need to mount the code folder in the PHP container too. This way Nginx will be able to serve any static files, and PHP will be able to find the files it has to interpret. One final change to the docker-compose.yml:
Finally, this last (this time for real)
present us with the much wanted PHP info
This is it.
We can run any simple PHP application inside Docker containers, using the official images for Nginx and PHP.
You can find the sample project here https://github.com/mikechernev/dockerised-php
EDIT: Since the GitHub repository changed quite a lot, I added a new blog post explaining the improvements - Making your dockerised PHP application even better
Sending emails from PHP in a docker container
This should be a trivial task but there are several issues that trip you up when trying to get this to work. Nordvpn kaspersky.
I'm using the official php image php:7-latest as the base.
Normally, you'd expect to need to just install sendmail in the Dockerfile:
RUN apt-get update &&
apt-get install -y
sendmail
# And clean up the image
RUN rm -rf /var/lib/apt/lists/*
However, this doesn't work for several reasons and needs some additional tweaks.
Problem 1: PHP does not have the sendmail path set
This is an easy fix. Set sendmail_path in an ini file during the container build process:
RUN echo 'sendmail_path=/usr/sbin/sendmail -t -i' >> /usr/local/etc/php/conf.d/sendmail.ini
Problem 2: You need to start the sendmail service
Because RUN
commands only execute during the build process, you can't just add RUN service sendmail start
to the Dockerfile, it has to be done each time the container is started.
So what you need to do is manually run the command in the container after it's been started:
docker exec [container id] service sendmail start
Problem 3: sendmail requires editing the /etc/hosts file
The solution above still won't work because sendmail scans the hostname for the local domain name. Docker doesn't set this by default, it can be generated by running this inside the container then restarting the sendmail service:
echo '$(hostname -i)t$(hostname) $(hostname).localhost' >> /etc/hosts
service sendmail restart
With both these done your PHP scripts can send emails with the mail function again!
Better solution?
The obvious issue with this approach is that any time the contianer is restarted or run on a different machine you have to manually run both these commands in the container:
Getting Started With Docker for PHP First, make sure you have Docker installed on your local system. I think the documentation on the website is clear for all operating systems. The other thing you're going to need for this tutorial is the PHP package management system called composer. Docker provides regularly updated PHP Images that can be pulled straight from the Dockerhub and can be customized using Dockerfiles. The Docker PHP Image allows you to build and run PHP applications and to access such applications on your localhost, you can use the -p flag to connect and publish ports.
Now we can run
This should give you the default Nginx screen on port 8080 for localhost or the IP of your docker machine.
Now that we have a server let's add some code. First we have to update the docker-compose.yml to mount a local directory. I will use a folder called code, which is in the same directory as my docker-compose.yml file, and it will be mounted as root folder code in the container.
The next step is to let Nginx know that this folder exists.
Let's create the following site.conf on the same level as the docker-compose.yml file:
If you don't have a lot of experience with Nginx, this is what we define here – index.html will be our default index, the server name is php-docker.local and it should be pointing (update your hosts file) to your Docker environment (localhost if you are on Linux or the docker machine if you are on Mac or Windows), we point the error logs to be the ones exposed by the default container, so that we will see the errors in our docker compose log, and finally we specify the root folder to be the one that we mounted in the container.
To activate this setup we need to apply yet another modification to our docker-compose.yml file:
This will add site.conf to the directory where Nginx is looking for configuration files to include. You can now place an index.html file in the code folder with contents that is to your heart's delight. And if we run
again, the index.html file should be available on php-docker.local:8080.
Yeey! We are half way there
Adding PHP-FPM
Now that we have Nginx up and running let's add the PHP in the game. The first thing we'll do is pull the official PHP7-FPM repo and link it to our Nginx container. Our docker-compose.yml will look like this now:
The next thing to do is configure Nginx to use the PHP-FPM container for interpreting PHP files. Your updated site.conf should look like this:
In order to test this let's rename the index.html file to index.php and replace its content with the standard:
One final
Drive up the hill to Oliver Winery,. Feel transported to a California vineyard. Site Map; Address & Phone. 200 East Winery Road, Bloomington, IN 47404 (812. Oliver winery position.
And we should be good to go.. but
Instead of getting the proper PHP info page we receive the rather unsettling
Since PHP is running in its own environment (container) it doesn't have access to the code. In order to fix this, we need to mount the code folder in the PHP container too. This way Nginx will be able to serve any static files, and PHP will be able to find the files it has to interpret. One final change to the docker-compose.yml:
Finally, this last (this time for real)
present us with the much wanted PHP info
This is it.
We can run any simple PHP application inside Docker containers, using the official images for Nginx and PHP.
You can find the sample project here https://github.com/mikechernev/dockerised-php
EDIT: Since the GitHub repository changed quite a lot, I added a new blog post explaining the improvements - Making your dockerised PHP application even better
Sending emails from PHP in a docker container
This should be a trivial task but there are several issues that trip you up when trying to get this to work. Nordvpn kaspersky.
I'm using the official php image php:7-latest as the base.
Normally, you'd expect to need to just install sendmail in the Dockerfile:
RUN apt-get update &&
apt-get install -y
sendmail
# And clean up the image
RUN rm -rf /var/lib/apt/lists/*
However, this doesn't work for several reasons and needs some additional tweaks.
Problem 1: PHP does not have the sendmail path set
This is an easy fix. Set sendmail_path in an ini file during the container build process:
RUN echo 'sendmail_path=/usr/sbin/sendmail -t -i' >> /usr/local/etc/php/conf.d/sendmail.ini
Problem 2: You need to start the sendmail service
Because RUN
commands only execute during the build process, you can't just add RUN service sendmail start
to the Dockerfile, it has to be done each time the container is started.
So what you need to do is manually run the command in the container after it's been started:
docker exec [container id] service sendmail start
Problem 3: sendmail requires editing the /etc/hosts file
The solution above still won't work because sendmail scans the hostname for the local domain name. Docker doesn't set this by default, it can be generated by running this inside the container then restarting the sendmail service:
echo '$(hostname -i)t$(hostname) $(hostname).localhost' >> /etc/hosts
service sendmail restart
With both these done your PHP scripts can send emails with the mail function again!
Better solution?
The obvious issue with this approach is that any time the contianer is restarted or run on a different machine you have to manually run both these commands in the container:
echo '$(hostname -i)t$(hostname) $(hostname).localhost' >> /etc/hosts
service sendmail start
It would be better if this was done automatically in the Dockerfile.
This is possible by adding the lines to PHP's docker entrypoint during the build process:
RUN sed -i '/#!/bin/sh/aservice sendmail restart' /usr/local/bin/docker-php-entrypoint
RUN sed -i '/#!/bin/sh/aecho '$(hostname -i)t$(hostname) $(hostname).localhost' >> /etc/hosts' /usr/local/bin/docker-php-entrypoint
Now you can just docker run or docker-compose up like normal without needing to remember to amend the hosts file and start the service.
Complete Dockerfile example
Docker Php Docker-php-ext-install
Here's a sample Dockerfile with a few extensions enabled as well:
FROM php:7-fpm
RUN apt-get update &&
apt-get install -y
zlib1g-dev libzip-dev sendmail
RUN echo 'sendmail_path=/usr/sbin/sendmail -t -i' >> /usr/local/etc/php/conf.d/sendmail.ini
RUN docker-php-ext-install pdo_mysql
RUN docker-php-ext-install zip
RUN sed -i '/#!/bin/sh/aservice sendmail restart' /usr/local/bin/docker-php-entrypoint
RUN sed -i '/#!/bin/sh/aecho '$(hostname -i)t$(hostname) $(hostname).localhost' >> /etc/hosts' /usr/local/bin/docker-php-entrypoint
# And clean up the image
RUN rm -rf /var/lib/apt/lists/*
Caveats
This approach works and it's the best I was able to manage but there are a few notes when doing this:
Docker Php Apache
1. This isn't a very Docker way of doing things. It would be nicer to run sendmail in its own container and connect to it from PHP, though this would require extra steps and still installing the bridge (e.g. ssmpt or similar) in the PHP container.
2. This solution is also rather brittle. If the base PHP image changes the location of the entrypoint script, this will stop working.
Docker Php
3. All the normal discussions about the pros/cons of sendmail vs a proper mailserver apply.