Running WordPress in Docker on Apple Silicon

As you may have noticed if we’ve been connected for a while, I’ve finally gotten back around to getting my long-neglected personal site up and running and modernized. It’s been long overdue.

While I did briefly consider other blogging and CMS platforms, in the end, I’m most familiar with WordPress so I decided with limited time to go with something I’m already familiar with.

Unit Testing/Sandboxing WordPress

That said, I definitely wanted a WordPress unit test/sandbox environment to play around with and get up to speed on the latest in the world of WordPress and test before actually applying changes to this site. It’s not difficult to have WordPress go wonky by applying too many or conflicting plugins and then try and back everything out. While plugins will still be persisted using this approach, it’s still a lot easier to spin up a new WordPress instance using containers than to try and de-foobar my main site on any foobar decisions made.

There have been a lot of advances in technology in the last 5 years and instead of building a test VM, the natural choice was to use Docker containers for this. I’m majorly happy with this direction as a WordPress sandbox environment. But it turns out, getting what I wanted up and running on Apple Silicon took some working out. So I thought I’d publicize my internal Engineering Notebook on this one in case it helps anyone else.

What I Wanted

What I wanted was a traditional WordPress environment, but in a Docker configuration. As a packaged configuration, I needed:

  • The latest version of WordPress
  • A relatively recent version of MySQL for the DB backend
  • Adminer for simple web-based MySQL Administration

I found a few really helpful articles that got me going in the right direction, but again, running MacOS on an M1 as my sandbox posed a few issues I had to overcome. There’s a myriad of articles on running WordPress on Docker; I’ll let you find those on your own.

This article is focused on helping you get over the hurdle of getting to a working state on Apple Silicon.

Articles I Used

Here are the articles I used:

I also referred to the official Docker Containers documentation for WordPress and MySQL, the latter because my main issue was getting a working MySQL version or a variant to work on my machine (using the ARM architecture and arm64 tag):

Data Persistence

One of the biggest issues to consider when building a container is data persistence. Persistence inside the container will be lost if the container is stopped and a new container is started from the original image without a commit. If memory serves (I could be wrong), persistence of the WordPress components and the MySQL components weren’t always taken into consideration in those articles.

Rooting myself in a relative path we’ll call ./docker/wordpress, I created the following directories:

chris@Zion WordPress % mkdir media mysql wordpress
chris@Zion WordPress % ls -lF
drwxr-xr-x@ 49 chris  staff  1568 May 18 13:38 media/
drwxr-xr-x@ 21 chris  staff   672 Apr 21 12:52 mysql/
drwxr-xr-x@ 25 chris  staff   800 May 16 21:37 wordpress/

Now I have places to root any volumes to my Docker container for WordPress and MySQL persistence. media is simply a place to store any downloaded or created media as in the past I’ve found once I’ve grabbed a media artifact like an image, it’s nice to have it around. And most especially since I’m sandboxing, if I grab a media artifact, test, and then want to run this into production (here on this site), I need the original media artifact (since “push to production” for such a tiny operation) is a copy/paste operation. (This is not bound to any volume on the container — it’s merely for my convenience and for “development” in the same directory root.)

Final Solution for Apple Silicon using Docker Compose

From here, I’ll just cut to the final solution since there are, again, a myriad of articles explaining the basics of Docker. The articles I’ve referenced above do a good job of this. I used Docker Compose as the final solution since Docker Compose provides the most efficient, economical way of encapsulating the entire Docker environment I want to run as a single package concept or single action.

The only thing I’ll add is… make sure you’re running the Docker engine on your Mac so all of this works. For instructions for installing Docker on MacOS Apple Siliconclick here. Make sure of course that you select the proper version:

The overall issue I was having was finding a true MySQL version from the official Docker Hub that would run and be supported on Apple Silicon, which is based on the ARM architecture. While some versions of MySQL had ARM versions, I couldn’t really get any to run for various reasons.

The solution? I switched to MariaDB as a MySQL substitute using an arm64 tag which seemed to work fine right out of the gate. Problem solved.

I renamed my mysql directory to maria, then used this Docker Compose YAML file (created in my docker rooted directory as above) to get it all running. Yes, I used straight-out default port 80 for my sandbox. Of course, adjust your YAML file appropriately to run on any off ports. (Bear in mind, some of the configuration files in the internal image for the software you are running may also need to be adjusted, depending on how you map ports. I would leave ports as default inside the container and map ports externally. Example: "9080:80", meaning expose as port 9080 but map to port 80 in the container.)

version: "3"

services:
  adminer:
    image: adminer
    ports:
      - "8080:8080"

  mariadb:
    image: mariadb
    restart: always
    ports:
      - "3306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: <root db password goes here>
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: <wordpress db user password goes here>
    volumes:
      - ./maria:/var/lib/mysql

  wordpress:
    depends_on:
      - mariadb
    image: wordpress
    restart: always
    ports:
      - "80:80"
    environment:
      WORDPRESS_DB_HOST: mariadb
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: <wordpress db user password goes here>
      WORDPRESS_DB_NAME: wordpress
    volumes:
      - ./wordpress:/var/www/html
volumes:
  mysql:

From here, it’s a simple docker-compose up command in a Terminal window (docker-compose up -d if you want to run detached — I run in a Terminal screen session and like seeing the logs at times for again, sandboxing).

Here’s my final solution from a rooted directory standpoint and from where I can now launch the WordPress Docker container:

chris@Zion WordPress % ls -lF
-rw-r--r--@  1 chris  staff   739 Apr 14 03:34 docker-compose.yaml
drwxr-xr-x@ 16 chris  staff   512 May  6 23:00 maria/
drwxr-xr-x@ 51 chris  staff  1632 May 19 12:03 media/
drwxr-xr-x@ 25 chris  staff   800 May 16 21:37 wordpress/
chris@Zion WordPress % docker-compose up -d

This is working well for me and is fully supporting the underlying ARM requirements for running on Apple Silicon.

Hope this helps! It’s a beautiful Spring day here in the Twin Cities, MN USA.

Update 2/18/2024

It’s probably worth pointing out that the port designations in the docker-compose file above expose those ports “publicly” in some way. If you’re just running this on your desktop/laptop — probably not a big deal (but again could be, depending on your local or current network — airport WiFi, company LAN/VPN, etc.)

Refer to the Docker documentation on Networking to understand how to restrict exposing ports. MySQL and WordPress will need to be on the same network, which could be (should be?) running on a local, internal Docker network. There are at least a couple ways to do this. Again, refer to the Docker documentation on Networking for this.

Chris Olive

Chris Olive is a seasoned and passionate cybersecurity strategist, evangelist, consultant, trusted advisor, and hands-on technologist with over two decades of cybersecurity consulting experience in the US/UK governments, the Fortune 500, and large international companies all over the world. Chris has primary expertise in Identity Access Management and Identity Governance & Administration along with professional experience and expertise in Ethic Hacking & Penetration Testing, Secure Development, and Data Security & Encryption. Chris is a frequent writer, speaker, and evangelist on a range of cybersecurity topics. Chris is currently a Senior National Security Advisor & Architect for CDW -- a worldwide leader and innovator in solutioning, architecting, and delivering secure information technology solutions on-prem, in the cloud, multi-cloud, hybrid, or co-hosted leveraging the world's largest, best, and most trusted brands.

View all posts by Chris Olive →