Mac Docker WordPress Entwicklungs-Umgebung

Stand: März 2026

Docker braucht einen Linux-Kernel, um Container auszuführen. Auf macOS gibt’s keinen Linux-Kernel, deshalb muss eine VM im Hintergrund laufen (z. B. mit colima).

Docker Desktop ist ressourcenfressend und träge. Nutze deshalb colima als VM. Mit Docker läuft alles viel schneller als mit LocalWP!

Colima installieren

Zsh
brew install colima

Colima starten

Zsh
colima start

Mac ID finden

Zsh
#Mac User ID
ID 
# Auf Mac oft 501, deshalb unten user: "510:20" - sonst Katastrophe mit Berechtigungen.

Docker Compose File

Für macOS – ARM und fixe WordPress Installation.

YAML
services:
  wordpress:
    build: .
    platform: linux/arm64
    ports:
      - '8080:80'
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: wordpress
      WORDPRESS_DB_NAME: wordpress
      WP_CLI_CACHE_DIR: /dev/null
    volumes:
      - .:/var/www/html
      - ./php-config.ini:/usr/local/etc/php/conf.d/uploads.ini
    user: '501:20'
    depends_on:
      db:
        condition: service_healthy

  db:
    image: mariadb:10.11
    environment:
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: wordpress
      MYSQL_ROOT_PASSWORD: root
    volumes:
      - db_data:/var/lib/mysql
    command: >
      --innodb_buffer_pool_size=256M
      --max_allowed_packet=64M
      --max_connections=20
      --table_open_cache=64
      --innodb_file_per_table=1
      --innodb_flush_log_at_trx_commit=2
      --character-set-server=utf8mb4
      --collation-server=utf8mb4_unicode_ci
    healthcheck:
      test: ['CMD', 'mysqladmin', 'ping', '-h', 'localhost', '-u', 'root', '-proot']
      timeout: 20s
      retries: 10
      interval: 10s
      start_period: 30s

  adminer:
    image: adminer:4.8.1
    platform: linux/arm64
    ports:
      - '8081:8080'
    environment:
      ADMINER_DEFAULT_SERVER: db
    depends_on:
      db:
        condition: service_healthy

  mailpit:
    image: axllent/mailpit:latest
    platform: linux/arm64
    ports:
      - '8026:8025'
      - '1026:1025'
    environment:
      MP_SMTP_AUTH_ACCEPT_ANY: 1
      MP_SMTP_AUTH_ALLOW_INSECURE: 1
    volumes:
      - mailpit_data:/data

volumes:
  db_data:
  mailpit_data:

Dockerfile

Bash
FROM wordpress:6.9.1-php8.3-apache

# WP-CLI installieren
RUN curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar && \
    chmod +x wp-cli.phar && \
    mv wp-cli.phar /usr/local/bin/wp

# PHP-Config kopieren
COPY php-config.ini /usr/local/etc/php/conf.d/uploads.ini

WORKDIR /var/www/html

php-config.ini in Root Folder

PHP
# Upload und Request Limits
upload_max_filesize = 64M
post_max_size = 64M
max_execution_time = 300
max_input_time = 300
memory_limit = 256M
max_input_vars = 3000
max_file_uploads = 20

# OPcache
opcache.enable = 1
opcache.memory_consumption = 128
opcache.max_accelerated_files = 4000
opcache.revalidate_freq = 2
opcache.validate_timestamps = 1

Wohin mit den Files?

  • docker-compose.yml
  • php-config.ini
  • Dockerfile

in Sites/new-wp-site Ordner.

Zsh
cd Sites
mkdir new-wp-site
cd new-wp-site
touch docker-compose.yml php-config.ini Dockerfile
# Code von oben reinkopieren

Plugin und Theme Stack installieren

Füge den ganzen entpackten Plugins und Themes Ordner in new-wp-site mit dazu. So kannst du vorausgewählte Themes und Plugins gleich direkt mitinstallieren.

CLI Skript Automatisierung

Füge in .zshrc Profil aliase für Automatisierungen hinzu.

1. wpsetup dein-ordnername

Erstellt in Sites Ordner einen neuen Ordner mit „dein-ordnername“ und installiert dort WordPress lokal mit den Settings aus dem docker-compose.yml file und der php-config.ini. Es wird zusätzlich wp-cli mitinstalliert. Du bist danach automatisch im Ordner drin.

2. wpinit

Löscht die Standardplugins und Themes und kopiert die Inhalte aus dem Themes und Plugins Ordner in die lokale Entwicklungsumgebung. Mit wp-cli werden noch einige Seiteneinstellungen vorgenommen.

Bash
alias wpsetup='function _wpsetup() { 
  cd ~/Sites && mkdir "$1" && \
  cp new-wp-site/{docker-compose.yml,php-config.ini,Dockerfile} "$1/" && \
  cd "$1" && docker-compose up -d --build
}; _wpsetup'
alias wpinit='function _wpinit() {
   if [ ! -f "docker-compose.yml" ]; then
       echo "Fehler: Keine docker-compose.yml gefunden."
       return 1
   fi
   
   current_dir=$(basename "$PWD")
   echo "Initialisiere: $current_dir"
   
   rm -f wp-content/plugins/hello.php
   rm -rf wp-content/plugins/akismet
   rm -rf wp-content/themes/twentytwentyfive
   rm -rf wp-content/themes/twentytwentyfour
   rm -rf wp-content/themes/twentytwentythree
   rm -f license.txt wp-config-sample.php readme.html
   
   [ -d "$HOME/Sites/new-wp-site/themes" ] && cp -r "$HOME/Sites/new-wp-site/themes/"* wp-content/themes/
   [ -d "$HOME/Sites/new-wp-site/plugins" ] && cp -r "$HOME/Sites/new-wp-site/plugins/"* wp-content/plugins/

   sleep 5
   
   docker-compose exec -T wordpress wp core install --url=https://gwdev.ch --title="$current_dir" --admin_user=admin --admin_password=admin --admin_email=admin@admin.ch --skip-email
   docker-compose exec -T wordpress wp language core install de_DE
   docker-compose exec -T wordpress wp site switch-language de_DE
   docker-compose exec -T wordpress wp option update timezone_string "Europe/Zurich"
   docker-compose exec -T wordpress wp option update home "https://gwdev.ch"
   docker-compose exec -T wordpress wp option update siteurl "https://gwdev.ch"
   docker-compose exec -T wordpress wp rewrite structure "/%postname%/" --hard
   docker-compose exec -T wordpress wp option update default_comment_status closed
   docker-compose exec -T wordpress wp option update default_ping_status closed
   docker-compose exec -T wordpress wp option update date_format "j. F Y"
   docker-compose exec -T wordpress wp option update time_format "G:i"
   docker-compose exec -T wordpress wp option update uploads_use_yearmonth_folders 0
   docker-compose exec -T wordpress wp theme update --all
   docker-compose exec -T wordpress wp plugin update --all
   docker-compose exec -T wordpress wp core update
   docker-compose exec -T wordpress wp language core update
   docker-compose exec -T wordpress wp language plugin update --all
   docker-compose exec -T wordpress wp language theme update --all
   docker-compose exec -T wordpress wp plugin activate --all
   docker-compose exec -T wordpress wp theme activate gwbase
   docker-compose exec -T wordpress wp post create --post_type=page --post_title="Home" --post_status=publish
   docker-compose exec -T wordpress wp post create --post_type=page --post_title="Impressum" --post_status=publish
   docker-compose exec -T wordpress wp post create --post_type=page --post_title="Datenschutz" --post_status=publish

   docker-compose exec -T wordpress wp post delete 1 --force
   docker-compose exec -T wordpress wp post delete 2 --force
   docker-compose exec -T wordpress wp post delete 3 --force
   
   echo "✓ Fertig!"

}; _wpinit'

zshrc Aliase

Site öffnen
alias ols=“open https://gwdev.ch“

Backend der Seite öffnen
alias ola=“open https://gwdev.ch/wp-login.php“

Adminer öffnen
alias olad=“open http://localhost:8081″

Mailpit öffnen
alias olm=“open http://localhost:8025″

SMTP Ports für Mailpit

Mit SMTP Plugin mailpit mit Port 1025 – ohne PW.

Docker Container starten

Zsh
docker compose up -d 
# dcu

Bei Änderungen an bestehendem docker-compose.yml File

Zsh
docker compose down --remove-orphans
docker compose up -d --remove-orphans

Aktive Container anzeigen

Zsh
docker ps

Docker Container beenden

Zsh
docker compose down
# dcd

Alle Docker Container stoppen

Zsh
docker stop $(docker ps -q)
# Bei Konflikten

VM stoppen

Da geht gar nichts mehr, da keine Virtual Machine mehr läuft

Zsh
colima stop

Problembehandlung

Ports laufen noch. Wichtig: Hier immer alles beenden bevor du neu beginnst. Wenn du nicht mehr weisst, was genau wo gestartet ist: docker stop $(docker ps -q) egal von wo aus.

Nach löschen von Ordner sind Daten in Volumes noch da!

Volumes mit gleichem Namen sind noch gespeichert und geben bei DB Änderungen Fehler aus raus.

Zsh
# Alle Volumes anzeigen (auch ungenutzte)
docker volume ls

# Detaillierte Informationen zu einem Volume
docker volume inspect VOLUME_NAME

# Volumes nach Namen filtern
docker volume ls --filter name=wp-kadence

# Einzelnes Volume löschen
docker volume rm VOLUME_NAME

# Alles stoppen und löschen
docker kill $(docker ps -aq)
docker rm $(docker ps -aq)
docker volume rm $(docker volume ls -q)

Mehrere Sites?

Jeweils nur an einer arbeiten. Wenn du eine andere willst, docker compose down, dann ins andere verzeichnis und dort docker compose up -d

Geht das Easy?

OMG – wenn du keinen Bock auf Wutanfälle hast, nutze einfach WP Studio oder LocalWP. Docker ist zwar mächtiger und viel flexibler – aber diese ständige Berechtigungs-Kacke. Das ist so mühsam. Ich habe heute Stunden verschwendet alle Berechtigungs-Fehler auszumerzen.

Hat es sich gelohnt? Ja definitiv. Läuft schon viel schneller und stabiler. Aber das war eine richtige Zangengeburt.

Docker ist flexibel erweiterbar

Meine Variante hier ist die easy Variante. Ich habe verschiedene getestet. Die hier ist extrem minimal. Das reicht für mein Setup.

Du kannst All-in mit Docker. WordPress als eigenständige Dependency und nur Verwaltung der wp-config.php und des wp-content Ordners.

Nicht direkt die offiziellen Images laden sondern eigene Zusammenbauen mittels DOCKERFILE – Node, Composer, WP Cli integrieren etc.

Ich nutze oft Subdomains auf Production-Server als Entwicklungs-Sites. WP CLI, Node, Composer, LiteSpeed Cache, SSL, scharfes SMTP – dort ist alles schon vorhanden. Und ich kann Kunden direkt eine PW geschützte Seite zukommen lassen. Für meine eigenen Projekte nutze ich Docker.

Wenn du mit mehreren Entwicklern am gleichen Projekt arbeitest? All-In mit Github – Github Actions, Node, Composer und WP CLI. Sonst wird das viel zu chaotisch.

LocalWP geht trotzdem schneller?

Naja, in nichtmal 1 Minute habe ich alles am laufen mit Docker. Ordner erstellen, File rein, docker compose up -d, und los gehts.