Skip to main content

βš™οΈ 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.

flowchart LR A[Local<br/>build & experiment] -->|push| B[Staging<br/>review & test] B -->|deploy| C[Production<br/>live users] C -.->|clone data back| A
EnvironmentPurposeWho sees itTypical tools
LocalBuild and experiment freelyJust youLocalWP, Docker, XAMPP
StagingReview & test in a production-like copyTeam & clientsHost staging tools, subdomain
ProductionServe real traffic reliablyThe publicManaged/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.

  1. Download and install LocalWP.
  2. Click + Create a new site and follow the wizard.
  3. Pick a name, choose Preferred or custom (PHP 8.2, MySQL 8) settings, and set an admin user that is not "admin".
  4. 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, gd or imagick, mbstring, xml, zip, curl
  • HTTPS support (an SSL certificate) β€” expected for every site today
sequenceDiagram participant U as You participant S as Server participant DB as Database U->>S: Upload WordPress files U->>DB: Create database & user U->>S: Edit wp-config.php U->>S: Open the site in a browser S->>DB: Test connection S->>U: Show setup form U->>S: Submit site info S->>DB: Create tables & seed data S->>U: Installation complete

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.

TypeProsConsBest for
SharedCheap, easy cPanel, one-click installsLimited resources, noisy neighboursSmall blogs, low traffic
VPSDedicated resources, root accessYou manage security & updatesMid-size sites needing control
Managed WPWP-tuned, auto-updates, staging, supportPricier, some plugin restrictionsBusiness-critical sites
Cloud (IaaS)Highly scalable, pay-as-you-goNeeds DevOps skillsEnterprise, 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.

LayerTechniques
ServerPHP 8.2+, OPcache, object cache (Redis/Memcached), HTTP/2 or HTTP/3, Gzip/Brotli, a CDN
WordPressPage-cache plugin, limit revisions, disable unused features, transients for expensive queries
FrontendOptimize & 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

  1. Create an empty folder and save the docker-compose.yml from the Local Development section into it.
  2. Run docker compose up -d and open http://localhost:8000.
  3. Complete the install wizard with an admin user that is not "admin".
  4. Add the development debug constants to wp-content-mounted config, load a page, and confirm errors log to debug.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.php constants 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

πŸš€ 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.