DEV Community

Cover image for Running High-Performance WordPress on a NAS with Docker Compose, MariaDB & Redis
Alessandro Mainardi
Alessandro Mainardi

Posted on Originally published at alexmaina.dev

Running High-Performance WordPress on a NAS with Docker Compose, MariaDB & Redis

πŸ“– Original Reference: Originally published with full volume mapping specs and storage pool benchmarks at alexmaina.dev/wordpress-su-nas.

Many developers who spin up WordPress on a home or small-business NAS (QNAP Container Station, Synology Container Manager, or Proxmox) face painful TTFB (Time to First Byte) latency of 2 to 5 seconds. Pages feel sluggish, and admin dashboards grind to a halt.

The root cause is rarely the CPU: it is almost always disk I/O bottlenecks on consumer NAS drives combined with default MySQL settings that write every single transient query to spinning mechanical disks.

Here is the tuned, production-ready docker-compose.yml stack with MariaDB performance tweaks and Redis in-memory object caching that brings response times under 200ms on local hardware.


1. The High-Performance Docker Compose Stack

Create a directory on your NAS fast storage volume (preferably an SSD pool or NVMe cache tier):

mkdir -p /share/Container/wordpress-stack && cd /share/Container/wordpress-stack
nano docker-compose.yml
Enter fullscreen mode Exit fullscreen mode

Paste the following optimized stack:

version: '3.8'

services:
  db:
    image: mariadb:10.11-jammy
    container_name: wp_mariadb
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: YourSuperSecureRootPassword_123!
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wp_user
      MYSQL_PASSWORD: YourSuperSecureUserPassword_123!
    volumes:
      - ./mariadb_data:/var/lib/mysql
      - ./mariadb_conf/my.cnf:/etc/mysql/conf.d/my.cnf:ro
    networks:
      - wp_internal

  redis:
    image: redis:7-alpine
    container_name: wp_redis
    restart: always
    command: redis-server --maxmemory 256mb --maxmemory-policy allkeys-lru
    networks:
      - wp_internal

  wordpress:
    image: wordpress:php8.3-fpm-alpine
    container_name: wp_core
    restart: always
    depends_on:
      - db
      - redis
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_NAME: wordpress
      WORDPRESS_DB_USER: wp_user
      WORDPRESS_DB_PASSWORD: YourSuperSecureUserPassword_123!
      WORDPRESS_CONFIG_EXTRA: |
        define('WP_REDIS_HOST', 'redis');
        define('WP_REDIS_PORT', 6379);
        define('WP_REDIS_TIMEOUT', 1);
        define('WP_REDIS_READ_TIMEOUT', 1);
        define('WP_CACHE', true);
    volumes:
      - ./wp_data:/var/www/html
    networks:
      - wp_internal
      - web_proxy

networks:
  wp_internal:
    internal: true
  web_proxy:
    external: true
Enter fullscreen mode Exit fullscreen mode

2. Tuning MariaDB: Stop Killing Your Disk I/O

Default MariaDB installations allocate only 128MB to the InnoDB buffer pool. On a NAS, this forces MariaDB to constantly read and write table indices directly to slow SATA hard drives.

Create ./mariadb_conf/my.cnf:

[mysqld]
# Allocate 50-70% of available RAM allocated to this container
innodb_buffer_pool_size = 1G
innodb_log_file_size = 256M
innodb_flush_log_at_trx_commit = 2
innodb_flush_method = O_DIRECT

# Connection and query cache settings
max_connections = 100
query_cache_type = 0
query_cache_size = 0

# Prevent slow reverse DNS lookups on internal container network
skip-name-resolve
Enter fullscreen mode Exit fullscreen mode

⚑ The Secret Sauce: innodb_flush_log_at_trx_commit = 2 writes log buffers to disk once per second instead of on every single transaction commit. This reduces disk write IOPS by over 80% while remaining completely safe against OS crashes.


3. Enable Redis Object Caching

Instead of querying MariaDB for post metadata, taxonomy terms, and options on every page load, Redis stores the parsed PHP objects in RAM:

  1. Log into your WordPress admin dashboard (/wp-admin).
  2. Go to Plugins β†’ Add New and search for Redis Object Cache by Till KrΓΌss.
  3. Click Install β†’ Activate.
  4. Go to Settings β†’ Redis and click Enable Object Cache.
  5. You should see Status: Connected with zero configuration needed (since we already injected the constants via WORDPRESS_CONFIG_EXTRA).

Your database queries will drop from 60-120 per page down to 2-4 queries.


4. Automated Daily Backup Script

Never rely solely on NAS snapshots. Run a cron job that creates a clean SQL dump and compresses wp-content:

#!/bin/bash
BACKUP_DIR="/share/Backup/wordpress"
DATE=$(date +%Y%m%d_%H%M%S)
mkdir -p "$BACKUP_DIR"

# Dump database without locking tables
docker exec wp_mariadb mariadb-dump -u wp_user -pYourSuperSecureUserPassword_123! --single-transaction wordpress | gzip > "$BACKUP_DIR/wp_db_$DATE.sql.gz"

# Keep last 7 days of backups
find "$BACKUP_DIR" -type f -name "*.sql.gz" -mtime +7 -delete
Enter fullscreen mode Exit fullscreen mode

Conclusion

Running WordPress on a NAS doesn't have to be slow. By using a lightweight Alpine-based FPM container, tuning MariaDB's InnoDB buffer pool to keep queries in memory, and offloading repetitive lookups to Redis, you get cloud-grade performance right from your local hardware.

Author: Alessandro Mainardi β€” Software Developer & Systems Architect. Read the complete self-hosting and containerization guides at alexmaina.dev/wordpress-su-nas.

Top comments (0)