From 2a523ef76ce9b88b8514f1363b7539c50b74f536 Mon Sep 17 00:00:00 2001 From: Steve Ross Date: Wed, 3 Sep 2025 19:29:55 +0100 Subject: [PATCH] add docker local dev stuff --- .gitignore | 2 + docker-compose.yml | 63 ++++++ docker/.gitignore | 4 + docker/Dockerfile | 21 ++ docker/README.md | 351 +++++++++++++++++++++++++++++++++ docker/certs/.gitkeep | 0 docker/cli/create-cert.sh | 13 ++ docker/config/php.ini | 6 + docker/config/phpmyadmin.ini | 2 + docker/data/.gitkeep | 0 docker/nginx/default.conf.conf | 79 ++++++++ 11 files changed, 541 insertions(+) create mode 100644 docker-compose.yml create mode 100644 docker/.gitignore create mode 100644 docker/Dockerfile create mode 100644 docker/README.md create mode 100644 docker/certs/.gitkeep create mode 100755 docker/cli/create-cert.sh create mode 100644 docker/config/php.ini create mode 100644 docker/config/phpmyadmin.ini create mode 100644 docker/data/.gitkeep create mode 100644 docker/nginx/default.conf.conf diff --git a/.gitignore b/.gitignore index c309ecc..eff5bdc 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,5 @@ auth.json # WP-CLI wp-cli.local.yml + +.DS_Store diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..c162d5b --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,63 @@ +services: + nginx: + image: nginx:latest + container_name: ${APP_NAME}-nginx + ports: + - '80:80' + - '443:443' + volumes: + - "./docker/nginx/:/etc/nginx/templates/" + - ./:/var/www/html:rw,cached + - ./docker/certs:/etc/certs + environment: + - "NGINX_ENVSUBST_TEMPLATE_SUFFIX=.conf" + - "DOMAIN=${DOMAIN}" + depends_on: + - wordpress + restart: always + + mysql: + image: mariadb:10.7 + container_name: ${APP_NAME}-mysql + command: --lower_case_table_names=2 + volumes: + - './docker/data/db:/var/lib/mysql:delegated' + environment: + - MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD} + - MYSQL_DATABASE=${DB_NAME} + restart: always + ports: + - '3306:3306' + + wordpress: + build: + context: . + dockerfile: ./docker/Dockerfile + container_name: ${APP_NAME}-wordpress + volumes: + - ./:/var/www/html:rw,cached + - ./docker/config/php.ini:/usr/local/etc/php/conf.d/php.ini + depends_on: + - mysql + restart: always + + phpmyadmin: + image: arm64v8/phpmyadmin + container_name: ${APP_NAME}-phpmyadmin + volumes: + - ./docker/config/phpmyadmin.ini:/usr/local/etc/php/conf.d/phpmyadmin.ini + environment: + PMA_HOST: "${DB_HOST}" + PMA_PORT: 3306 + MYSQL_ROOT_PASSWORD: "${DB_ROOT_PASSWORD}" + ports: + - '8082:80' + links: + - mysql:mysql + + mailpit: + container_name: ${APP_NAME}-mailpit + image: axllent/mailpit + ports: + - "8025:8025" + - "1025:1025" diff --git a/docker/.gitignore b/docker/.gitignore new file mode 100644 index 0000000..b5795a7 --- /dev/null +++ b/docker/.gitignore @@ -0,0 +1,4 @@ +certs/* +!certs/.gitkeep +data/* +!data/.gitkeep diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..a17c87b --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,21 @@ +FROM urre/wordpress-nginx-docker-compose-image:1.4.0 + +# PHP Extensions +RUN docker-php-ext-configure calendar && docker-php-ext-install calendar + +# Install wp-cli +RUN apt-get update && apt-get install -y sudo less mariadb-client +RUN curl -o /bin/wp-cli.phar https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar +RUN chmod +x /bin/wp-cli.phar +RUN cd /bin && mv wp-cli.phar wp +RUN mkdir -p /var/www/.wp-cli/cache && chown www-data:www-data /var/www/.wp-cli/cache + +# Install composer +COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer + +# Forward Message to mailhog +RUN curl --location --output /usr/local/bin/mhsendmail https://github.com/mailhog/mhsendmail/releases/download/v0.2.0/mhsendmail_linux_amd64 && \ + chmod +x /usr/local/bin/mhsendmail +RUN echo 'sendmail_path="/usr/local/bin/mhsendmail --smtp-addr=mailhog:1025 --from=no-reply@gbp.lo"' > /usr/local/etc/php/conf.d/mailhog.ini + +# Note: Use docker-compose up -d --force-recreate --build when Dockerfile has changed. diff --git a/docker/README.md b/docker/README.md new file mode 100644 index 0000000..2272a0c --- /dev/null +++ b/docker/README.md @@ -0,0 +1,351 @@ + +# Docker Compose and WordPress + +![](https://github.com/urre/wordpress-nginx-docker-compose/actions/workflows/ci.yml/badge.svg) + +[![Donate](https://img.shields.io/badge/Donation-green?logo=paypal&label=Paypal)](https://www.paypal.me/urbansanden) + +Use WordPress locally with Docker using [Docker compose](https://docs.docker.com/compose/) + +## Contents + ++ A `Dockerfile` for extending a base image and using a custom [Docker image](https://github.com/urre/wordpress-nginx-docker-compose-image) with an [automated build on Docker Hub](https://cloud.docker.com/repository/docker/urre/wordpress-nginx-docker-compose-image) ++ PHP 8.1 ++ Custom domain and HTTPS support. So you can use for example [https://myapp.local](https://myapp.local) ++ Custom nginx config in `./nginx` ++ Custom PHP `php.ini` config in `./config` ++ Volumes for `nginx`, `wordpress` and `mariadb` ++ [Bedrock](https://roots.io/bedrock/) - modern development tools, easier configuration, and an improved secured folder structure for WordPress ++ Composer ++ [WP-CLI](https://wp-cli.org/) - WP-CLI is the command-line interface for WordPress. ++ [MailHog](https://github.com/mailhog/MailHog) - An email testing tool for developers. Configure your outgoing SMTP server and view your outgoing email in a web UI. ++ [PhpMyAdmin](https://www.phpmyadmin.net/) - free and open source administration tool for MySQL and MariaDB + - PhpMyAdmin config in `./config` ++ CLI script to create a SSL certificate + +## Instructions + +
+ Requirements + ++ [Docker](https://www.docker.com/get-started) ++ [mkcert](https://github.com/FiloSottile/mkcert) for creating the SSL cert. + +Install mkcert: + +``` +brew install mkcert +brew install nss # if you use Firefox +``` + +
+ +
+ Setup + + ### Setup Environment variables + +Both step 1. and 2. below are required: + +#### 1. For Docker and the CLI script (Required step) + +Copy `.env.example` in the project root to `.env` and edit your preferences. + +Example: + +```dotenv +IP=127.0.0.1 +APP_NAME=myapp +DOMAIN="myapp.local" +DB_HOST=mysql +DB_NAME=myapp +DB_ROOT_PASSWORD=password +DB_TABLE_PREFIX=wp_ +``` + +#### 2. For WordPress (Required step) + +Edit `./src/.env.example` to your needs. During the `composer create-project` command described below, an `./src/.env` will be created. + +Example: + +```dotenv +DB_NAME='myapp' +DB_USER='root' +DB_PASSWORD='password' + +# Optionally, you can use a data source name (DSN) +# When using a DSN, you can remove the DB_NAME, DB_USER, DB_PASSWORD, and DB_HOST variables +# DATABASE_URL='mysql://database_user:database_password@database_host:database_port/database_name' + +# Optional variables +DB_HOST='mysql' +# DB_PREFIX='wp_' + +WP_ENV='development' +WP_HOME='https://myapp.local' +WP_SITEURL="${WP_HOME}/wp" +WP_DEBUG_LOG=/path/to/debug.log + +# Generate your keys here: https://roots.io/salts.html +AUTH_KEY='generateme' +SECURE_AUTH_KEY='generateme' +LOGGED_IN_KEY='generateme' +NONCE_KEY='generateme' +AUTH_SALT='generateme' +SECURE_AUTH_SALT='generateme' +LOGGED_IN_SALT='generateme' +NONCE_SALT='generateme' +``` + +
+ +
+ Option 1). Use HTTPS with a custom domain + +1. Create a SSL cert: + +```shell +cd cli +./create-cert.sh +``` + +This script will create a locally-trusted development certificates. It requires no configuration. + +> mkcert needs to be installed like described in Requirements. Read more for [Windows](https://github.com/FiloSottile/mkcert#windows) and [Linux](https://github.com/FiloSottile/mkcert#linux) + +1b. Make sure your `/etc/hosts` file has a record for used domains. On Windows the hosts file can be find at `C:\Windows\System32\drivers\etc`. Make sure to open it with admin rights. + +``` +sudo nano /etc/hosts +``` + +Add your selected domain like this: + +``` +127.0.0.1 myapp.local +``` + +2. Continue on the Install step below + +
+ +
+ Option 2). Use a simple config + +1. Edit `nginx/default.conf.conf` to use this simpler config (without using a cert and HTTPS) + +```shell +server { + listen 80; + + root /var/www/html/web; + index index.php; + + access_log /var/log/nginx/access.log; + error_log /var/log/nginx/error.log; + + client_max_body_size 100M; + + location / { + try_files $uri $uri/ /index.php?$args; + } + + location ~ \.php$ { + try_files $uri =404; + fastcgi_split_path_info ^(.+\.php)(/.+)$; + fastcgi_pass wordpress:9000; + fastcgi_index index.php; + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_param PATH_INFO $fastcgi_path_info; + } +} + +``` + +2. Edit the nginx service in `docker-compose.yml` to use port 80. 443 is not needed now. + +```shell + nginx: + image: nginx:latest + container_name: ${APP_NAME}-nginx + ports: + - '80:80' + +``` + +3. Continue on the Install step below + +
+ +
+ Install + +```shell +docker-compose run composer create-project +``` + +
+ +
+ Run + +```shell +docker-compose up +``` + +Docker Compose will now start all the services for you: + +```shell +Starting myapp-mysql ... done +Starting myapp-composer ... done +Starting myapp-phpmyadmin ... done +Starting myapp-wordpress ... done +Starting myapp-nginx ... done +Starting myapp-mailhog ... done +``` + +🚀 Open [https://myapp.local](https://myapp.local) in your browser + +## PhpMyAdmin + +PhpMyAdmin comes installed as a service in docker-compose. + +🚀 Open [http://127.0.0.1:8082/](http://127.0.0.1:8082/) in your browser + +## MailHog + +MailHog comes installed as a service in docker-compose. + +🚀 Open [http://0.0.0.0:8025/](http://0.0.0.0:8025/) in your browser + +
+ +
+ Tools + +### Update WordPress Core and Composer packages (plugins/themes) + +```shell +docker-compose run composer update +``` + +#### Use WP-CLI + +```shell +docker exec -it myapp-wordpress bash +``` + +Login to the container + +```shell +wp search-replace https://olddomain.com https://newdomain.com --allow-root +``` + +Run a wp-cli command + +> You can use this command first after you've installed WordPress using Composer as the example above. + +### Update plugins and themes from wp-admin? + +You can, but I recommend to use Composer for this only. But to enable this edit `./src/config/environments/development.php` (for example to use it in Dev) + +```shell +Config::define('DISALLOW_FILE_EDIT', false); +Config::define('DISALLOW_FILE_MODS', false); +``` + +### Useful Docker Commands + +When making changes to the Dockerfile, use: + +```bash +docker-compose up -d --force-recreate --build +``` + +Login to the docker container + +```shell +docker exec -it myapp-wordpress bash +``` + +Stop + +```shell +docker-compose stop +``` + +Down (stop and remove) + +```shell +docker-compose down +``` + +Cleanup + +```shell +docker-compose rm -v +``` + +Recreate + +```shell +docker-compose up -d --force-recreate +``` + +Rebuild docker container when Dockerfile has changed + +```shell +docker-compose up -d --force-recreate --build +``` +
+ +
+ Changelog + +#### 2022-05-28 +- Use PHP 8.1 [Dockerfile](https://github.com/urre/wordpress-nginx-docker-compose-image/blob/master/Dockerfile) is updated. +#### 2022-05-28 +- Use php:8.0-fpm-alpine as the base image on the image in Dockerfile [](https://hub.docker.com/repository/registry-1.docker.io/urre/wordpress-nginx-docker-compose-image/general) +#### 2022-05-28 +- Updated the Docker image to use PHP 8 +#### 2021-08-04 +- Updated to WordPress 5.8.0 +#### 2021-03-16 +- Changed root `.env-example` to `.env.example` to match the git ignore patterns. Thanks [@scottnunemacher](https://github.com/scottnunemacher) +#### 2021-03-05 +- Clarify steps in the readme +#### 2021-03-02 +- Fixed a misstake so instead of `./src/.env-example`, it should be `./src/.env.example`. +- Redirect HTTP to HTTPS. Thanks [@humblecoder](https://github.com/humblecoder) +#### 2021-01-02 +- Use `NGINX_ENVSUBST_TEMPLATE_SUFFIX`. Use a template and better substution of ENV variables in nginx config. +#### 2020-10-04 +- Added mariadb-client (Solves [#54](https://github.com/urre/wordpress-nginx-docker-compose/issues/54)) +#### 2020-09-15 +- Updated Bedrock. Update WordPress to 5.5.1 and other composer updates. +#### 2020-07-12 +- Added Mailhog. Thanks [@mortensassi](https://github.com/mortensassi) +#### 2020-05-03 +- Added nginx gzip compression +#### 2020-04-19 +- Added Windows support for creating SSH cert, trusting it and setting up the host file entry. Thanks to [@styssi](https://github.com/styssi) +#### 2020-04-12 +- Remove port number from `DB_HOST`. Generated database connection error in macOS Catalina. Thanks to [@nirvanadev](https://github.com/nirvanadev) +- Add missing ENV variable from mariadb Thanks to [@vonwa](https://github.com/vonwa) +#### 2020-03-26 +- Added phpMyAdmin config.Thanks to [@titoffanton](https://github.com/titoffanton) +#### 2020-02-06 +- Readme improvements. Explain `/etc/hosts` better +#### 2020-01-30 +- Use `Entrypoint` command in Docker Compose to replace the domain name in the nginx config. Removing the need to manually edit the domain name in the nginx conf. Now using the `.env` value `DOMAIN` +- Added APP_NAME in `.env-example` Thanks to [@Dave3o3](https://github.com/Dave3o3) +#### 2020-01-11 +- Added `.env` support for specifying your own app name, domain etc in Docker and cli scripts. +- Added phpMyAdmin. Visit [http://127.0.0.1:8080/](http://127.0.0.1:8080/) + +#### 2019-08-02 +- Added Linux support. Thanks to [@faysal-ishtiaq](https://github.com/faysal-ishtiaq). + +
diff --git a/docker/certs/.gitkeep b/docker/certs/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/docker/cli/create-cert.sh b/docker/cli/create-cert.sh new file mode 100755 index 0000000..9465a6a --- /dev/null +++ b/docker/cli/create-cert.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +set -e + +source "../../.env" + +DOMAIN=$(echo "$DOMAIN") + +mkcert -install "${DOMAIN}" + +mkdir -p ../certs + +find . -type f -name "*.pem" -exec mv {} ../certs \; diff --git a/docker/config/php.ini b/docker/config/php.ini new file mode 100644 index 0000000..fc202ab --- /dev/null +++ b/docker/config/php.ini @@ -0,0 +1,6 @@ +file_uploads = On +memory_limit = 512M +upload_max_filesize = 128M +post_max_size = 128M +max_execution_time = 600 +client_max_body_size = 128M diff --git a/docker/config/phpmyadmin.ini b/docker/config/phpmyadmin.ini new file mode 100644 index 0000000..b75c290 --- /dev/null +++ b/docker/config/phpmyadmin.ini @@ -0,0 +1,2 @@ +upload_max_filesize = 128M +post_max_size = 128M diff --git a/docker/data/.gitkeep b/docker/data/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/docker/nginx/default.conf.conf b/docker/nginx/default.conf.conf new file mode 100644 index 0000000..6de979a --- /dev/null +++ b/docker/nginx/default.conf.conf @@ -0,0 +1,79 @@ +server { + listen 80; + server_name ${DOMAIN}; + return 301 https://$host$request_uri; +} + +server { + listen 443 ssl http2; + server_name ${DOMAIN} www.${DOMAIN}; + + ssl_certificate /etc/certs/${DOMAIN}.pem; + ssl_certificate_key /etc/certs/${DOMAIN}-key.pem; + + add_header Strict-Transport-Security "max-age=31536000" always; + + ssl_session_cache shared:SSL:20m; + ssl_session_timeout 10m; + + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + ssl_prefer_server_ciphers on; + ssl_ciphers "ECDH+AESGCM:ECDH+AES256:ECDH+AES128:!ADH:!AECDH:!MD5;"; + + root /var/www/html/web; + index index.php; + + access_log /var/log/nginx/access.log; + error_log /var/log/nginx/error.log; + + gzip on; + gzip_disable "msie6"; + + gzip_vary on; + gzip_proxied any; + gzip_comp_level 6; + gzip_buffers 16 8k; + gzip_http_version 1.1; + gzip_min_length 0; + gzip_types text/plain application/javascript text/css text/xml application/xml application/xml+rss text/javascript application/vnd.ms-fontobject application/x-font-ttf font/opentype; + + client_max_body_size 100M; + + location ~ /.well-known/acme-challenge { + allow all; + root /var/www/html; + } + + location / { + try_files $uri $uri/ /index.php$is_args$args; + } + + location ~ \.php$ { + try_files $uri =404; + fastcgi_buffers 8 16k; + fastcgi_buffer_size 32k; + fastcgi_connect_timeout 60; + fastcgi_read_timeout 300; + fastcgi_split_path_info ^(.+\.php)(/.+)$; + fastcgi_pass wordpress:9000; + fastcgi_index index.php; + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_param PATH_INFO $fastcgi_path_info; + } + + location ~ /\.ht { + deny all; + } + + location = /favicon.ico { + log_not_found off; access_log off; + } + location = /robots.txt { + log_not_found off; access_log off; allow all; + } + location ~* \.(css|gif|ico|jpeg|jpg|js|png)$ { + expires max; + log_not_found off; + } +}