βοΈ WordPress Installation and Configuration
A WordPress site lives across three worlds β the laptop where you build it, the staging copy where it's reviewed, and the production server real users hit. This lesson takes you through installing WordPress in each, then tuning wp-config.php for security, performance, and safe migrations.
π― Learning Objectives
By the end of this lesson, you will be able to:
- Distinguish local, staging, and production environments and pick tools for each
- Install WordPress via LocalWP, Docker, and the classic manual flow
- Configure essential wp-config.php constants for each environment
- Apply security hardening and performance best practices
- Migrate a WordPress site between environments safely
Estimated Time: 45β55 minutes β’ Difficulty: BeginnerβIntermediate
Hands-on: Stand up a local WordPress with Docker and configure it for development.
In This Lesson
Three Environments
Professional WordPress work flows through three environments, each with a different job. Changes travel left-to-right; they never jump straight to production.
| Environment | Purpose | Who sees it | Typical tools |
|---|---|---|---|
| Local | Build and experiment freely | Just you | LocalWP, Docker, XAMPP |
| Staging | Review & test in a production-like copy | Team & clients | Host staging tools, subdomain |
| Production | Serve real traffic reliably | The public | Managed/cloud hosting |
π‘ A useful analogy: Local is your private workshop, staging is the showroom before opening day, and production is the storefront full of customers. You test the risky stuff in the workshop β never on the sales floor.
Local Development
A local install runs WordPress on your own machine: fast, private, offline-capable, and impossible to break for anyone but you. Three options cover most needs.
LocalWP β the easiest start
LocalWP is a purpose-built desktop app: it bundles the web server, PHP, and MySQL, and creates a site in a few clicks with SSL and shareable live links. Best for beginners and WordPress-only work.
- Download and install LocalWP.
- Click + Create a new site and follow the wizard.
- Pick a name, choose Preferred or custom (PHP 8.2, MySQL 8) settings, and set an admin user that is not "admin".
- Start the site and open WP Admin.
Docker β reproducible and team-friendly
Docker containers give every teammate an identical, version-controlled environment. A minimal docker-compose.yml:
services:
db:
image: mysql:8.0
volumes:
- db_data:/var/lib/mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: rootpass
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress
wordpress:
depends_on:
- db
image: wordpress:php8.2-apache
ports:
- "8000:80"
restart: always
volumes:
- ./wp-content:/var/www/html/wp-content
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: wordpress
WORDPRESS_DB_NAME: wordpress
volumes:
db_data: {}
# Bring the stack up, then visit http://localhost:8000
docker compose up -d
# Follow logs, or tear it all down
docker compose logs -f
docker compose down
π‘ Note the modern syntax
Current Docker uses docker compose (a subcommand) rather than the old docker-compose binary, and the top-level version: key in the YAML is now obsolete β omit it. Mounting only ./wp-content keeps your themes and plugins in version control while core stays inside the image.
XAMPP / MAMP β the general-purpose stack
XAMPP (Windows/Linux) and MAMP (macOS) install Apache, MySQL, and PHP for any PHP project. You download WordPress yourself, drop it in the web root, create a database in phpMyAdmin, and run the installer. More manual, but flexible if you juggle multiple technologies.
The Classic Installation
Even with one-click installers everywhere, knowing the manual "famous 5-minute install" demystifies what those tools do for you.
π Prerequisites (WordPress current requirements)
- PHP 8.2+ recommended (7.4 is the bare minimum but end-of-life)
- MySQL 8.0+ or MariaDB 10.5+
- PHP extensions:
mysqli,gdorimagick,mbstring,xml,zip,curl - HTTPS support (an SSL certificate) β expected for every site today
Step 1 β Create the database
CREATE DATABASE wordpress CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'wp_user'@'localhost' IDENTIFIED BY 'a-strong-password';
GRANT ALL PRIVILEGES ON wordpress.* TO 'wp_user'@'localhost';
FLUSH PRIVILEGES;
Step 2 β Configure the database connection
Copy wp-config-sample.php to wp-config.php and fill in the credentials:
<?php
define( 'DB_NAME', 'wordpress' );
define( 'DB_USER', 'wp_user' );
define( 'DB_PASSWORD', 'a-strong-password' );
define( 'DB_HOST', 'localhost' );
define( 'DB_CHARSET', 'utf8mb4' );
define( 'DB_COLLATE', '' );
β οΈ Always generate fresh salts
The keys and salts strengthen your auth cookies. Never leave the "put your unique phrase here" placeholders. Paste fresh values from the official generator:
https://api.wordpress.org/secret-key/1.1/salt/
Step 3 β Run the installer
Visit the site URL. WordPress creates the tables and asks for a site title, admin username (not "admin"), a strong password, and an email. Click install, and you can log in at /wp-login.php.
Production Hosting
Where you host production is a trade-off between cost, control, and how much server management you want to own.
| Type | Pros | Cons | Best for |
|---|---|---|---|
| Shared | Cheap, easy cPanel, one-click installs | Limited resources, noisy neighbours | Small blogs, low traffic |
| VPS | Dedicated resources, root access | You manage security & updates | Mid-size sites needing control |
| Managed WP | WP-tuned, auto-updates, staging, support | Pricier, some plugin restrictions | Business-critical sites |
| Cloud (IaaS) | Highly scalable, pay-as-you-go | Needs DevOps skills | Enterprise, variable traffic |
π‘ Recommended production baseline
PHP 8.2+, MySQL 8.0+/MariaDB 10.5+, PHP memory limit 256MB, max execution time 60s, upload max 32MB+, Apache with mod_rewrite or Nginx (for pretty permalinks), and a valid SSL certificate. Check yours under Tools β Site Health.
Configuring wp-config.php
wp-config.php is mission control. Beyond the database block, a handful of constants shape debugging, security, and performance β and they should differ by environment.
Debugging (development only)
<?php
define( 'WP_DEBUG', true ); // turn on error reporting
define( 'WP_DEBUG_LOG', true ); // write to wp-content/debug.log
define( 'WP_DEBUG_DISPLAY', false ); // don't show errors to visitors
define( 'SCRIPT_DEBUG', true ); // load unminified core CSS/JS
Performance & housekeeping
<?php
define( 'WP_MEMORY_LIMIT', '256M' );
define( 'WP_POST_REVISIONS', 5 ); // cap revisions instead of unlimited
define( 'AUTOSAVE_INTERVAL', 160 ); // seconds between autosaves
define( 'DISALLOW_FILE_EDIT', true );// disable the built-in code editor
Environment type
Modern WordPress exposes wp_get_environment_type(), driven by this constant. Use it to branch settings:
<?php
define( 'WP_ENVIRONMENT_TYPE', 'development' ); // or 'staging' / 'production'
switch ( wp_get_environment_type() ) {
case 'development':
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_DISPLAY', true );
break;
case 'staging':
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_DISPLAY', false );
break;
case 'production':
define( 'WP_DEBUG', false );
define( 'DISALLOW_FILE_EDIT', true );
break;
}
β Keep secrets out of version control
Never commit real database credentials or salts. Use environment variables (or a tool like wp-config-transformer) and commit only a sanitized wp-config-sample.php. Your .gitignore should exclude wp-config.php, wp-content/uploads/, and *.log.
Security Hardening
Security is a process, not a checkbox. These measures raise the bar significantly for very little effort.
β Do
- Force HTTPS everywhere:
define( 'FORCE_SSL_ADMIN', true ); - Use a non-obvious admin username and a strong password; add two-factor auth.
- Disable the file editor:
define( 'DISALLOW_FILE_EDIT', true ); - Keep core, themes, and plugins updated; remove anything unused.
- Set file permissions to 644 (files), 755 (directories), 600 (
wp-config.php). - Run automated backups and test that you can restore them.
β οΈ Don't
- Leave debug display on in production β it leaks paths and versions.
- Stack multiple security plugins (they conflict); pick one, e.g. Wordfence or Sucuri.
- Reuse the same credentials across environments.
- Expose
wp-config.phpβ block direct access at the server level.
Example server-level protections (Apache):
# Block direct access to wp-config.php
<Files wp-config.php>
Require all denied
</Files>
# Disable XML-RPC if you don't use it
<Files xmlrpc.php>
Require all denied
</Files>
Note the modern Require all denied directive β the old order deny,allow syntax was removed in Apache 2.4.
You can also trim WordPress's public fingerprint in a theme or small plugin:
<?php
// Remove the WordPress version meta tag and feed generator.
add_filter( 'the_generator', '__return_empty_string' );
// Disable XML-RPC entirely.
add_filter( 'xmlrpc_enabled', '__return_false' );
Performance Tuning
Speed improves user experience and SEO. Optimize at three layers.
| Layer | Techniques |
|---|---|
| Server | PHP 8.2+, OPcache, object cache (Redis/Memcached), HTTP/2 or HTTP/3, Gzip/Brotli, a CDN |
| WordPress | Page-cache plugin, limit revisions, disable unused features, transients for expensive queries |
| Frontend | Optimize & lazy-load images (WebP/AVIF), minify CSS/JS, defer non-critical scripts, preconnect |
Object cache constants (Redis example)
<?php
define( 'WP_CACHE', true );
define( 'WP_REDIS_HOST', '127.0.0.1' );
define( 'WP_REDIS_PORT', 6379 );
Defer non-critical JavaScript
<?php
add_filter( 'script_loader_tag', function ( string $tag, string $handle ): string {
$defer = [ 'my-theme-script', 'analytics' ];
if ( ! is_admin() && in_array( $handle, $defer, true ) ) {
return str_replace( ' src', ' defer src', $tag );
}
return $tag;
}, 10, 2 );
π‘ Measure, then optimize
Use PageSpeed Insights, GTmetrix, or the Query Monitor plugin to find real bottlenecks before touching anything. Popular caching plugins: WP Rocket, W3 Total Cache, WP Super Cache, and LiteSpeed Cache.
Migrating Sites
Moving a site between environments is routine but error-prone. The critical, easily-forgotten step is the URL search-and-replace β done correctly so serialized data survives.
The WP-CLI way (scriptable, reliable)
# On the source: export the database
wp db export backup.sql
# On the target: import it
wp db import backup.sql
# Replace URLs safely β WP-CLI handles serialized PHP data correctly
wp search-replace 'https://old-domain.com' 'https://new-domain.com' --all-tables --skip-columns=guid
# Refresh permalinks after moving
wp rewrite flush
β οΈ Never do URL replace with plain SQL
A raw UPDATE ... REPLACE() corrupts serialized arrays (widget settings, options) because it changes string contents without fixing their stored length prefixes. Always use WP-CLI's search-replace or a serialization-aware tool like WP Migrate. Also skip the guid column β those values must stay historically stable.
Plugin and host tools
For non-CLI workflows, Duplicator, All-in-One WP Migration, and WP Migrate package files + database into a portable bundle. Managed hosts (WP Engine, Kinsta, SiteGround, Flywheel) offer one-click migrations tuned to their platform.
β Migration checklist
- Back up files and database before you start.
- Match PHP/MySQL versions between source and target when possible.
- Run a serialization-aware search-and-replace for URLs.
- Flush permalinks; test forms, media, and checkout flows.
- Lower DNS TTL beforehand to minimize cutover downtime; verify email/SMTP after.
Hands-on: Docker WordPress
ποΈ Stand up a dev site with Docker
Objective: Run a fresh WordPress locally with Docker Compose and configure it for development.
Instructions
- Create an empty folder and save the
docker-compose.ymlfrom the Local Development section into it. - Run
docker compose up -dand openhttp://localhost:8000. - Complete the install wizard with an admin user that is not "admin".
- Add the development debug constants to
wp-content-mounted config, load a page, and confirm errors log todebug.log.
π‘ Hint
With the official image, the simplest way to add constants is a small must-use plugin or a WORDPRESS_CONFIG_EXTRA environment variable in the compose file. To verify logging, temporarily call an undefined function in a mu-plugin and check wp-content/debug.log appears.
β Solution
Add the debug constants directly via the image's config-extra hook:
wordpress:
# ...as before...
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: wordpress
WORDPRESS_DB_NAME: wordpress
WORDPRESS_CONFIG_EXTRA: |
define( 'WP_ENVIRONMENT_TYPE', 'development' );
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );
docker compose down
docker compose up -d
# Trigger a notice, then read the log:
docker compose exec wordpress tail -n 20 wp-content/debug.log
Errors now write to wp-content/debug.log without ever showing to a visitor β exactly the development posture you want.
π― Quick Quiz
Question 1: For a production site, which debug setting combination is correct?
Question 2: When changing domains during a migration, why avoid a plain SQL REPLACE()?
Question 3: Which local tool gives every teammate an identical, version-controlled environment?
Summary & Quiz
π Key Takeaways
- WordPress work flows through local β staging β production; risky changes stay left.
- LocalWP is the easiest local start; Docker gives reproducible, team-shared environments.
- The manual install = create DB β configure
wp-config.php(with fresh salts) β run the wizard. wp-config.phpconstants control debugging, security, and performance β set them per environment.- Harden with HTTPS, strong logins, updates, permissions, and backups; keep secrets out of Git.
- Migrate with a serialization-aware search-and-replace (WP-CLI), then flush permalinks and test.
π Further Reading
- WordPress.org β Installation Guide
- wp-config.php Reference
- Hardening WordPress
- WP-CLI search-replace
π What's Next?
With WordPress installed and configured, you're ready to start building the front end. Next up: how themes work β the theme file structure and the template hierarchy that decides which file renders each page.
π Environment mastered!
You can now install, configure, secure, and migrate WordPress across every stage of a real project.