Why WordPress Was Slow on Docker Desktop for Windows

5 min read
Table of Contents

Our local WordPress multisite environment suddenly started feeling much slower than expected. The first instinct was to ask the usual questions: is WordPress heavy, did a plugin slow it down, or is Docker under pressure? This post documents how we measured the problem, ruled out the wrong suspects, and fixed the real bottleneck.

The Symptom

The local site at http://localhost:8000/ was visibly slow to load. The admin area also felt sluggish. Early measurements showed homepage TTFB values between two and five seconds:

home total=2.320s ttfb=2.300s
run1 total=2.970s ttfb=2.954s
run2 total=3.602s ttfb=3.585s
run3 total=2.970s ttfb=2.944s

Those numbers are high for a local WordPress install. When static files respond quickly but PHP pages are slow, the investigation usually moves toward WordPress bootstrap cost, theme/plugin code, cron, the database, or the filesystem layer.

First Checks

We started with the Docker containers:

docker ps
docker stats --no-stream

WordPress, MariaDB, and phpMyAdmin were running. MariaDB looked healthy. The WordPress container showed occasional CPU activity, but that alone did not explain the delay.

Then we measured a static file response:

curl.exe -o NUL -s -w "static total=%{time_total}s ttfb=%{time_starttransfer}s\n" \
  http://localhost:8000/wp-content/themes/twentytwentyfive/style.css

The static file came back in about 0.04s. That was an important separation: Docker port forwarding and Apache serving simple files were not the bottleneck. The delay appeared when PHP and WordPress had to load.

Was a Plugin the Culprit?

At the time, these network-active plugins were enabled:

multisite-translation-relations 1.0.4
plugin-check 1.9.0

We temporarily deactivated them and measured the homepage again:

wp plugin deactivate plugin-check --network
wp plugin deactivate multisite-translation-relations --network

The result was not a dramatic improvement. Even with the plugins disabled, responses were still in the 2.9-3.8 second range. That was a strong signal that plugin code was not the root cause.

WP-Cron Was Checked Too

The WP-Cron queue had a few events due immediately:

wp cron event list

Running due events showed that Site Health checks could be slow:

wp_version_check: 2.754s
wp_site_health_scheduled_check: 16.683s

This could add occasional weight to page loads, but even after clearing cron events the homepage TTFB remained around three to five seconds. Cron was a factor, not the root cause.

Database and Autoload Options

We also checked autoloaded options:

SELECT COUNT(*) AS autoload_options,
       ROUND(SUM(LENGTH(option_value))/1024/1024, 3) AS autoload_mb
FROM wp_options
WHERE autoload IN ('yes','on','auto-on','auto');

The result was about 0.046 MB, which is tiny. The database tables also looked normal for a test environment. A bloated database or huge autoload payload was unlikely.

The Root Cause: Windows Bind Mounts

The breakthrough came from measuring WordPress bootstrap time on two different filesystems. First, we measured the normal setup where the WordPress directory was bind-mounted from the Windows filesystem into the Docker container. Then we copied the same WordPress files into the container's Linux filesystem and ran the same bootstrap from there.

bind-mount wp-load seconds=5.5932
linux-copy wp-load seconds=0.4811

That difference clarified the root cause. WordPress itself was not inherently slow. The expensive part was Docker Desktop reading thousands of PHP files through a Windows bind mount. Because WordPress touches many PHP files on every request, that filesystem overhead directly increased TTFB.

The Fix: Named Volume for WordPress Core, Bind Mounts for Our Code

Instead of bind-mounting the entire WordPress directory, we moved to a more balanced layout:

  • /var/www/html became a Docker named volume for WordPress core.
  • Only the theme and plugin folders we actively develop remained bind mounts.
  • wp-config.php, .htaccess, and uploads stayed controlled from the host.
  • Debug and automatic update checks were disabled in the fast local mode.

The override file looked like this:

services:
  wordpress:
    environment:
      WORDPRESS_DEBUG: "false"
      WORDPRESS_CONFIG_EXTRA: |
        define( 'DISABLE_WP_CRON', true );
        define( 'WP_AUTO_UPDATE_CORE', false );
        define( 'AUTOMATIC_UPDATER_DISABLED', true );
    volumes:
      - wp_core:/var/www/html
      - ./wordpress/wp-config.php:/var/www/html/wp-config.php
      - ./wordpress/.htaccess:/var/www/html/.htaccess
      - ./wordpress/wp-content/themes/mudos-theme:/var/www/html/wp-content/themes/mudos-theme
      - ./wordpress/wp-content/plugins/mudos-multilingual-relations:/var/www/html/wp-content/plugins/mudos-multilingual-relations
      - ./wordpress/wp-content/plugins/multisite-translation-relations:/var/www/html/wp-content/plugins/multisite-translation-relations
      - ./wordpress/wp-content/plugins/plugin-check:/var/www/html/wp-content/plugins/plugin-check
      - ./wordpress/wp-content/uploads:/var/www/html/wp-content/uploads

volumes:
  wp_core:

We started the environment with:

docker compose -f docker-compose.yml -f docker-compose.fast.yml up -d

The Result

After the change, homepage TTFB dropped sharply:

fixed-fast run1 total=0.478s ttfb=0.475s
fixed-fast run2 total=0.166s ttfb=0.164s
fixed-fast run3 total=0.133s ttfb=0.127s
fixed-fast run4 total=0.343s ttfb=0.333s
fixed-fast run5 total=0.131s ttfb=0.128s

The /tr/ subsite also responded at roughly 0.24s. Network-active plugins and the multisite site list continued to work correctly.

Takeaway

When developing WordPress on Docker Desktop for Windows, performance issues are not always caused by PHP, theme code, or plugin code. For applications like WordPress that read many files per request, the bind mount layer can become the bottleneck.

The practical pattern is simple:

  • Keep WordPress core files inside a Docker named volume when they do not need constant editing.
  • Bind-mount only the theme and plugin folders you are actively developing.
  • Manage WP-Cron, debug behavior, and update checks consciously in local fast mode.
  • Separate guesses from measurements by checking TTFB and isolated bootstrap timing such as wp-load.php.

This approach keeps the development workflow comfortable while significantly reducing the filesystem overhead of the Windows and Docker Desktop combination.

Share this Post

Let’s Build Something Useful Together

Have a project in mind? Share brief details and we will get back quickly.

Fast response
Free project consultation

Or Contact Us Directly