<!--
  canonical-url: https://www.avonture.be/blog/install-docker
  published:     2023-11-03
  This is a static plain-Markdown mirror generated at build time.
  Visit the canonical URL above for the fully rendered page, with images and interactive components.
-->

# Install Docker and play with PHP

> Install Docker and run PHP with Apache instantly using containers. Learn to easily switch between PHP versions (like 7.4 and 8.1) without painful local conflicts.

---
![Install Docker and play with PHP](/img/v2/docker_tips.webp)

**TL;DR**

This getting-started article installs Docker Desktop and runs a PHP+Apache site with zero local PHP/Apache install: `docker run --detach --name step_1_1a -p 80:80 php:8.3-apache`, then creating an `index.php` inside the container via `docker exec`. It shows how trivially you can switch PHP versions (e.g. to `php:8.4-apache` on a different port) compared to juggling versions with EasyPHP or WAMP.

Docker can be installed free of charge for personal or small-scale usage: [https://www.docker.com/products/personal/](https://www.docker.com/products/docker-desktop/).

You can install it on Linux, Mac or Windows.

The easiest way, on Windows, is to use [Docker Desktop](https://www.docker.com/products/docker-desktop/).

## One command, a working PHP server

Start a new console (DOS, Powershell or Linux) and run this:

```bash
$ docker run --detach --name step_1_1a -p 80:80 php:8.3-apache
```

Drop an `index.php` file calling `phpinfo()` in it (we'll see how, below), surf to `http://127.0.0.1
:
80`, and here is a PHP 8.3 server answering on your machine:

> Screenshot — http\://127.0.0.1:80/
>
> phpinfo - PHP 8.3

Apache is running, PHP is running, and neither of them has been installed on your computer.

## Why Docker images

* Images are most of the time just plug-and-play: once downloaded, they are ready to use. You will probably add some configuration items but, most of the time, it is not even needed.
* On [Docker Hub](https://hub.docker.com) you'll find a huge number of images for running PHP, PHP+Apache, MySQL and many, many more; all of them completely free, public or private, and you can publish your own. If the very concept of Docker is still fuzzy to you, [Docker - Explain me like I'm five](/blog/docker-definition-like-im-five) is a good, gentle primer.
* The old-fashioned way, before running a web page locally, you first install a web server (e.g., Apache) and the PHP interpreter, then fight to change their versions. Here, the version is a word in a command line.

In this blog post, we will be using the PHP images available at <https://hub.docker.com/_/php>

## Setting it up

The easiest way, on Windows, is to use [Docker Desktop](https://www.docker.com/products/docker-desktop/). Once installed, the command shown above is all you need; Docker will, the first time, download PHP `8.3` (including Apache) and, once downloaded, start the image.

> **Information:**
>
> On subsequent runs, the PHP image is already present, so it is no longer downloaded. And the commands we will use in this step will be the same whether you are running Linux, Mac or Windows.

Explanation of the arguments used in our `docker run --detach --name 
step_1_1a
 -p 
80
:80 php:8.3-apache` command

* `--detach`: by default, `docker run` executes the container and closes it as soon as the job is finished. If the image were a virus scanner, `docker run` would run a scan and close the container when the scan is complete. Here, we want to keep our site "listening",
* `--name` step\_1\_1a: just for simplicity's sake, let's give our container a name. This is a recommended practice for clearly identifying containers,
* `-p 
  80
  :80`: our PHP+Apache image runs on port `80`, so we want to map this "internal" port to port 80 on our computer. This allows us to access the web site.
* `php:8.3-apache`: the name of the used image. We ask php+apache, version 8.3.

![The PHP container is running](./images/php_container_is_running.webp)

We can see that the PHP image is now present in Docker Desktop, and that an application (a `container` in Docker terms) is running. We also get both information on the command line, with `docker image list` and `docker container list`.

### Creating our PHP script

With the instruction below, we can launch a Linux console and display the contents of the image *as if* it were a folder on our hard disk:

```bash
$ docker exec -it step_1_1a /bin/bash
```

Once in the console, let's quickly create an `index.php` file and exit the console; we will not need it again.

```bash
$ echo "<?php" > index.php
$ echo "phpinfo();" >> index.php
$ exit
```

Back to our browser and... Bingo! Our first Docker instance running a PHP script, i.e. the screenshot shown at the beginning of this article.

## Changing the PHP version in one word

Have you ever tried to change your PHP version if you are using EasyPHP, WAMP or another software program: it is a real pain! With Docker, you change one word.

By going to the page <https://hub.docker.com/_/php?tab=tags> and searching for `-apache` images, you'll find every published version. Let's change `8.3` to `8.4` and, for example, use another port (we will use `801` this time).

```bash
$ docker run --detach --name step_1_1b -p 801:80 php:8.4-apache
```

```bash
$ docker exec -it step_1_1b /bin/bash
```

```bash
$ echo "<?php" > index.php
$ echo "phpinfo();" >> index.php
$ exit
```

> Screenshot — http\://127.0.0.1:801/
>
> phpinfo - PHP 8.4

***No headaches and zero conflicts!*** We have installed a new version of PHP in seconds, and the two versions are running side by side, each on its own port.

> **Information:**
>
> This is just crazy. Think of the benefits: you are developing a PHP script and want to check whether it works with different versions of PHP. It's child's play.

## Under the Hood (skip this if you just want to use it)

Before creating the `index.php` file, the site answers, but with a *Forbidden* page:

> Screenshot — http\://127.0.0.1:80/
>
> ![localhost-is-forbidden](./images/localhost_is_forbidden.webp)

It works in the sense that *something is listening and has responded*, but does not display anything, since we haven't set anything up yet: Apache is ready, there's simply no `index.php` file yet. That's the difference between "the container runs" and "the site works".

> **Note:**
>
> In this chapter, as we discover Docker, we've used different port numbers each time to access our local site (80 then 801). This is only to keep both containers alive at the same time; two containers can't publish the same port on your machine.

Note also that the `index.php` we created lives **inside** the container: remove the container and the file goes with it. That's the next step.

## Conclusion

**At the end of this chapter, we've just learned:**

* how to use Docker,

* define the PHP version we want to use,

* how to name our containers,

* define different ports for different containers.

Now let's take it to the next level and synchronize the files on our hard disk with the container: [Share data between your running Docker container and your computer](/blog/docker-volume), so your code stays on your disk instead of inside the container, then [The easiest way to run a PHP script / website](/blog/docker-php-run-script-or-website), which combines both in a single command.

This same "zero local install" approach works for pretty much any language — I've since applied it to [Python](/blog/docker-python), [Pascal](/blog/docker-pascal), [Assembly](/blog/docker-assembly), and [Java](/blog/docker-java).
