If you want to learn, test, or develop WordPress without spending money on a server or domain — and without exposing your site to the public internet — running WordPress locally is the way to go. A local setup lets you simulate a full website environment right on your own machine, accessible through your browser with no internet connection or file uploads required. Building on the Local approach covered earlier, this lesson introduces a faster, more modern deployment method using Docker.
1. Why Run WordPress Locally?
1.1 Learn and Explore WordPress — Fast and Free
One of the biggest perks of a local WordPress setup is that you can dive in and start experimenting immediately — no hosting plan, no domain registration, no cost, no risk.
You can install different versions of WordPress side by side and compare how things have changed. Try out different themes and plugins to explore layouts and functionality. Build different types of sites — a blog, an online store, a community forum — and learn how each one works from the ground up.
💡 Learning Scenario Examples:
| Learning Goal | How to Practice Locally |
|---|---|
| Compare WordPress versions | Run WordPress 6.7 and 6.8 simultaneously and compare block editor improvements |
| Get started with theme development | Install the official Twenty Twenty-Five theme and gradually modify its CSS and template files |
| Test plugin compatibility | Test combinations of WooCommerce, Elementor, and other plugins in an isolated environment |
| Multisite networks | Enable WordPress Multisite to simulate enterprise-level multi-site management |
1.2 Develop and Test in a Safe Sandbox
Another major benefit is having a safe, private space to experiment with your site’s design, content, plugins, and code — without ever risking your live site.
Edit styles, rearrange layouts, add or remove content and images, and see results in real time — no uploading files or waiting for deploys. Install and test plugins to check for compatibility issues, fine-tune their settings, and optimize performance. Write and debug custom code in a controlled environment where mistakes won’t take down a production site.
⚠️ A Cautionary Tale: Countless WordPress sites have crashed because someone updated a plugin directly in production. A local testing environment can save you from that kind of disaster.
1.3 Back Up and Restore with Ease
A local environment also makes it far easier to keep your data safe. You can back up your site’s files and database at any time — manually or on a schedule — and store them on your machine or an external drive. If anything goes wrong, restoring is as simple as copying the backup files back into place. No reinstallation, no reconfiguration.
🔄 The Docker Backup Advantage:
Compared to traditional local environments like XAMPP or MAMP, Docker offers a much cleaner backup story. Your entire WordPress site — themes, plugins, uploaded media, and database — can be version-controlled and migrated as a single, self-contained unit.
1.4 Seamlessly Migrate Between Local and Production
Finally, a local setup makes it straightforward to move your site to a live server when you’re ready — or pull a production site down to your local machine for maintenance. Once development and testing are done, upload your files and database to a server, tweak a few settings, and your site is live. The reverse works just as easily for backup or continued development.
📦 Migration Workflow Overview:
┌─────────────────┐ Export ┌─────────────────┐ Import ┌─────────────────┐
│ Local Dev Env │ ─────────▶ │ Migration Pkg │ ─────────▶ │ Production Server│
│ (Docker Container)│ │ (.sql + files) │ │ (Cloud Server) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
2. Technical Foundations & Tool Selection
Before diving into the actual deployment, let’s cover the core technical concepts behind this lesson. Understanding these fundamentals will make the hands-on steps much easier to follow.
2.1 Docker: Modern Application Containerization
Docker is a containerization technology that packages an application along with all its dependencies into a standardized unit called a “container.” Think of a Docker container as a lightweight virtual machine — but one that starts faster and uses far fewer resources than a traditional VM.
🎯 Why Use Docker to Deploy WordPress?
| Comparison | Traditional (XAMPP/MAMP) | Docker |
|---|---|---|
| Environment consistency | Local and server environments may differ | Dev, staging, and production environments are identical |
| Dependency management | Manually install PHP, MySQL, etc. | All dependencies handled automatically |
| Multiple versions | Difficult; conflicts are common | Run multiple isolated environments with ease |
| Cleanup & rebuild | Leftover files are hard to remove | Delete the container and everything is gone |
| Migration & deployment | Requires reconfiguration | Export an image and you’re done |
| Resource usage | Services run in the background constantly | Start and stop on demand — zero footprint when idle |
2.2 Docker Compose: Orchestrating Multiple Containers
Docker Compose is the official multi-container orchestration tool from Docker. A complete WordPress site needs several services working together: a web server, a PHP runtime, a database, and a caching layer. Docker Compose lets you define and manage all of these interconnected services in a single YAML configuration file.
📝 Key Concepts Explained:
# docker-compose.yml basic structure
services: # Define the services (containers) to run
wordpress: # Service name
image: wordpress:fpm # Docker image to use
ports:
- "80:80" # Port mapping: host_port:container_port
volumes:
- wp_data:/var/www/html # Persist data across restarts
environment: # Environment variable configuration
WORDPRESS_DB_HOST: db
depends_on: # Service dependencies
- db
db: # Database service
image: mariadb:latest
volumes:
- db_data:/var/lib/mysql
volumes: # Declare volumes for persistent storage
wp_data:
db_data:
⚡ Important Note: Starting with Docker Compose V2 (now the default), the **version: "3"** declaration at the top of the config file has been deprecated. Keeping it won’t cause errors, but for new projects it’s best to simply leave it out. All configuration files in this course follow the latest convention.
2.3 Choosing the Right Docker Setup for Your OS
Different operating systems call for different Docker strategies:
| Operating System | Recommended Setup | Notes |
|---|---|---|
| macOS | OrbStack | Lightweight and efficient; provides a virtualized environment |
| Linux | Native Docker + Dockge | Best performance; GUI management available |
| HomeLab users | Umbrel / CasaOS | Graphical management interface; great for beginners |
3. macOS Setup: OrbStack + Docker + Dockge
As container technology continues to evolve, developers increasingly demand lightweight and efficient virtualization tools. OrbStack is a next-generation container and virtual machine platform built specifically for macOS, offering a faster and leaner alternative to Docker Desktop. This chapter walks through running Ubuntu on OrbStack, then setting up Docker and Dockge inside it to create a flexible, high-performance container management environment.
3.1 What Is OrbStack?
OrbStack is a modern container and VM platform designed for macOS. It’s lighter, faster, and more resource-efficient than Docker Desktop:
| Feature | Details |
|---|---|
| 🔋 Low resource usage | Significantly lower CPU and memory footprint vs. Docker Desktop (real-world memory usage is roughly 1/3 to 1/5) |
| ⚡ Fast startup | Near-instant container and VM launches (cold start typically under 2 seconds) |
| 🔗 Deep macOS integration | Built-in file sharing and port forwarding; container services accessible via container-name.orb.local |
| 🐳 Docker & Kubernetes support | Fully compatible with Docker commands and workflows — no changes to existing Docker Compose files needed |
💡 When to choose OrbStack: If you’re on macOS and primarily doing web development or running Docker containers, OrbStack is arguably the best option available today.
3.2 Why Run Ubuntu Inside OrbStack?
Running an Ubuntu VM on OrbStack and deploying Docker inside it offers several advantages:
- 🔒 Environment isolation: The Ubuntu VM provides a fully isolated environment, preventing any container side effects from affecting your macOS host
- 🎛️ Flexibility: Choose a specific Ubuntu release (e.g., Ubuntu 22.04 LTS or 24.04 LTS)
- ✅ Compatibility: Solves compatibility issues for applications that depend on Linux kernel features
- 📦 Portability: The entire environment can be easily backed up and migrated; VMs can be exported in standard formats for team sharing
3.3 Step-by-Step Setup
Step 1: Install OrbStack
Option A: Install via Homebrew (Recommended)
brew install orbstack
Option B: Download from the official site
Visit https://orbstack.dev/download and grab the installer for your chip (Apple Silicon / Intel).
🔍 Verify the installation: Open a terminal and run **orb version** to confirm everything is set up correctly.
Step 2: Create an Ubuntu Virtual Machine
Once OrbStack is running, create an Ubuntu VM through either the GUI or the command line:
# Create an Ubuntu VM named "ubuntu"
orb create ubuntu ubuntu
# Enter the VM's shell
orb shell ubuntu
💡 Tip: Linux VMs created by OrbStack share the macOS host’s file system. Your Mac user directory is automatically mounted at **/Users/your-username** inside the VM.
Step 3: Install Docker Inside Ubuntu
Once you’re inside the Ubuntu VM, install Docker with the following steps:
# 1. Update the package index and install required dependencies
sudo apt update
sudo apt install apt-transport-https ca-certificates curl software-properties-common -y
# 2. Add Docker's official GPG key
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
# 3. Add the Docker repository to APT sources
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# 4. Install Docker Engine and related components
sudo apt update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y
# 5. Verify the installation
sudo docker --version
Step 4: Deploy Dockge — A Visual Docker Compose Manager
Dockge is a lightweight, open-source Docker Compose management tool created by the developer behind Uptime Kuma. Compared to heavier solutions like Portainer, Dockge focuses exclusively on managing Docker Compose projects with a cleaner, more intuitive interface.
# 1. Create the required directories
sudo mkdir -p /opt/stacks /opt/dockge
cd /opt/dockge
# 2. Download the official compose.yaml
sudo curl https://raw.githubusercontent.com/louislam/dockge/master/compose.yaml --output compose.yaml
# 3. Start Dockge
sudo docker compose up -d
📋 Dockge Key Features:
- 🖥️ Intuitive web UI for managing Docker Compose projects
- 📝 Built-in YAML editor with syntax highlighting
- 🔄 One-click start / stop / restart for Compose stacks
- 📊 Real-time container logs and status monitoring
Step 5: Access the Dockge Web Interface
Once Dockge is up and running, configure port forwarding so you can access it from your Mac:
# Run this in the macOS terminal (not inside the VM)
orb expose ubuntu 5001:5001
Then open your browser and navigate to: http://localhost:5001
3.4 Troubleshooting
🔧 Issue 1: Port Mapping Not Working
# Reconfigure port mapping
orb expose ubuntu 5001:5001
🔧 Issue 2: Docker Permission Denied
# Add the current user to the docker group
sudo usermod -aG docker $USER
# Log out and back in for the change to take effect
🔧 Issue 3: Running Out of Disk Space
# Check disk usage
df -h
# Clean up unused Docker resources
docker system prune -a
3.5 Use Cases
This nested virtualization approach works well for the following scenarios:
| Scenario | Description |
|---|---|
| 🖥️ Development environments | Maintain a dev/test environment that mirrors production |
| 📚 Learning & experimentation | Safely learn and experiment with Docker technology |
| 📦 Container management | Simplify Docker Compose project management with Dockge |
| 🔄 Cross-platform development | Run Linux-dependent applications on macOS |
4. Deploying WordPress with Docker Compose
Regardless of which Docker setup you chose, the WordPress deployment process is the same. This chapter provides a battle-tested configuration featuring the full Nginx + PHP-FPM + MariaDB + Redis stack, complete with FastCGI caching for maximum performance.
4.1 Architecture Overview
┌─────────────────────────────────────────────────────────────┐
│ Browser Request │
└─────────────────────────┬───────────────────────────────────┘
▼
┌─────────────────────────────────────────────────────────────┐
│ Nginx (Port 80) │
│ ┌─────────────────────────┐ │
│ │ FastCGI Cache Layer │ │
│ │ (Static HTML caching) │ │
│ └───────────┬─────────────┘ │
└──────────────────────────┼──────────────────────────────────┘
▼
┌─────────────────────────────────────────────────────────────┐
│ WordPress (PHP-FPM, Port 9000) │
│ ┌─────────────────────────┐ │
│ │ Redis Object Cache │◀───────────────────┤
│ │ (DB query caching) │ │
│ └───────────┬─────────────┘ │
└──────────────────────────┼──────────────────────────────────┘
▼
┌─────────────────────────────────────────────────────────────┐
│ MariaDB Database │
└─────────────────────────────────────────────────────────────┘
🎯 Two-Layer Caching Strategy Explained:
- FastCGI Cache (Nginx layer): Caches the fully rendered HTML pages generated by PHP as static files. Subsequent requests for the same page are served directly from cache — no PHP execution required.
- Redis Object Cache (WordPress layer): Caches WordPress’s internal database query results, reducing the load on the database.
4.2 File Structure
wordpress-docker/
├── docker-compose.yml # Docker Compose configuration
├── nginx.conf # Nginx configuration
└── logs/
└── nginx/ # Nginx log directory (auto-created)
4.3 docker-compose.yml
services:
db:
image: mariadb:latest
restart: always
environment:
MYSQL_ROOT_PASSWORD: somewordpress
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress
volumes:
- db_data:/var/lib/mysql
redis:
image: redis:latest
restart: always
wordpress:
depends_on:
- db
- redis
image: wordpress:fpm
restart: always
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: wordpress
WORDPRESS_DB_NAME: wordpress
WORDPRESS_CONFIG_EXTRA: |
define('WP_REDIS_HOST', 'redis');
define('WP_REDIS_PORT', 6379);
define('WP_CACHE', true);
command:
- sh
- -c
- |
echo 'upload_max_filesize = 4096M' > /usr/local/etc/php/conf.d/uploads.ini
echo 'post_max_size = 4096M' >> /usr/local/etc/php/conf.d/uploads.ini
echo 'memory_limit = 512M' >> /usr/local/etc/php/conf.d/uploads.ini
echo 'max_execution_time = 1200' >> /usr/local/etc/php/conf.d/uploads.ini
docker-entrypoint.sh php-fpm
volumes:
- wordpress_data:/var/www/html
nginx:
depends_on:
- wordpress
image: nginx:latest
restart: always
ports:
- 80:80
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf
- wordpress_data:/var/www/html
- nginx_cache:/var/cache/nginx
- ./logs/nginx:/var/log/nginx
volumes:
db_data: null
wordpress_data: null
nginx_cache: null
networks: {}
4.4 nginx.conf
# FastCGI cache definition
fastcgi_cache_path /var/cache/nginx levels=1:2 keys_zone=WPCACHE:64m inactive=60m max_size=256m;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
server {
listen 80;
server_name localhost;
root /var/www/html;
index index.php index.html index.htm;
# Set to 0 for unlimited, or explicitly set to 4G
client_max_body_size 4G;
# Increase buffer size for large uploads to reduce temp file writes
client_body_buffer_size 10M;
# Extend read timeout to prevent disconnections during large (4GB) uploads
client_body_timeout 600s;
# Cache status header (useful for debugging — shows whether cache was hit)
add_header X-Cache-Status $upstream_cache_status;
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;
# FastCGI cache settings
fastcgi_cache WPCACHE;
fastcgi_cache_valid 200 60m;
fastcgi_cache_valid 404 1m;
# Conditions for skipping the cache
set $skip_cache 0;
# Don't cache POST requests
if ($request_method = POST) {
set $skip_cache 1;
}
# Don't cache logged-in users or comment authors
if ($http_cookie ~* "wordpress_logged_in|comment_author") {
set $skip_cache 1;
}
# Don't cache admin pages
if ($request_uri ~* "/wp-admin/|/wp-login.php") {
set $skip_cache 1;
}
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
}
# Cache static assets
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires max;
log_not_found off;
}
# Block access to hidden files
location ~ /\.ht {
deny all;
}
}
4.5 Image Reference
| Service | Image | Notes |
|---|---|---|
| db | mariadb:latest | Latest stable MariaDB release |
| redis | redis:latest | Latest stable Redis release |
| wordpress | wordpress:fpm | WordPress PHP-FPM variant (automatically tracks the latest PHP version) |
| nginx | nginx:latest | Latest stable Nginx release |
4.6 Deployment Steps
# 1. Create the project directory
mkdir wordpress-docker && cd wordpress-docker
# 2. Create the log directory
mkdir -p logs/nginx
# 3. Create the docker-compose.yml file
# (Save the configuration above to this file)
# 4. Create the nginx.conf file
# (Save the configuration above to this file)
# 5. Start all services
docker compose up -d
# 6. Check the status
docker compose ps
# 7. View logs (optional)
docker compose logs -f
🎉 Once everything is up, visit http://localhost to launch the WordPress installation wizard!
You can also use Dockge’s web-based GUI to configure everything visually.
4.7 Verifying That Caching Works
# Check the response headers with curl
curl -I http://localhost
# Look at the X-Cache-Status header:
# MISS = Cache miss (first visit)
# HIT = Cache hit (served from cache)
# BYPASS = Cache bypassed (logged-in user or admin page)
The first request will show **MISS**. Refresh the page and you should see **HIT**, confirming that caching is working.
4.8 WordPress Admin Configuration
After deployment, you still need to enable Redis object caching in the WordPress dashboard:
- Install the Redis Object Cache plugin
- Go to WordPress Dashboard → Plugins → Add New
- Search for “Redis Object Cache”
- Install and activate it
- Enable object caching
- Navigate to Settings → Redis
- Click the “Enable Object Cache” button
- Confirm the status shows “Connected”
✅ That’s it — you now have a high-performance local WordPress environment with two-layer caching (FastCGI + Redis)! Upcoming lessons will dive deeper into how caching works under the hood.
4.9 Common Management Commands
# Stop all services
docker compose down
# Stop and remove all data volumes (full reset)
docker compose down -v
# Restart services
docker compose restart
# View logs for a specific service
docker compose logs wordpress
docker compose logs nginx
# Enter the WordPress container
docker compose exec wordpress bash
# Enter the database container
docker compose exec db mysql -u wordpress -p
5. Installing WordPress on HomeLab Platforms
Running applications on a personal server or home lab (HomeLab) is a popular choice among tech enthusiasts and privacy-conscious users. Platforms like Umbrel, CasaOS, and other Docker-based HomeLab management tools dramatically simplify the process of deploying and managing self-hosted services.
5.1 HomeLab Platform Overview
| Platform | Highlights | Best For |
|---|---|---|
| Umbrel | Beautiful UI, rich app store, privacy-focused | Bitcoin nodes, personal cloud services |
| CasaOS | Lightweight, easy to install, beginner-friendly | First-time users, NAS devices |
| Portainer | Feature-rich, built for power users | Complex multi-container management |
5.2 The Power of One-Click Deployment
Installing WordPress through tools like Umbrel is remarkably straightforward. These platforms typically provide an app-store-style interface — just find WordPress, click a few buttons, and the installation kicks off automatically. Behind the scenes, the system handles all the heavy lifting: setting up the web server (usually Nginx or Apache), the PHP runtime, and the database (typically MariaDB or MySQL). This one-click or guided installation eliminates the need to manually configure servers, databases, and WordPress files, dramatically lowering the barrier to entry.
5.3 The Value of Self-Hosted WordPress
Running your own WordPress instance in a HomeLab gives you something no third-party host can match: complete ownership and control of your data. All your website content and user data lives on your own hardware, which significantly enhances both privacy and security. Beyond that, it provides an outstanding learning and experimentation environment — you’re free to test themes, plugins, and deep-dive into how websites work, without worrying about breaking a live site or racking up bills (aside from hardware and electricity).
📊 HomeLab vs. Traditional Hosting:
| Aspect | HomeLab (Self-Hosted) | Traditional Cloud Hosting |
|---|---|---|
| Data control | ✅ Full ownership | ⚠️ Depends on the provider |
| Monthly cost | 💰 Electricity only | 💰💰 $10–50+/month |
| Learning value | 🎓 Extremely high | Relatively low |
📚 References & Resources:
- Docker Official Docs: https://docs.docker.com
- WordPress Developer Resources: https://developer.wordpress.org
- OrbStack Documentation: https://docs.orbstack.dev
- Dockge Project: https://github.com/louislam/dockge
Leave a Reply