├── .github ├── FUNDING.yml └── workflows │ └── build.yml ├── README.md ├── docker-compose.yml ├── main.yml ├── requirements.yml └── vars ├── 8.1.yml ├── 8.2.yml └── 8.3.yml /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | --- 3 | github: geerlingguy 4 | patreon: geerlingguy 5 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Build 3 | 4 | on: 5 | pull_request: 6 | push: 7 | branches: 8 | - master 9 | schedule: 10 | - cron: "45 1 * * 0" 11 | 12 | env: 13 | ANSIBLE_FORCE_COLOR: true 14 | 15 | jobs: 16 | # Test the images build and work correctly. 17 | test: 18 | name: Test 19 | runs-on: ubuntu-latest 20 | strategy: 21 | matrix: 22 | php_version: 23 | - '8.3' 24 | - '8.2' 25 | - '8.1' 26 | 27 | steps: 28 | - uses: actions/checkout@v2 29 | 30 | - name: Set up Python 3. 31 | uses: actions/setup-python@v2 32 | with: 33 | python-version: '3.x' 34 | 35 | - name: Install prerequisites. 36 | run: pip3 install ansible docker six 37 | 38 | - name: Install role dependencies. 39 | run: ansible-galaxy install -r requirements.yml 40 | 41 | - name: Build the container. 42 | run: ansible-playbook --extra-vars="@vars/${{ matrix.php_version }}.yml" main.yml 43 | 44 | - name: Run the container. 45 | run: docker run -d --name=php-apache -p 8080:80 geerlingguy/php-apache:${{ matrix.php_version }} /usr/sbin/apache2ctl -D FOREGROUND 46 | 47 | - name: Verify container has correct PHP version and works. 48 | run: | 49 | docker exec php-apache php -v | grep ${{ matrix.php_version }} 50 | curl http://localhost:8080/ 51 | 52 | # If on master branch, build and release images. 53 | release: 54 | name: Release 55 | runs-on: ubuntu-latest 56 | strategy: 57 | matrix: 58 | php_version: 59 | - '8.3' 60 | - '8.2' 61 | - '8.1' 62 | needs: test 63 | if: github.ref == 'refs/heads/master' 64 | 65 | steps: 66 | - uses: actions/checkout@v2 67 | 68 | - name: Set up Python 3. 69 | uses: actions/setup-python@v2 70 | with: 71 | python-version: '3.x' 72 | 73 | - name: Install prerequisites. 74 | run: pip3 install ansible docker six 75 | 76 | - name: Install role dependencies. 77 | run: ansible-galaxy install -r requirements.yml 78 | 79 | - name: Build the container. 80 | run: ansible-playbook --extra-vars="@vars/${{ matrix.php_version }}.yml" main.yml 81 | 82 | - name: Login to DockerHub 83 | uses: docker/login-action@v1 84 | with: 85 | username: ${{ secrets.DOCKERHUB_USERNAME }} 86 | password: ${{ secrets.DOCKERHUB_TOKEN }} 87 | 88 | - name: Push image. 89 | run: | 90 | # Push $php_version tag. 91 | docker push geerlingguy/php-apache:${{ matrix.php_version }} 92 | 93 | # Push $php_version + '.x' tag. 94 | docker tag geerlingguy/php-apache:${{ matrix.php_version }} geerlingguy/php-apache:${{ matrix.php_version }}.x 95 | docker push geerlingguy/php-apache:${{ matrix.php_version }}.x 96 | 97 | # Push $php_version + '.PHP_RELEASE_VERSION' tag. 98 | php_release_version=$(docker run --rm geerlingguy/php-apache:${{ matrix.php_version }} bash -c "php -r 'echo PHP_RELEASE_VERSION;'") 99 | docker tag geerlingguy/php-apache:${{ matrix.php_version }} geerlingguy/php-apache:${{ matrix.php_version }}.${php_release_version} 100 | docker push geerlingguy/php-apache:${{ matrix.php_version }}.${php_release_version} 101 | 102 | # Push latest tag if building latest version. 103 | if [[ "${{ matrix.php_version }}" == "8.3" ]]; then 104 | docker tag geerlingguy/php-apache:${{ matrix.php_version }} geerlingguy/php-apache:latest 105 | docker push geerlingguy/php-apache:latest 106 | fi 107 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PHP Apache Container (Built with Ansible) 2 | 3 | [![Build](https://github.com/geerlingguy/php-apache-container/actions/workflows/build.yml/badge.svg)](https://github.com/geerlingguy/php-apache-container/actions/workflows/build.yml) [![Docker pulls](https://img.shields.io/docker/pulls/geerlingguy/php-apache)](https://hub.docker.com/r/geerlingguy/php-apache/) 4 | 5 | This project is composed of three main parts: 6 | 7 | - **Ansible project**: This project is maintained on GitHub: [geerlingguy/php-apache-container](https://github.com/geerlingguy/php-apache-container). Please file issues, support requests, etc. against this GitHub repository. 8 | - **Docker Hub Image**: If you just want to use [the `geerlingguy/php-apache` Docker image](https://hub.docker.com/r/geerlingguy/php-apache/) in your project, you can pull it from Docker Hub. 9 | - **Ansible Role**: If you need a flexible Ansible role that's compatible with both traditional servers and containerized builds, check out [`geerlingguy.php`](https://galaxy.ansible.com/geerlingguy/php/) on Ansible Galaxy. (This is the Ansible role that does the bulk of the work in managing the PHP container.) 10 | 11 | ## Versions 12 | 13 | Currently maintained versions include: 14 | 15 | - `8.3`, `8.3.x`, `latest`: PHP 8.3.x 16 | - `8.2`, `8.2.x`: PHP 8.2.x 17 | - `8.1`, `8.1.x`: PHP 8.1.x 18 | 19 | ## Standalone Usage 20 | 21 | If you want to use the `geerlingguy/php-apache` image from Docker Hub, you don't need to install or use this project at all. You can quickly build a PHP container locally with: 22 | 23 | docker run -d --name=php-apache -p 80:80 geerlingguy/php-apache:latest /usr/sbin/apache2ctl -D FOREGROUND 24 | 25 | You can also wrap up that configuration in a `Dockerfile` and/or a `docker-compose.yml` file if you want to keep things simple. For example: 26 | 27 | version: "3" 28 | 29 | services: 30 | php-apache: 31 | image: geerlingguy/php-apache:latest 32 | container_name: php-apache 33 | ports: 34 | - "80:80" 35 | restart: always 36 | # See 'Custom PHP codebase' for instructions for volumes. 37 | volumes: [] 38 | 39 | Then run: 40 | 41 | docker-compose up -d 42 | 43 | Now you should be able to access the default home page at `http://localhost/`. 44 | 45 | ### Custom PHP codebase 46 | 47 | If you have a codebase inside the folder `web`, mount it as a volume like `-v ./web:/var/www/html:rw,delegated`. 48 | 49 | Or, if using a Docker Compose file: 50 | 51 | services: 52 | myapp: 53 | ... 54 | volumes: 55 | - ./web:/var/www/html:rw,delegated 56 | 57 | If you wish to build an image using this image as the base (e.g. for deploying to production), create a Dockerfile and `COPY` the webroot into place so it's part of the image. 58 | 59 | If you want to run multiple webroots, or need to further customize the Apache VirtualHost definitions, you can mount a config file over the existing one in the container, e.g.: 60 | 61 | services: 62 | myapp: 63 | ... 64 | volumes: 65 | - ./web:/var/www/html:rw,delegated 66 | - ./virtualhosts.conf:/etc/apache2/sites-enabled/vhosts.conf:rw 67 | 68 | Similarly, you can mount a PHP config file to the path `/etc/php/8.3/apache2/php.ini` (substitute whatever PHP version you're currently using in that path). 69 | 70 | ## Management with Ansible 71 | 72 | ### Prerequisites 73 | 74 | Before using this project to build and maintain PHP images for Docker, you need to have the following installed: 75 | 76 | - [Docker Community Edition](https://docs.docker.com/engine/installation/) (for Mac, Windows, or Linux) 77 | - [Ansible](http://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html) 78 | 79 | ### Build the image 80 | 81 | First, install Ansible role requirements: 82 | 83 | ansible-galaxy install -r requirements.yml 84 | 85 | Then, make sure Docker is running, and run the playbook to build the container: 86 | 87 | ansible-playbook --extra-vars="@vars/8.2.yml" main.yml 88 | 89 | (Substitute whatever supported PHP version you desire in the vars path) Once the image is built, you can run `docker images` to see the `php-apache` image that was generated. 90 | 91 | > Note: If you get an error like `Failed to import docker`, run `pip install docker`. 92 | 93 | ### Push the image to Docker Hub 94 | 95 | See the `.github/workflows/build.yml` file in this repository for how it pushes all the tagged images automatically on any commit to the `master` branch. 96 | 97 | ## License 98 | 99 | MIT / BSD 100 | 101 | ## Author Information 102 | 103 | This container build was created in 2018 by [Jeff Geerling](https://www.jeffgeerling.com/), author of [Ansible for DevOps](https://www.ansiblefordevops.com/). 104 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: "3" 3 | 4 | services: 5 | php-apache: 6 | image: geerlingguy/php-apache:latest 7 | container_name: php-apache 8 | ports: 9 | - "80:80" 10 | restart: always 11 | # See 'Custom PHP codebase' for instructions for volumes. 12 | volumes: 13 | - ./web:/var/www/html:rw,delegated 14 | command: ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"] 15 | -------------------------------------------------------------------------------- /main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | connection: local 4 | gather_facts: no 5 | 6 | vars: 7 | base_image: debian:bookworm 8 | container_name: php_apache_build_container 9 | image_namespace: geerlingguy 10 | image_name: php-apache 11 | 12 | # Apache settings. 13 | apache_remove_default_vhost: yes 14 | 15 | # PHP settings. 16 | php_version: '8.3' 17 | php_packages_extra: 18 | - libapache2-mod-php8.3 19 | php_install_recommends: no 20 | 21 | # Handy utilities. 22 | handy_utilities: 23 | - curl 24 | - unzip 25 | - tar 26 | - sudo 27 | 28 | pre_tasks: 29 | - name: Make the latest version of the base image available locally. 30 | docker_image: 31 | name: '{{ base_image }}' 32 | source: pull 33 | force_source: true 34 | 35 | - name: Create the Docker container. 36 | docker_container: 37 | image: '{{ base_image }}' 38 | name: '{{ container_name }}' 39 | command: sleep infinity 40 | 41 | - name: Add the newly created container to the inventory. 42 | add_host: 43 | hostname: '{{ container_name }}' 44 | ansible_connection: docker 45 | 46 | - name: Ensure Python is installed. 47 | raw: > 48 | apt-get update && 49 | apt-get install -y --no-install-recommends python3 50 | delegate_to: '{{ container_name }}' 51 | 52 | - name: Gather facts inside the container. 53 | setup: 54 | delegate_to: '{{ container_name }}' 55 | 56 | - name: Install handy utilities. 57 | package: 58 | name: "{{ item }}" 59 | state: present 60 | with_items: "{{ handy_utilities }}" 61 | delegate_to: '{{ container_name }}' 62 | 63 | roles: 64 | - name: geerlingguy.apache 65 | delegate_to: '{{ container_name }}' 66 | 67 | - name: geerlingguy.php-versions 68 | delegate_to: '{{ container_name }}' 69 | 70 | - name: geerlingguy.php 71 | delegate_to: '{{ container_name }}' 72 | 73 | - name: geerlingguy.php-mysql 74 | delegate_to: '{{ container_name }}' 75 | 76 | - name: geerlingguy.composer 77 | delegate_to: '{{ container_name }}' 78 | 79 | post_tasks: 80 | - name: Clean up the container. 81 | shell: > 82 | apt-get remove --purge -y python && 83 | rm -rf /var/lib/apt/lists/* 84 | delegate_to: '{{ container_name }}' 85 | 86 | - name: Commit the container. 87 | command: > 88 | docker commit 89 | -c 'CMD ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"]' 90 | {{ container_name }} {{ image_namespace }}/{{ image_name }}:{{ php_version }} 91 | 92 | - name: Remove the container. 93 | docker_container: 94 | name: '{{ container_name }}' 95 | state: absent 96 | -------------------------------------------------------------------------------- /requirements.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - src: geerlingguy.apache 3 | - src: geerlingguy.php-versions 4 | - src: geerlingguy.php 5 | - src: geerlingguy.php-mysql 6 | - src: geerlingguy.composer 7 | -------------------------------------------------------------------------------- /vars/8.1.yml: -------------------------------------------------------------------------------- 1 | --- 2 | php_version: '8.1' 3 | php_packages_extra: 4 | - libapache2-mod-php8.1 5 | -------------------------------------------------------------------------------- /vars/8.2.yml: -------------------------------------------------------------------------------- 1 | --- 2 | php_version: '8.2' 3 | php_packages_extra: 4 | - libapache2-mod-php8.2 5 | -------------------------------------------------------------------------------- /vars/8.3.yml: -------------------------------------------------------------------------------- 1 | --- 2 | php_version: '8.3' 3 | php_packages_extra: 4 | - libapache2-mod-php8.3 5 | --------------------------------------------------------------------------------