├── .gitignore ├── scripts ├── helpers.sh ├── run.sh ├── plugins.sh ├── database.sh └── composer.sh ├── .dockerignore ├── php.ini ├── LICENSE ├── default.conf ├── Dockerfile ├── docker-compose.yml ├── run.sh └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | backups/ 2 | templates/ 3 | -------------------------------------------------------------------------------- /scripts/helpers.sh: -------------------------------------------------------------------------------- 1 | h2() { 2 | printf '\e[1;33m==>\e[37;1m %s\e[0m\n' "$*" 3 | } 4 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | Dockerfile* 2 | docker-compose* 3 | .dockerignore 4 | .git 5 | .gitignore 6 | README.md 7 | LICENSE 8 | default.conf 9 | -------------------------------------------------------------------------------- /php.ini: -------------------------------------------------------------------------------- 1 | date.timezone="Europe/Vienna" 2 | memory_limit=1024M 3 | max_execution_time=300 4 | upload_max_filesize=64M 5 | post_max_size=64M 6 | max_input_vars=2500 7 | -------------------------------------------------------------------------------- /scripts/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | source /scripts/helpers.sh 6 | source /scripts/database.sh 7 | source /scripts/composer.sh 8 | source /scripts/plugins.sh 9 | 10 | setup_database & 11 | SETUP_PID=$! 12 | update_dependencies & 13 | DEPENDENDIES_PID=$! 14 | 15 | wait $SETUP_PID 16 | wait $DEPENDENCIES_PID 17 | activate_plugins 18 | 19 | wait 20 | 21 | h2 "✅ Visit http://localhost or http:// to start using Craft CMS." 22 | 23 | # Start php-fpm 24 | exec "$@" 25 | -------------------------------------------------------------------------------- /scripts/plugins.sh: -------------------------------------------------------------------------------- 1 | activate_plugins() { 2 | h2 'Activating Plugins.' 3 | 4 | cd /var/www/html 5 | 6 | dependencies=$(cat composer.json | 7 | jq '.require' | 8 | jq --compact-output 'keys' | 9 | tr -d '[]"' | tr ',' '\n') 10 | 11 | for package in ${dependencies}; do 12 | 13 | vendor=$(awk -F '[\/:]+' '{print $1}' <<<$package) 14 | packageName=$(awk -F '[\/:]+' '{print $2}' <<<$package) 15 | isCraftPlugin=$(cat vendor/$vendor/$packageName/composer.json | jq '.type == "craft-plugin"') 16 | 17 | if [ "$isCraftPlugin" = true ]; then 18 | handle=$(cat vendor/$vendor/$packageName/composer.json | jq -r '.extra.handle') 19 | ./craft install/plugin $handle 20 | fi 21 | done 22 | } 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Harald Atteneder 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /default.conf: -------------------------------------------------------------------------------- 1 | # Nginx configuration 2 | 3 | server { 4 | listen 80 default_server; 5 | server_name localhost; 6 | 7 | index index.php index.html; 8 | error_log /var/log/nginx/error.log; 9 | access_log /var/log/nginx/access.log; 10 | root /var/www/html/web; 11 | charset utf-8; 12 | 13 | # Root directory location handler 14 | location / { 15 | try_files $uri/index.html $uri $uri/ /index.php?$query_string; 16 | } 17 | 18 | location ~ \.php$ { 19 | try_files $uri $uri/ /index.php?$query_string; 20 | fastcgi_split_path_info ^(.+\.php)(/.+)$; 21 | fastcgi_pass craft:9000; 22 | fastcgi_index index.php; 23 | include fastcgi_params; 24 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 25 | fastcgi_param PATH_INFO $fastcgi_path_info; 26 | } 27 | } 28 | 29 | # server { 30 | # server_name localhost; 31 | 32 | # listen 443 ssl; 33 | # fastcgi_param HTTPS on; 34 | 35 | # ssl_certificate /etc/ssl/server.pem; 36 | # ssl_certificate_key /etc/ssl/server.key; 37 | # ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2; 38 | 39 | # index index.php index.html; 40 | # error_log /var/log/nginx/error.log; 41 | # access_log /var/log/nginx/access.log; 42 | # root /var/www/html/web; 43 | 44 | # # Root directory location handler 45 | # location / { 46 | # try_files $uri/index.html $uri $uri/ /index.php?$query_string; 47 | # } 48 | 49 | # location ~ \.php$ { 50 | # try_files $uri =404; 51 | # fastcgi_split_path_info ^(.+\.php)(/.+)$; 52 | # fastcgi_pass craft:9000; 53 | # fastcgi_index index.php; 54 | # include fastcgi_params; 55 | # fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 56 | # fastcgi_param PATH_INFO $fastcgi_path_info; 57 | # } 58 | # } 59 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:7.2-fpm-alpine3.7 2 | 3 | LABEL maintainer="harald@urbantrout.io" 4 | 5 | ENV COMPOSER_NO_INTERACTION=1 6 | 7 | RUN set -ex \ 8 | && apk add --update --no-cache \ 9 | freetype \ 10 | libpng \ 11 | libjpeg-turbo \ 12 | freetype-dev \ 13 | libpng-dev \ 14 | libjpeg-turbo-dev \ 15 | libxml2-dev \ 16 | autoconf \ 17 | g++ \ 18 | imagemagick \ 19 | imagemagick-dev \ 20 | libtool \ 21 | make \ 22 | pcre-dev \ 23 | postgresql-dev \ 24 | postgresql \ 25 | libintl \ 26 | icu \ 27 | icu-dev \ 28 | bash \ 29 | jq \ 30 | git \ 31 | findutils \ 32 | gzip \ 33 | && docker-php-ext-configure gd \ 34 | --with-freetype-dir=/usr/include/ \ 35 | --with-png-dir=/usr/include/ \ 36 | --with-jpeg-dir=/usr/include/ \ 37 | && docker-php-ext-install bcmath mbstring iconv gd soap zip intl pdo_pgsql \ 38 | && pecl install imagick redis \ 39 | && docker-php-ext-enable imagick redis \ 40 | && rm -rf /tmp/pear \ 41 | && apk del freetype-dev libpng-dev libjpeg-turbo-dev autoconf g++ libtool make pcre-dev 42 | 43 | RUN apk add gnu-libiconv --update-cache --repository http://dl-cdn.alpinelinux.org/alpine/edge/community/ --allow-untrusted 44 | ENV LD_PRELOAD /usr/lib/preloadable_libiconv.so php 45 | 46 | COPY ./php.ini /usr/local/etc/php/ 47 | 48 | COPY --from=composer:latest /usr/bin/composer /usr/bin/composer 49 | 50 | COPY scripts/ /scripts/ 51 | RUN chown -R www-data:www-data /scripts \ 52 | && chmod -R +x /scripts 53 | 54 | WORKDIR /var/www/html 55 | RUN chown -R www-data:www-data . 56 | USER www-data 57 | 58 | # Install Craft CMS and save original dependencies in file 59 | RUN composer create-project craftcms/craft . \ 60 | && cp composer.json composer.base 61 | 62 | VOLUME [ "/var/www/html" ] 63 | 64 | ENTRYPOINT [ "/scripts/run.sh" ] 65 | 66 | CMD [ "docker-php-entrypoint", "php-fpm"] 67 | -------------------------------------------------------------------------------- /scripts/database.sh: -------------------------------------------------------------------------------- 1 | setup_database() { 2 | declare zip_file 3 | declare sql_file 4 | 5 | # Save DB credentials 6 | echo $DB_SERVER:$DB_PORT:$DB_DATABASE:$DB_USER:$DB_PASSWORD >~/.pgpass 7 | chmod 600 ~/.pgpass 8 | 9 | cd /var/www/html/storage 10 | 11 | # Find most recent zip file (mtime) 12 | zip_file=$(find backups -name "*.zip" -printf "%t %p\n" | sort -n | rev | cut -d' ' -f 1 | rev | tail -n1) 13 | 14 | if [[ "$zip_file" ]]; then 15 | h2 "Decompressing zip file: ${zip_file}" 16 | 17 | # Unzip file and force overwrite 18 | unzip -o $zip_file -d backups 19 | fi 20 | 21 | # Find most recent sql file (mtime) 22 | sql_file=$(find backups -name "*.sql" -printf "%t %p\n" | sort -n | rev | cut -d' ' -f 1 | rev | tail -n1) 23 | 24 | if [[ "$sql_file" ]]; then 25 | h2 "Database dump found: ${sql_file}" 26 | 27 | ignore_file="backups/.ignore" 28 | 29 | if [ -f $ignore_file ] && grep -q $sql_file $ignore_file; then 30 | h2 "Ignoring file because it is listed in $ignore_file" 31 | else 32 | while ! pg_isready -h $DB_SERVER; do 33 | h2 "Waiting for PostreSQL server" 34 | sleep 1 35 | done 36 | 37 | h2 "Importing database" 38 | cat "$sql_file" | psql -h $DB_SERVER -U $DB_USER && \ 39 | echo "$sql_file" >> $ignore_file 40 | fi 41 | 42 | if [[ "$zip_file" ]]; then 43 | h2 "Deleting decompressed SQL file." 44 | rm $sql_file 45 | fi 46 | else 47 | h2 "Setup Craft CMS" 48 | 49 | while ! pg_isready -h $DB_SERVER; do 50 | h2 "Waiting for PostreSQL server" 51 | sleep 1 52 | done 53 | 54 | cd /var/www/html && 55 | ./craft setup/security-key && 56 | ./craft install \ 57 | --interactive=0 \ 58 | --email="${CRAFTCMS_EMAIL}" \ 59 | --username="${CRAFTCMS_USERNAME:-admin}" \ 60 | --password="${CRAFTCMS_PASSWORD}" \ 61 | --siteName="${CRAFTCMS_SITENAME}" \ 62 | --siteUrl="${CRAFTCMS_SITEURL:-@web}" \ 63 | --language="${CRAFTCMS_LANGUAGE:-en-US}" 64 | fi 65 | } 66 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | # docker-compose.yml 2 | version: '2.1' 3 | 4 | services: 5 | nginx: 6 | image: nginx:alpine 7 | ports: 8 | - 80:80 9 | depends_on: 10 | - craft 11 | volumes_from: 12 | - craft 13 | volumes: 14 | - ./default.conf:/etc/nginx/conf.d/default.conf # nginx configuration (see below) 15 | - ./assets:/var/www/html/web/assets # For static assets (media, js and css). We don't need PHP for them. 16 | 17 | craft: 18 | image: urbantrout/craftcms:postgresql 19 | depends_on: 20 | - postgres 21 | volumes: 22 | - ./backups:/var/www/html/storage/backups 23 | - ./templates:/var/www/html/templates # Craft CMS template files 24 | environment: 25 | DEPENDENCIES: >- # additional composer packages (must be comma separated) 26 | yiisoft/yii2-redis, 27 | craftcms/redactor, 28 | 29 | CRAFTCMS_EMAIL: harald@urbantrout.io 30 | CRAFTCMS_USERNAME: admin 31 | CRAFTCMS_PASSWORD: super-secret-password 32 | CRAFTCMS_SITENAME: Craft CMS Installation 33 | CRAFTCMS_LANGUAGE: de-AT 34 | 35 | AUTO_UPDATE: 'false' 36 | 37 | REDIS_HOST: redis 38 | SESSION_DRIVER: redis 39 | CACHE_DRIVER: redis 40 | 41 | DB_DSN: pgsql:host=postgres;dbname=craft 42 | DB_SERVER: postgres 43 | DB_NAME: craft 44 | DB_USER: craft 45 | DB_PASSWORD: secret 46 | DB_DATABASE: craft 47 | DB_SCHEMA: public 48 | DB_DRIVER: pgsql 49 | DB_PORT: 5432 50 | DB_TABLE_PREFIX: ut 51 | 52 | postgres: 53 | image: postgres:9.6-alpine 54 | environment: 55 | POSTGRES_ROOT_PASSWORD: root 56 | POSTGRES_USER: craft 57 | POSTGRES_PASSWORD: secret 58 | POSTGRES_DB: craft 59 | volumes: 60 | # Persistent data 61 | - pgdata:/var/lib/postgresql/data 62 | 63 | redis: 64 | image: redis:4-alpine 65 | volumes: 66 | - redisdata:/data 67 | 68 | volumes: 69 | pgdata: 70 | redisdata: 71 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | declare DEPENDENCIES=(${DEPENDENCIES//,/ }) 6 | 7 | update_dependencies() { 8 | cd /var/www/html/ 9 | 10 | # Get base packages which are installed after 'composer create-project craftcms/craft'. 11 | base=$(cat composer.base | 12 | jq '.require' | 13 | jq --compact-output 'keys' | 14 | tr -d '[]"' | tr ',' '\n') 15 | 16 | # Get all currently installed packages including $base from above. 17 | current=$(cat composer.json | 18 | jq '.require' | 19 | jq --compact-output 'keys' | 20 | tr -d '[]"' | tr ',' '\n') 21 | 22 | # Exclude $base packages from $current packages. 23 | additional=($(comm -13 <(printf '%s\n' "${base[@]}" | LC_ALL=C sort) <(printf '%s\n' "${current[@]}" | LC_ALL=C sort))) 24 | 25 | # Get packages from $DEPENDENCIES env var which are not yet installed. 26 | require=($(comm -13 <(printf '%s\n' "${additional[@]}" | LC_ALL=C sort) <(printf '%s\n' "${DEPENDENCIES[@]}" | LC_ALL=C sort))) 27 | 28 | # Get packages which are installed but not listeed in $DEPENDENCIES var and therefore remove them in the next step. 29 | removable=($(comm -13 <(printf '%s\n' "${DEPENDENCIES[@]}" | LC_ALL=C sort) <(printf '%s\n' "${additional[@]}" | LC_ALL=C sort))) 30 | 31 | if [ ${#removable[*]} -gt 0 ]; then 32 | printf '\e[1;33m==>\e[37;1m %s\e[0m\n' "Remove packages" 33 | echo ${removable[*]} 34 | composer remove ${removable[*]} 35 | fi 36 | 37 | if [ ${#require[*]} -gt 0 ]; then 38 | printf '\e[1;33m==>\e[37;1m %s\e[0m\n' "Install packages" 39 | echo ${require[*]} 40 | composer require ${require[*]} 41 | fi 42 | } 43 | 44 | import_database() { 45 | declare dump_zip 46 | declare dump_sql 47 | 48 | cd /var/www/html/storage/backups 49 | 50 | dump_zip=$(find . -name '*.zip' -print) 51 | 52 | if [[ "$dump_zip" ]]; then 53 | printf '\e[1;33m==>\e[37;1m %s\e[0m\n' "Database dump found (zip file)" 54 | 55 | if grep -q $dump_zip .ignore; then 56 | printf '\e[1;33m==>\e[37;1m %s\e[0m\n' "Ignoring file because it is listed in .ignore" 57 | else 58 | while ! mysqladmin ping -h $DB_SERVER -u $DB_USER --password=$DB_PASSWORD --silent >/dev/null; do 59 | printf '\e[1;33m==>\e[37;1m %s\e[0m\n' "Waiting for MySQL server" 60 | sleep 1 61 | done 62 | 63 | zcat "$dump_zip" | mysql -h $DB_SERVER -u $DB_USER --password=$DB_PASSWORD $DB_DATABSE && echo "$dump_zip" >>.ignore 64 | fi 65 | fi 66 | 67 | dump_sql=$(find . -name '*.sql' -print) 68 | 69 | if [[ "$dump_sql" ]]; then 70 | printf '\e[1;33m==>\e[37;1m %s\e[0m\n' "Database dump found (sql file)" 71 | 72 | if grep -q $dump_sql .ignore; then 73 | printf '\e[1;33m==>\e[37;1m %s\e[0m\n' "Ignoring file because it is listed in .ignore" 74 | else 75 | while ! mysqladmin ping -h $DB_SERVER -u $DB_USER --password=$DB_PASSWORD --silent >/dev/null; do 76 | printf '\e[1;33m==>\e[37;1m %s\e[0m\n' "Waiting for MySQL server" 77 | sleep 1 78 | done 79 | 80 | cat "$dump_sql" | mysql -h $DB_SERVER -u $DB_USER --password=$DB_PASSWORD $DB_DATABASE && echo "$dump_sql" >>.ignore 81 | fi 82 | fi 83 | } 84 | 85 | update_dependencies & 86 | 87 | import_database & 88 | 89 | # Start php-fpm 90 | exec "$@" 91 | -------------------------------------------------------------------------------- /scripts/composer.sh: -------------------------------------------------------------------------------- 1 | declare DEPENDENCIES=(${DEPENDENCIES//,/ }) 2 | declare AUTO_UPDATE=${AUTO_UPDATE:-true} 3 | 4 | update_dependencies() { 5 | cd /var/www/html/ 6 | 7 | # Get base packages which are installed after 'composer create-project craftcms/craft'. 8 | base=$(cat composer.base | 9 | jq '.require' | 10 | jq --compact-output 'keys' | 11 | tr -d '[]"' | tr ',' '\n') 12 | 13 | # Get all currently installed packages including $base from above. 14 | current=$(cat composer.json | 15 | jq '.require' | 16 | jq --compact-output 'keys' | 17 | tr -d '[]"' | tr ',' '\n') 18 | 19 | # Exclude $base packages from $current packages. 20 | additional=($(comm -13 <(printf '%s\n' "${base[@]}" | LC_ALL=C sort) <(printf '%s\n' "${current[@]}" | LC_ALL=C sort))) 21 | 22 | # Get packages from $DEPENDENCIES env var which are not yet installed. 23 | require=($(comm -13 <(printf '%s\n' "${additional[@]}" | LC_ALL=C sort) <(printf '%s\n' "${DEPENDENCIES[@]}" | LC_ALL=C sort))) 24 | 25 | # Get packages which are installed but not listeed in $DEPENDENCIES var and therefore remove them in the next step. 26 | removable=($(comm -13 <(printf '%s\n' "${DEPENDENCIES[@]}" | LC_ALL=C sort) <(printf '%s\n' "${additional[@]}" | LC_ALL=C sort))) 27 | 28 | if [ ${#removable[*]} -gt 0 ]; then 29 | h2 "Remove packages." 30 | echo ${removable[*]} 31 | composer remove ${removable[*]} 32 | fi 33 | 34 | # Regex pattern to match VCS dependencies (Git repos) 35 | # external dependencies have to look like this pattern 36 | # - [vendor/package-name:branch-name]https://url-to-the-git-repo.git 37 | # - [vendor/package-name:version]/path/to/volume 38 | # If dependency is not registerd by composer 39 | regexHttp="(\[(.*?):(.*?)\])([http].*)" 40 | regexLocal="(\[(.*?):(.*?)\])([^http].*)" 41 | 42 | h2 'Start installing dependencies.' 43 | 44 | for package in ${require[@]}; do 45 | 46 | if [[ $package =~ $regexHttp ]]; then 47 | name="${BASH_REMATCH[2]}" 48 | version="${BASH_REMATCH[3]}" 49 | url="${BASH_REMATCH[4]}" 50 | printf "Install \e[0;32mvcs composer package\e[0m: \e[0;36m${name} ${version}\e[0m\n" 51 | composer config repositories.${name} '{"type": "vcs", "url": "'${url}'", "no-api": true }' 52 | composer require --update-with-dependencies ${name}:${version} 53 | elif [[ $package =~ $regexLocal ]]; then 54 | name="${BASH_REMATCH[2]}" 55 | version="${BASH_REMATCH[3]}" 56 | url="${BASH_REMATCH[4]}" 57 | printf "Install \e[0;32mlocalcomposer package\e[0m: \e[0;36m${name} ${version}\e[0m\n" 58 | composer config repositories.${name} '{"type": "path", "url": "'${url}'", "options": {"symlink": true}}' 59 | composer require --update-with-dependencies ${name}:${version} 60 | else 61 | printf "Install \e[0;32mcomposer package\e[0m: \e[0;36m${package}\e[0m\n" 62 | composer require --update-with-dependencies ${package} 63 | fi 64 | 65 | done 66 | 67 | if $AUTO_UPDATE; then 68 | h2 'Updating outdated dependencies.' 69 | composer update 70 | else 71 | h2 'Skipping updates.' 72 | fi 73 | 74 | h2 '✅ All dependencies successfully installed.' 75 | } 76 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Craft CMS Docker Image 2 | 3 | Lightweight Craft CMS 3 Image 4 | 5 | Comes with Craft CMS 3 and support for PostgreSQL (`urbantrout/craftcms:postgresql`) or MySQL (`urbantrout/craftcms:mysql`). 6 | 7 | Bring your own webserver and database. 8 | 9 | ## Features 10 | 11 | - [Plugins and other dependencies](#plugins) 12 | Automatically requires and removes additional plugins via DEPENDENCIES environment variable 13 | - [Import SQL files](#import-database) 14 | Automatically restores database backups located under ./backups (See volumes in docker-compose.yml below). To create a database backup use the built-in backup tool within the Craft CMS Control Panel. 15 | - Completely non-interactive installation of Craft CMS and plugins 16 | - [redis](#redis) 17 | - imagemagick 18 | - If you want to use PostgreSQL use the `urbantrout/craftcms:postgresql` image 19 | - If you want to use MySQL use the `urbantrout/craftcms:mysql` image 20 | 21 | ## Getting started 22 | 23 | You only need two files: 24 | 25 | - docker-compose.yml 26 | - default.conf 27 | 28 | Add `backups/.ignore` to your .gitignore file. This file is used for automatic db restores. Files listed in `backups/.ignore` do not get imported on start up. 29 | 30 | ### docker-compose 31 | 32 | #### PostgreSQL Example 33 | 34 | ```yml 35 | # docker-compose.yml 36 | version: '2.1' 37 | 38 | services: 39 | nginx: 40 | image: nginx:alpine 41 | ports: 42 | - 80:80 43 | depends_on: 44 | - craft 45 | volumes_from: 46 | - craft 47 | volumes: 48 | - ./default.conf:/etc/nginx/conf.d/default.conf # nginx configuration (see below) 49 | - ./assets:/var/www/html/web/assets # For static assets (media, js and css). 50 | 51 | craft: 52 | image: urbantrout/craftcms:postgresql 53 | depends_on: 54 | - postgres 55 | volumes: 56 | - ./assets:/var/www/html/web/assets:z 57 | - ./backups:/var/www/html/storage/backups # Used for db restore on start. 58 | - ./templates:/var/www/html/templates # Craft CMS template files 59 | - ./translations:/var/www/html/translations 60 | - ./redactor:/var/www/html/config/redactor 61 | environment: 62 | DEPENDENCIES: >- # additional composer packages 63 | yiisoft/yii2-redis 64 | craftcms/redactor:2.0.1 65 | 66 | CRAFTCMS_EMAIL: admin@company.com 67 | CRAFTCMS_USERNAME: admin 68 | CRAFTCMS_PASSWORD: super-secret-password 69 | CRAFTCMS_SITENAME: Craft CMS Installation 70 | CRAFTCMS_SITEURL: http://dev.project.com # Optional 71 | CRAFTCMS_LANGUAGE: de-AT # Optional 72 | 73 | AUTO_UPDATE: 'false' # Enable/disable auto updates for all composer packages (including Craft CMS, Default: true) 74 | 75 | REDIS_HOST: redis 76 | SESSION_DRIVER: redis 77 | CACHE_DRIVER: redis 78 | 79 | DB_DSN: pgsql:host=postgres;dbname=craft 80 | DB_SERVER: postgres 81 | DB_NAME: craft 82 | DB_USER: craft 83 | DB_PASSWORD: secret 84 | DB_DATABASE: craft 85 | DB_SCHEMA: public 86 | DB_DRIVER: pgsql 87 | DB_PORT: 5432 88 | DB_TABLE_PREFIX: ut 89 | 90 | postgres: 91 | image: postgres:10.3-alpine 92 | environment: 93 | POSTGRES_ROOT_PASSWORD: root 94 | POSTGRES_USER: craft 95 | POSTGRES_PASSWORD: secret 96 | POSTGRES_DB: craft 97 | volumes: 98 | # Persistent data 99 | - pgdata:/var/lib/postgresql/data 100 | 101 | redis: 102 | image: redis:4-alpine 103 | volumes: 104 | - redisdata:/data 105 | 106 | volumes: 107 | pgdata: 108 | redisdata: 109 | ``` 110 | 111 | #### MySQL Database Example 112 | 113 | ```yml 114 | # docker-compose.yml 115 | version: '2.1' 116 | 117 | services: 118 | nginx: 119 | image: nginx:alpine 120 | ports: 121 | - 80:80 122 | depends_on: 123 | - craft 124 | volumes_from: 125 | - craft 126 | volumes: 127 | - ./default.conf:/etc/nginx/conf.d/default.conf # nginx configuration (see below) 128 | - ./assets:/var/www/html/web/assets # For static assets (media, js and css). 129 | 130 | craft: 131 | image: urbantrout/craftcms:mysql # Use mysql instead of postgresql 132 | depends_on: 133 | - mariadb 134 | volumes: 135 | - ./assets:/var/www/html/web/assets:z 136 | - ./backups:/var/www/html/storage/backups # Used for db restore on start. 137 | - ./templates:/var/www/html/templates # Craft CMS template files 138 | - ./translations:/var/www/html/translations 139 | - ./redactor:/var/www/html/config/redactor 140 | environment: 141 | DEPENDENCIES: >- # additional composer packages 142 | yiisoft/yii2-redis 143 | craftcms/redactor:2.0.1 144 | 145 | CRAFTCMS_EMAIL: admin@company.com 146 | CRAFTCMS_USERNAME: admin 147 | CRAFTCMS_PASSWORD: super-secret-password 148 | CRAFTCMS_SITENAME: Craft CMS Installation 149 | CRAFTCMS_SITEURL: http://dev.project.com # Optional 150 | 151 | AUTO_UPDATE: 'false' # Enable/disable auto updates for all composer packages (including Craft CMS, Default: true) 152 | 153 | REDIS_HOST: redis 154 | SESSION_DRIVER: redis 155 | CACHE_DRIVER: redis 156 | 157 | DB_DSN: mysql:host=mariadb;dbname=craft 158 | DB_SERVER: mariadb 159 | DB_NAME: craft 160 | DB_USER: craft 161 | DB_PASSWORD: secret 162 | DB_DATABASE: craft 163 | DB_SCHEMA: public 164 | DB_DRIVER: mysql 165 | DB_PORT: 3306 166 | DB_TABLE_PREFIX: ut 167 | 168 | mariadb: 169 | image: mariadb:10.1 170 | environment: 171 | MYSQL_ROOT_PASSWORD: root 172 | MYSQL_USER: craft 173 | MYSQL_PASSWORD: secret 174 | MYSQL_DATABASE: craft 175 | volumes: 176 | # Persistent data 177 | - dbdata:/var/lib/mysql 178 | 179 | redis: 180 | image: redis:4-alpine 181 | volumes: 182 | - redisdata:/data 183 | 184 | volumes: 185 | dbdata: 186 | redisdata: 187 | ``` 188 | 189 | ### nginx configuration 190 | 191 | Create a file called **default.conf** in to your project directory: 192 | 193 | ```nginx 194 | # default.conf 195 | 196 | server { 197 | listen 80 default_server; 198 | listen [::]:80 default_server; 199 | server_name localhost; 200 | 201 | index index.php index.html; 202 | error_log /var/log/nginx/error.log; 203 | access_log /var/log/nginx/access.log; 204 | root /var/www/html/web; 205 | charset utf-8; 206 | 207 | # Root directory location handler 208 | location / { 209 | try_files $uri/index.html $uri $uri/ /index.php?$query_string; 210 | } 211 | 212 | location ~ \.php$ { 213 | try_files $uri $uri/ /index.php?$query_string; 214 | fastcgi_split_path_info ^(.+\.php)(/.+)$; 215 | fastcgi_pass craft:9000; 216 | fastcgi_index index.php; 217 | include fastcgi_params; 218 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 219 | fastcgi_param PATH_INFO $fastcgi_path_info; 220 | } 221 | } 222 | ``` 223 | 224 | ## Plugins 225 | 226 | Add your plugins to the environment variable DEPENDENCIES. A script then automatically adds or removes those dependencies when you create the container. 227 | 228 | In a docker-compose file: 229 | 230 | ```yaml 231 | volumes: 232 | - ./path/to/plugin:/plugins/plugin # If you want to use a local plugin with composer 233 | 234 | environment: 235 | DEPENDENCIES: >- # additional composer packages 236 | craftcms/redactor:2.0.1 237 | [vendor/package-name:branch-name]https://url-to-the-git-repo.git # branch-name needs to be prefixed with 'dev-'. (e.g. dev-development for branch development) 238 | [vendor/package-name:version]/path/to/volume # Version as 1.0.0 239 | ``` 240 | 241 | You can add plugins from a public Git Repo, or from a local folder on your machine as Well. 242 | For local Plugins take care that you added a volume so that docker can use the plugin. 243 | 244 | If you change your dependencies, run `docker-compose down && docker-compose up` to remove and recreate your container. 245 | 246 | ## Import database 247 | 248 | Create another volume which gets mounted to /var/www/html/storage/backups 249 | 250 | ``` 251 | volumes: 252 | - ./backups:/var/www/html/storage/backups 253 | ``` 254 | 255 | When you create a db dump from within your Craft CMS CP, a sql file gets automatically saved in this folder and you can add it to your git repository. 256 | 257 | On startup the docker image looks for sql or zip files in this folder and imports them, unless its filename is listed in a special file called `.ignore`. This prevents importing the same file twice. 258 | 259 | After successfully importing the db dump, this file gets added to `.ignore`, so you don't have to worry about that. 260 | 261 | ## Redis 262 | 263 | Create `config/app.php` and add the following lines: 264 | 265 | ```php 266 | return [ 267 | 'components' => [ 268 | 'cache' => [ 269 | 'class' => yii\redis\Cache::class, 270 | 'defaultDuration' => 86400, 271 | 'redis' => [ 272 | 'hostname' => getenv('REDIS_HOST'), 273 | 'port' => 6379, 274 | 'database' => 1, 275 | ], 276 | ], 277 | ], 278 | ]; 279 | ``` 280 | 281 | Add `yiisoft/yii2-redis` to your DEPENDENCIES env variable and create another volume for your redis configuration 282 | 283 | ```yaml 284 | volumes: 285 | - ./config/app.php:/var/www/html/config/app.php 286 | ``` 287 | 288 | Add a redis service to your docker-compose.yml 289 | 290 | ```yaml 291 | redis: 292 | image: redis:4-alpine 293 | volumes: 294 | - redisdata:/data 295 | ``` 296 | 297 | ## Finish setup 298 | 299 | Run `docker-compose up` and visit http://localhost/admin. Voilà! 300 | 301 | ## Known Issues 302 | 303 | - Docker volumes and file system permissions 304 | See https://medium.com/@nielssj/docker-volumes-and-file-system-permissions-772c1aee23ca 305 | --------------------------------------------------------------------------------