├── .gitignore ├── ansible.cfg ├── .github ├── FUNDING.yml └── workflows │ └── build.yml ├── arm64 ├── vhosts.conf ├── Dockerfile └── docker-entrypoint.sh ├── arm32v7 ├── vhosts.conf └── Dockerfile ├── Dockerfile ├── docker-compose.yml ├── tests ├── download-method-git │ └── docker-compose.yml └── download-method-composer │ └── docker-compose.yml ├── main.yml ├── docker-entrypoint.sh └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | web/* 2 | -------------------------------------------------------------------------------- /ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | nocows = true 3 | stdout_callback = yaml 4 | bin_ansible_callbacks = True 5 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: geerlingguy 4 | patreon: geerlingguy 5 | -------------------------------------------------------------------------------- /arm64/vhosts.conf: -------------------------------------------------------------------------------- 1 | DirectoryIndex index.php index.html 2 | 3 | 4 | ServerName local.dev 5 | DocumentRoot "/var/www/html" 6 | 7 | 8 | AllowOverride All 9 | Options -Indexes +FollowSymLinks 10 | Require all granted 11 | 12 | 13 | -------------------------------------------------------------------------------- /arm32v7/vhosts.conf: -------------------------------------------------------------------------------- 1 | DirectoryIndex index.php index.html 2 | 3 | 4 | ServerName local.dev 5 | DocumentRoot "/var/www/html" 6 | 7 | 8 | AllowOverride All 9 | Options -Indexes +FollowSymLinks 10 | Require all granted 11 | 12 | 13 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM geerlingguy/php-apache:8.2 2 | 3 | RUN apt-get update \ 4 | && apt-get install -y mariadb-client git \ 5 | && rm -rf /var/lib/apt/lists/* 6 | 7 | COPY docker-entrypoint.sh /usr/local/bin/ 8 | RUN ln -s usr/local/bin/docker-entrypoint.sh / # For backwards compatibility. 9 | ENTRYPOINT ["docker-entrypoint.sh"] 10 | 11 | WORKDIR "/var/www/html" 12 | 13 | EXPOSE 80 14 | CMD ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"] 15 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: '3' 3 | 4 | services: 5 | drupal: 6 | build: ./ 7 | image: geerlingguy/drupal:latest 8 | container_name: drupal 9 | environment: 10 | DRUPAL_DATABASE_HOST: drupal-mysql 11 | DRUPAL_DATABASE_PORT: 3306 12 | DRUPAL_DATABASE_NAME: drupal 13 | DRUPAL_DATABASE_USERNAME: drupal 14 | DRUPAL_DATABASE_PASSWORD: drupal 15 | DRUPAL_DATABASE_PREFIX: drupal 16 | # Generate a salt with: `php -r "echo bin2hex(random_bytes(25));"` 17 | DRUPAL_HASH_SALT: db0de8a1556aa5348f87cfc950cd2c9641713d46e9412c8b05 18 | ports: 19 | - "80:80" 20 | restart: always 21 | # Uncomment the volumes line and set to the local path of your Drupal 22 | # installation, if you need to work with a local codebase. 23 | # volumes: 24 | # - ~/Sites/drupal-container:/var/www/html:rw,delegated 25 | 26 | mysql: 27 | image: mariadb:10 28 | container_name: drupal-mysql 29 | environment: 30 | MARIADB_RANDOM_ROOT_PASSWORD: 'yes' 31 | MARIADB_DATABASE: drupal 32 | MARIADB_USER: drupal 33 | MARIADB_PASSWORD: drupal 34 | ports: 35 | - "3306:3306" 36 | -------------------------------------------------------------------------------- /tests/download-method-git/docker-compose.yml: -------------------------------------------------------------------------------- 1 | --- 2 | services: 3 | drupal: 4 | build: ./ 5 | image: geerlingguy/drupal:latest 6 | container_name: drupal 7 | environment: 8 | DRUPAL_DATABASE_HOST: drupal-mysql 9 | DRUPAL_DATABASE_PORT: 3306 10 | DRUPAL_DATABASE_NAME: drupal 11 | DRUPAL_DATABASE_USERNAME: drupal 12 | DRUPAL_DATABASE_PASSWORD: drupal 13 | DRUPAL_DATABASE_PREFIX: drupal 14 | # Generate a salt with: `php -r "echo bin2hex(random_bytes(25));"` 15 | DRUPAL_HASH_SALT: db0de8a1556aa5348f87cfc950cd2c9641713d46e9412c8b05 16 | DRUPAL_DOWNLOAD_METHOD: git 17 | ports: 18 | - "80:80" 19 | restart: always 20 | # Uncomment the volumes line and set to the local path of your Drupal 21 | # installation, if you need to work with a local codebase. 22 | # volumes: 23 | # - ~/Sites/drupal-container:/var/www/html:rw,delegated 24 | 25 | mysql: 26 | image: mysql:5.7 27 | container_name: drupal-mysql 28 | environment: 29 | MYSQL_RANDOM_ROOT_PASSWORD: 'yes' 30 | MYSQL_DATABASE: drupal 31 | MYSQL_USER: drupal 32 | MYSQL_PASSWORD: drupal 33 | ports: 34 | - "3306:3306" 35 | -------------------------------------------------------------------------------- /tests/download-method-composer/docker-compose.yml: -------------------------------------------------------------------------------- 1 | --- 2 | services: 3 | drupal: 4 | build: ./ 5 | image: geerlingguy/drupal:latest 6 | container_name: drupal 7 | environment: 8 | DRUPAL_DATABASE_HOST: drupal-mysql 9 | DRUPAL_DATABASE_PORT: 3306 10 | DRUPAL_DATABASE_NAME: drupal 11 | DRUPAL_DATABASE_USERNAME: drupal 12 | DRUPAL_DATABASE_PASSWORD: drupal 13 | DRUPAL_DATABASE_PREFIX: drupal 14 | # Generate a salt with: `php -r "echo bin2hex(random_bytes(25));"` 15 | DRUPAL_HASH_SALT: db0de8a1556aa5348f87cfc950cd2c9641713d46e9412c8b05 16 | DRUPAL_DOWNLOAD_METHOD: composer 17 | DRUPAL_PROJECT_ROOT: /var/www/html 18 | APACHE_DOCUMENT_ROOT: /var/www/html/web 19 | ports: 20 | - "80:80" 21 | restart: always 22 | # Uncomment the volumes line and set to the local path of your Drupal 23 | # installation, if you need to work with a local codebase. 24 | # volumes: 25 | # - ~/Sites/drupal-container:/var/www/html:rw,delegated 26 | 27 | mysql: 28 | image: mysql:5.7 29 | container_name: drupal-mysql 30 | environment: 31 | MYSQL_RANDOM_ROOT_PASSWORD: 'yes' 32 | MYSQL_DATABASE: drupal 33 | MYSQL_USER: drupal 34 | MYSQL_PASSWORD: drupal 35 | ports: 36 | - "3306:3306" 37 | -------------------------------------------------------------------------------- /arm32v7/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM balenalib/raspberrypi3-debian:bookworm 2 | 3 | # Add Ondrej Sury's apt repo and requirements. 4 | RUN sudo apt-get update \ 5 | && sudo apt-get install apt-transport-https lsb-release ca-certificates wget git \ 6 | && sudo wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg \ 7 | && echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/php.list \ 8 | && rm -rf /var/lib/apt/lists/* 9 | 10 | # Install Apache, PHP 11 | RUN sudo apt-get update \ 12 | && sudo apt-get install -y \ 13 | apache2 libapache2-mod-php libpcre3-dev unzip \ 14 | php8.2-common:armhf php8.2-dev:armhf php8.2-gd:armhf php8.2-curl:armhf php8.2-imap:armhf php8.2-opcache:armhf php8.2-xml:armhf php8.2-mbstring:armhf php8.2-mysql:armhf php8.2-zip:armhf php-apcu:armhf \ 15 | mariadb-client \ 16 | && rm -rf /var/lib/apt/lists/* 17 | 18 | COPY --from=composer:latest /usr/bin/composer /usr/bin/composer 19 | 20 | RUN a2enmod rewrite 21 | 22 | RUN rm -f /etc/apache2/sites-enabled/000-default.conf 23 | COPY vhosts.conf /etc/apache2/sites-enabled/vhosts.conf 24 | 25 | COPY docker-entrypoint.sh /usr/local/bin/ 26 | RUN ln -s usr/local/bin/docker-entrypoint.sh / # For backwards compatibility. 27 | ENTRYPOINT ["docker-entrypoint.sh"] 28 | 29 | WORKDIR "/var/www/html" 30 | 31 | EXPOSE 80 32 | CMD ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"] 33 | -------------------------------------------------------------------------------- /main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | connection: local 4 | gather_facts: no 5 | 6 | vars: 7 | build_amd64: true 8 | build_arm64: true 9 | build_arm32: true 10 | 11 | tasks: 12 | - name: Build the x86 Docker image from the main Dockerfile. 13 | docker_image: 14 | build: 15 | path: ./ 16 | nocache: true 17 | pull: true 18 | name: geerlingguy/drupal 19 | tag: latest 20 | source: build 21 | force_source: true 22 | when: build_amd64 | bool 23 | 24 | - name: Copy entrypoint into arm64 folder temporarily. 25 | copy: 26 | src: docker-entrypoint.sh 27 | dest: arm64/docker-entrypoint.sh 28 | mode: 0755 29 | 30 | - name: Build the arm64 Docker image from the arm Dockerfile. 31 | docker_image: 32 | build: 33 | path: ./arm64/ 34 | nocache: true 35 | pull: true 36 | platform: linux/arm64 37 | name: geerlingguy/drupal 38 | tag: latest-arm64 39 | source: build 40 | force_source: true 41 | when: build_arm64 | bool 42 | 43 | - name: Remove temporary entrypoint file. 44 | file: 45 | path: arm64/docker-entrypoint.sh 46 | state: absent 47 | 48 | - name: Copy entrypoint into arm32v7 folder temporarily. 49 | copy: 50 | src: docker-entrypoint.sh 51 | dest: arm32v7/docker-entrypoint.sh 52 | mode: 0755 53 | 54 | - name: Build the arm32v7 Docker image from the arm Dockerfile. 55 | docker_image: 56 | build: 57 | path: ./arm32v7/ 58 | nocache: true 59 | pull: true 60 | name: geerlingguy/drupal 61 | tag: latest-arm32v7 62 | source: build 63 | force_source: true 64 | when: build_arm32 | bool 65 | 66 | - name: Remove temporary entrypoint file. 67 | file: 68 | path: arm32v7/docker-entrypoint.sh 69 | state: absent 70 | -------------------------------------------------------------------------------- /arm64/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:bookworm-slim 2 | 3 | RUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections 4 | 5 | ENV php_version="8.2" 6 | 7 | # Add Ondrej Sury's apt repo and requirements. 8 | RUN apt-get update \ 9 | && apt-get install -y apt-transport-https lsb-release ca-certificates curl wget git \ 10 | && wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg \ 11 | && echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/php.list \ 12 | && rm -rf /var/lib/apt/lists/* 13 | 14 | # Install Apache and PHP. 15 | RUN apt-get update \ 16 | && apt-get install -y \ 17 | apache2 libapache2-mod-php${php_version} libpcre3-dev unzip \ 18 | php${php_version}-common php${php_version}-dev php${php_version}-gd php${php_version}-curl php${php_version}-imap php${php_version}-opcache php${php_version}-xml php${php_version}-mbstring php${php_version}-mysql php${php_version}-zip php${php_version}-apcu \ 19 | mariadb-client --no-install-recommends \ 20 | && rm -rf /var/lib/apt/lists/* 21 | 22 | # Force specific version of PHP. 23 | RUN update-alternatives --set php /usr/bin/php${php_version} \ 24 | && update-alternatives --set phar /usr/bin/phar${php_version} \ 25 | && update-alternatives --set phar.phar /usr/bin/phar.phar${php_version} \ 26 | && update-alternatives --set phpize /usr/bin/phpize${php_version} \ 27 | && update-alternatives --set php-config /usr/bin/php-config${php_version} 28 | 29 | COPY --from=composer:latest /usr/bin/composer /usr/bin/composer 30 | 31 | RUN a2enmod rewrite 32 | 33 | RUN rm -f /etc/apache2/sites-enabled/000-default.conf 34 | COPY vhosts.conf /etc/apache2/sites-enabled/vhosts.conf 35 | 36 | COPY docker-entrypoint.sh /usr/local/bin/ 37 | RUN ln -s usr/local/bin/docker-entrypoint.sh / # For backwards compatibility. 38 | ENTRYPOINT ["docker-entrypoint.sh"] 39 | 40 | WORKDIR "/var/www/html" 41 | 42 | EXPOSE 80 43 | CMD ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"] 44 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Build 3 | 4 | on: 5 | pull_request: 6 | push: 7 | branches: 8 | - master 9 | schedule: 10 | - cron: "15 3 * * 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 | compose_dir: 23 | - '.' 24 | # - 'tests/download-method-git' # Not working as of 2021-03-01. 25 | - 'tests/download-method-composer' 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 | # See: https://github.com/geerlingguy/ansible-role-mysql/issues/422 39 | - name: Disable AppArmor. 40 | run: | 41 | set -x 42 | sudo apt-get install apparmor-profiles 43 | sudo ln -s /etc/apparmor.d/usr.sbin.mysqld /etc/apparmor.d/disable/ 44 | sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.mysqld 45 | 46 | - name: Build the amd64 image. 47 | run: > 48 | ansible-playbook main.yml --extra-vars "{build_arm32: false, build_arm64: false}" 49 | 50 | - name: Run the amd64 image and test it. 51 | run: | 52 | attempts=0 53 | max_attempts=60 54 | 55 | cd ${{ matrix.compose_dir }} 56 | docker compose up -d 57 | 58 | echo "Waiting for Drupal to complete setup." 59 | until $(curl --output /dev/null --silent --head --fail http://localhost/); do 60 | if [ ${attempts} -eq ${max_attempts} ];then 61 | echo "Timeout while waiting for Drupal to complete setup." 62 | exit 1 63 | fi 64 | 65 | printf '.' 66 | attempts=$(($attempts+1)) 67 | sleep 5 68 | done 69 | 70 | # If on master branch, build and release images. 71 | release: 72 | name: Release 73 | runs-on: ubuntu-latest 74 | needs: test 75 | if: github.ref == 'refs/heads/master' 76 | 77 | steps: 78 | - uses: actions/checkout@v2 79 | 80 | - name: Set up Python 3. 81 | uses: actions/setup-python@v2 82 | with: 83 | python-version: '3.x' 84 | 85 | - name: Set up QEMU 86 | uses: docker/setup-qemu-action@v1 87 | 88 | - name: Set up Docker Buildx 89 | uses: docker/setup-buildx-action@v1 90 | with: 91 | install: true 92 | 93 | - name: Install prerequisites. 94 | run: pip3 install ansible docker six 95 | 96 | - name: Build the images. 97 | run: ansible-playbook main.yml 98 | 99 | - name: List all images for debugging. 100 | run: docker images 101 | 102 | - name: Login to DockerHub 103 | uses: docker/login-action@v1 104 | with: 105 | username: ${{ secrets.DOCKERHUB_USERNAME }} 106 | password: ${{ secrets.DOCKERHUB_TOKEN }} 107 | 108 | - name: Push images. 109 | run: | 110 | docker push geerlingguy/drupal:latest 111 | docker push geerlingguy/drupal:latest-arm64 112 | docker push geerlingguy/drupal:latest-arm32v7 113 | -------------------------------------------------------------------------------- /docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Drupal container entrypoint. 4 | # 5 | # This entrypoint script will create a new Drupal codebase if one is not already 6 | # present in the APACHE_DOCUMENT_ROOT directory. 7 | 8 | set -e 9 | 10 | # Allow container to specify skipping cert validation. 11 | DRUPAL_DOWNLOAD_VERIFY_CERT=${DRUPAL_DOWNLOAD_VERIFY_CERT:-true} 12 | 13 | # Allow setting the way Drupal is downloaded (tarball, git, composer). 14 | DRUPAL_DOWNLOAD_METHOD=${DRUPAL_DOWNLOAD_METHOD:-tarball} 15 | 16 | # Drupal URLs and version options. 17 | DRUPAL_DOWNLOAD_URL="https://www.drupal.org/download-latest/tar.gz" 18 | DRUPAL_CLONE_URL=${DRUPAL_CLONE_URL:-"https://git.drupalcode.org/project/drupal.git"} 19 | DRUPAL_CLONE_BRANCH=${DRUPAL_CLONE_BRANCH:-"10.3.x"} 20 | DRUPAL_PROJECT_VERSION=${DRUPAL_PROJECT_VERSION:-"^10@dev"} 21 | 22 | # Allow container to skip the download by setting this to false. 23 | DRUPAL_DOWNLOAD_IF_NOT_PRESENT=${DRUPAL_DOWNLOAD_IF_NOT_PRESENT:-true} 24 | 25 | # Allow container to skip composer install step by setting this to false. 26 | DRUPAL_RUN_COMPOSER_INSTALL=${DRUPAL_RUN_COMPOSER_INSTALL:-true} 27 | 28 | # Project directories. 29 | APACHE_DOCUMENT_ROOT=${APACHE_DOCUMENT_ROOT:-"/var/www/html"} 30 | DRUPAL_PROJECT_ROOT=${DRUPAL_PROJECT_ROOT:-$APACHE_DOCUMENT_ROOT} 31 | 32 | # Allow users to override the docroot by setting an environment variable. 33 | if [ "$APACHE_DOCUMENT_ROOT" != "/var/www/html" ]; then 34 | sed -ri -e "s|\"/var/www/html\"|\"$APACHE_DOCUMENT_ROOT\"|g" /etc/apache2/sites-enabled/*.conf 35 | sed -ri -e "s|\"/var/www/html\"|\"$APACHE_DOCUMENT_ROOT\"|g" /etc/apache2/apache2.conf /etc/apache2/conf-available/*.conf 36 | fi 37 | 38 | # Download Drupal to $APACHE_DOCUMENT_ROOT if it's not present. 39 | if [ ! -f $APACHE_DOCUMENT_ROOT/index.php ] && [ $DRUPAL_DOWNLOAD_IF_NOT_PRESENT = true ]; then 40 | echo "Removing any existing files inside $APACHE_DOCUMENT_ROOT..." 41 | find $DRUPAL_PROJECT_ROOT -type f -maxdepth 1 -delete || true 42 | 43 | cd $DRUPAL_PROJECT_ROOT 44 | if [ "$DRUPAL_DOWNLOAD_METHOD" == 'tarball' ]; then 45 | echo "Downloading Drupal..." 46 | if [ $DRUPAL_DOWNLOAD_VERIFY_CERT = true ]; then 47 | curl -sSL $DRUPAL_DOWNLOAD_URL | tar -xz --strip-components=1 48 | else 49 | curl -sSLk $DRUPAL_DOWNLOAD_URL | tar -xz --strip-components=1 50 | fi 51 | mkdir -p /var/www/config/sync 52 | echo "Download complete!" 53 | elif [ "$DRUPAL_DOWNLOAD_METHOD" == 'git' ]; then 54 | echo "Cloning Drupal..." 55 | git clone --branch $DRUPAL_CLONE_BRANCH --single-branch $DRUPAL_CLONE_URL . 56 | echo "Clone complete!" 57 | elif [ "$DRUPAL_DOWNLOAD_METHOD" == 'composer' ]; then 58 | composer -n create-project drupal/recommended-project:$DRUPAL_PROJECT_VERSION . 59 | fi 60 | 61 | echo "Configuring settings.php with environment variables..." 62 | cp $APACHE_DOCUMENT_ROOT/sites/default/default.settings.php $APACHE_DOCUMENT_ROOT/sites/default/settings.php 63 | cat <> $APACHE_DOCUMENT_ROOT/sites/default/settings.php 64 | \$databases['default']['default'] = array ( 65 | 'database' => '$DRUPAL_DATABASE_NAME', 66 | 'username' => '$DRUPAL_DATABASE_USERNAME', 67 | 'password' => '$DRUPAL_DATABASE_PASSWORD', 68 | 'prefix' => '$DRUPAL_DATABASE_PREFIX', 69 | 'host' => '$DRUPAL_DATABASE_HOST', 70 | 'port' => '$DRUPAL_DATABASE_PORT', 71 | 'namespace' => 'Drupal\\\\Core\\\\Database\\\\Driver\\\\mysql', 72 | 'driver' => 'mysql', 73 | ); 74 | \$config_directories['sync'] = '../config/sync'; 75 | \$settings['hash_salt'] = '$DRUPAL_HASH_SALT'; 76 | EOF 77 | 78 | echo "Correcting permissions on /var/www..." 79 | chown -R www-data:www-data /var/www 80 | 81 | if [ $DRUPAL_RUN_COMPOSER_INSTALL = true ] && [ "$DRUPAL_DOWNLOAD_METHOD" != 'composer' ]; then 82 | echo "Running composer install..." 83 | composer install 84 | fi 85 | 86 | echo "Drupal codebase ready!" 87 | fi 88 | 89 | exec "$@" 90 | -------------------------------------------------------------------------------- /arm64/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Drupal container entrypoint. 4 | # 5 | # This entrypoint script will create a new Drupal codebase if one is not already 6 | # present in the APACHE_DOCUMENT_ROOT directory. 7 | 8 | set -e 9 | 10 | # Allow container to specify skipping cert validation. 11 | DRUPAL_DOWNLOAD_VERIFY_CERT=${DRUPAL_DOWNLOAD_VERIFY_CERT:-true} 12 | 13 | # Allow setting the way Drupal is downloaded (tarball, git, composer). 14 | DRUPAL_DOWNLOAD_METHOD=${DRUPAL_DOWNLOAD_METHOD:-tarball} 15 | 16 | # Drupal URLs and version options. 17 | DRUPAL_DOWNLOAD_URL="https://www.drupal.org/download-latest/tar.gz" 18 | DRUPAL_CLONE_URL=${DRUPAL_CLONE_URL:-"https://git.drupalcode.org/project/drupal.git"} 19 | DRUPAL_CLONE_BRANCH=${DRUPAL_CLONE_BRANCH:-"10.3.x"} 20 | DRUPAL_PROJECT_VERSION=${DRUPAL_PROJECT_VERSION:-"^10@dev"} 21 | 22 | # Allow container to skip the download by setting this to false. 23 | DRUPAL_DOWNLOAD_IF_NOT_PRESENT=${DRUPAL_DOWNLOAD_IF_NOT_PRESENT:-true} 24 | 25 | # Allow container to skip composer install step by setting this to false. 26 | DRUPAL_RUN_COMPOSER_INSTALL=${DRUPAL_RUN_COMPOSER_INSTALL:-true} 27 | 28 | # Project directories. 29 | APACHE_DOCUMENT_ROOT=${APACHE_DOCUMENT_ROOT:-"/var/www/html"} 30 | DRUPAL_PROJECT_ROOT=${DRUPAL_PROJECT_ROOT:-$APACHE_DOCUMENT_ROOT} 31 | 32 | # Allow users to override the docroot by setting an environment variable. 33 | if [ "$APACHE_DOCUMENT_ROOT" != "/var/www/html" ]; then 34 | sed -ri -e "s|\"/var/www/html\"|\"$APACHE_DOCUMENT_ROOT\"|g" /etc/apache2/sites-enabled/*.conf 35 | sed -ri -e "s|\"/var/www/html\"|\"$APACHE_DOCUMENT_ROOT\"|g" /etc/apache2/apache2.conf /etc/apache2/conf-available/*.conf 36 | fi 37 | 38 | # Download Drupal to $APACHE_DOCUMENT_ROOT if it's not present. 39 | if [ ! -f $APACHE_DOCUMENT_ROOT/index.php ] && [ $DRUPAL_DOWNLOAD_IF_NOT_PRESENT = true ]; then 40 | echo "Removing any existing files inside $APACHE_DOCUMENT_ROOT..." 41 | find $DRUPAL_PROJECT_ROOT -type f -maxdepth 1 -delete || true 42 | 43 | cd $DRUPAL_PROJECT_ROOT 44 | if [ "$DRUPAL_DOWNLOAD_METHOD" == 'tarball' ]; then 45 | echo "Downloading Drupal..." 46 | if [ $DRUPAL_DOWNLOAD_VERIFY_CERT = true ]; then 47 | curl -sSL $DRUPAL_DOWNLOAD_URL | tar -xz --strip-components=1 48 | else 49 | curl -sSLk $DRUPAL_DOWNLOAD_URL | tar -xz --strip-components=1 50 | fi 51 | mkdir -p /var/www/config/sync 52 | echo "Download complete!" 53 | elif [ "$DRUPAL_DOWNLOAD_METHOD" == 'git' ]; then 54 | echo "Cloning Drupal..." 55 | git clone --branch $DRUPAL_CLONE_BRANCH --single-branch $DRUPAL_CLONE_URL . 56 | echo "Clone complete!" 57 | elif [ "$DRUPAL_DOWNLOAD_METHOD" == 'composer' ]; then 58 | composer -n create-project drupal/recommended-project:$DRUPAL_PROJECT_VERSION . 59 | fi 60 | 61 | echo "Configuring settings.php with environment variables..." 62 | cp $APACHE_DOCUMENT_ROOT/sites/default/default.settings.php $APACHE_DOCUMENT_ROOT/sites/default/settings.php 63 | cat <> $APACHE_DOCUMENT_ROOT/sites/default/settings.php 64 | \$databases['default']['default'] = array ( 65 | 'database' => '$DRUPAL_DATABASE_NAME', 66 | 'username' => '$DRUPAL_DATABASE_USERNAME', 67 | 'password' => '$DRUPAL_DATABASE_PASSWORD', 68 | 'prefix' => '$DRUPAL_DATABASE_PREFIX', 69 | 'host' => '$DRUPAL_DATABASE_HOST', 70 | 'port' => '$DRUPAL_DATABASE_PORT', 71 | 'namespace' => 'Drupal\\\\Core\\\\Database\\\\Driver\\\\mysql', 72 | 'driver' => 'mysql', 73 | ); 74 | \$config_directories['sync'] = '../config/sync'; 75 | \$settings['hash_salt'] = '$DRUPAL_HASH_SALT'; 76 | EOF 77 | 78 | echo "Correcting permissions on /var/www..." 79 | chown -R www-data:www-data /var/www 80 | 81 | if [ $DRUPAL_RUN_COMPOSER_INSTALL = true ] && [ "$DRUPAL_DOWNLOAD_METHOD" != 'composer' ]; then 82 | echo "Running composer install..." 83 | composer install 84 | fi 85 | 86 | echo "Drupal codebase ready!" 87 | fi 88 | 89 | exec "$@" 90 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Drupal Container (Built with Ansible) 2 | 3 | [![Build](https://github.com/geerlingguy/drupal-container/actions/workflows/build.yml/badge.svg)](https://github.com/geerlingguy/drupal-container/actions/workflows/build.yml) [![Docker pulls](https://img.shields.io/docker/pulls/geerlingguy/drupal)](https://hub.docker.com/r/geerlingguy/drupal/) 4 | 5 | This project is composed of three main parts: 6 | 7 | - **Ansible project**: This project is maintained on GitHub: [geerlingguy/drupal-container](https://github.com/geerlingguy/drupal-container). Please file issues, support requests, etc. against this GitHub repository. 8 | - **Docker Hub Image**: If you just want to use [the `geerlingguy/drupal` Docker image](https://hub.docker.com/r/geerlingguy/drupal/) 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.docker`](https://galaxy.ansible.com/geerlingguy/docker/) on Ansible Galaxy. (This is the Ansible role that does the bulk of the work in managing the Docker container.) 10 | 11 | ## Versions 12 | 13 | Currently maintained versions include: 14 | 15 | - `latest` 16 | - `latest-arm64` 17 | - `latest-arm32v7` 18 | 19 | ## Standalone Usage 20 | 21 | The easiest way to use this Docker image is to place the `docker-compose.yml` file included with this project in your Drupal site's root directory, then customize it to your liking, and run: 22 | 23 | docker compose up -d 24 | 25 | You should be able to access the Drupal site at `http://localhost/`, and if you're installing the first time, the Drupal installer UI should appear. Follow the directions and you'll end up with a brand new Drupal site! 26 | 27 | ### Automatic Drupal codebase generation 28 | 29 | The image downloads Drupal into `/var/www/html` if you don't have a Drupal codebase mounted into that path by default. 30 | 31 | You can override this behavior (if, for example, you are sharing your codebase into `/var/www/html/web` or elsewhere) by setting the environment variable `DRUPAL_DOWNLOAD_IF_NOT_PRESENT=false`. 32 | 33 | There are three methods you can use to generate a Drupal codebase if you don't have one mounted into this container (or `COPY`ed into the container via `Dockerfile`): 34 | 35 | - `DRUPAL_DOWNLOAD_METHOD=tarball` (default): Downloads the latest tarball version of Drupal core. 36 | - `DRUPAL_DOWNLOAD_METHOD=git`: Clones Drupal from the git source, with options: 37 | - `DRUPAL_CLONE_URL`: The URL from which Drupal is cloned. 38 | - `DRUPAL_CLONE_BRANCH`: The branch that is checked out. 39 | - `DRUPAL_DOWNLOAD_METHOD=composer`: Creates a new Drupal project using `composer create-project`. If using this method, you should also override the following variables: 40 | - `DRUPAL_PROJECT_ROOT=/var/www/html` 41 | - `APACHE_DOCUMENT_ROOT=/var/www/html/web` 42 | 43 | ### Drupal codebase 44 | 45 | To get your Drupal codebase into the container, you can either `COPY` it in using a Dockerfile, or mount a volume (e.g. when using the image for development). The included `docker-compose.yml` file assumes you have a Drupal codebase at the path `./web`, but you can customize the volume mount to point to wherever your Drupal docroot exists. 46 | 47 | If you don't supply a Drupal codebase in the container in `/var/www/html`, this container's `docker-entrypoint.sh` script will download Drupal for you (using the `DRUPAL_DOWNLOAD_VERSION`). By default the image uses the latest development release of Drupal, but you can override it and install a specific version by setting `DRUPAL_DOWNLOAD_VERSION` to that version number (e.g. `10.3.1`). 48 | 49 | ### Settings in `settings.php` 50 | 51 | Since it's best practice to _not_ include secrets like database credentials in your codebase, this Docker container recommends putting connection details into runtime environment variables, which you can include in your Drupal site's `settings.php` file via `getenv()`. 52 | 53 | For example, to set up the database connection, pass settings like `DRUPAL_DATABASE_NAME`: 54 | 55 | $databases['default']['default'] = [ 56 | 'driver' => 'mysql', 57 | 'database' => getenv('DRUPAL_DATABASE_NAME'), 58 | 'username' => getenv('DRUPAL_DATABASE_USERNAME'), 59 | 'password' => getenv('DRUPAL_DATABASE_PASSWORD'), 60 | 'prefix' => getenv('DRUPAL_DATABASE_PREFIX'), 61 | 'host' => getenv('DRUPAL_DATABASE_HOST'), 62 | 'port' => getenv('DRUPAL_DATABASE_PORT'), 63 | ]; 64 | 65 | You may also want to set a `DRUPAL_HASH_SALT` environment variable to drive the `$settings['hash_salt']` setting. 66 | 67 | ### Custom Apache document root 68 | 69 | The default Apache document root is `/var/www/html`. If your codebase needs to use a different docroot (e.g. `/var/www/html/web` for Composer-built Drupal projects), you should set the environment variable `APACHE_DOCUMENT_ROOT` to the appropriate directory, and the container will change the docroot when it starts up. 70 | 71 | ## Management with Ansible 72 | 73 | ### Prerequisites 74 | 75 | Before using this project to build and maintain Drupal images for Docker, you need to have the following installed: 76 | 77 | - [Docker Community Edition](https://docs.docker.com/engine/installation/) (for Mac, Windows, or Linux) 78 | - [Ansible](http://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html) 79 | 80 | ### Build the image 81 | 82 | Make sure Docker is running, and run the playbook to build the container image: 83 | 84 | ansible-playbook main.yml 85 | 86 | # Or just build one platform version (e.g. x86): 87 | ansible-playbook main.yml --extra-vars "{build_amd64: true, build_arm64: false, build_arm32: false}" 88 | 89 | Once the image is built, you can run `docker images` to see the `drupal` image that was generated. 90 | 91 | > Note: If you get an error like `Failed to import docker-py`, run `pip install docker-py`. 92 | 93 | If you want to quickly run the image and test that the `docker-entrypoint.sh` script works to grab a copy of the Drupal codebase, run it with: 94 | 95 | docker run -d -p 80:80 -v $PWD/web:/var/www/html:rw geerlingguy/drupal 96 | 97 | Then visit [http://localhost/](http://localhost/), and (after Drupal is downloaded and expanded) you should see the Drupal installer! You can drop the volume mount (`-v`) for a much faster startup, but then the codebase is downloaded and stored inside the container, and will vanish when you stop it. 98 | 99 | ### Push the image to Docker Hub 100 | 101 | Currently, the process for updating this image on Docker Hub is manual. Eventually this will be automated via Travis CI. 102 | 103 | 1. Log into Docker Hub on the command line: 104 | 105 | docker login --username=geerlingguy 106 | 107 | 1. Push to Docker Hub: 108 | 109 | docker push geerlingguy/drupal:latest 110 | docker push geerlingguy/drupal:latest-arm64 111 | docker push geerlingguy/drupal:latest-arm32v7 112 | 113 | ## License 114 | 115 | MIT / BSD 116 | 117 | ## Author Information 118 | 119 | This container build was created in 2018 by [Jeff Geerling](https://www.jeffgeerling.com/), author of [Ansible for DevOps](https://www.ansiblefordevops.com/). 120 | --------------------------------------------------------------------------------