itsez.dev
๐Ÿ“–Tutorial

How to install WordPress on a VPS

2026-07-30ยท4 min readยทContent & CMS

Running WordPress on your own VPS gives you control over the application, database and backups. This tutorial deploys the official WordPress and MySQL containers with Docker Compose, puts them behind HTTPS and explains the first configuration and maintenance tasks.

Prerequisites

Prepare a fresh Ubuntu 22.04 or 24.04 VPS with SSH access, a public IP and at least 2 GB of RAM. Use more memory if you expect several plugins, frequent image processing or concurrent editors. Create an A record such as www.example.com pointing to the server and make sure the provider firewall allows SSH, HTTP and HTTPS.

You also need a local SSH client, Docker knowledge and a backup destination outside the VPS. WordPress is easy to start and easy to lose if the database and uploads are not copied somewhere else.

Step 1, Connecting to your server

Connect and update the host:

ssh root@SERVER_IP
apt update && apt upgrade -y
apt install -y ca-certificates curl

Create a dedicated directory with restricted permissions:

mkdir -p /opt/wordpress
cd /opt/wordpress
chmod 750 /opt/wordpress

Do not run WordPress from your home directory if other users can access it. Keep the Compose file and environment file readable only by administrators.

Step 2, Installing Docker and Docker Compose

Install Docker Engine and the Compose plugin by following Docker's current Ubuntu instructions. Verify the runtime before creating the stack:

docker --version
docker compose version
systemctl enable --now docker

The Compose plugin is invoked as docker compose, not necessarily as the older docker-compose binary. Prefer the current command so that the same file works with a supported Docker installation.

Step 3, Running WordPress with Docker Compose

Create an .env file and replace every placeholder before starting. Keep this file out of Git and use long random values for both database passwords:

MYSQL_DATABASE=wordpress
MYSQL_USER=wordpress
MYSQL_PASSWORD=REPLACE_WITH_A_RANDOM_VALUE
MYSQL_ROOT_PASSWORD=REPLACE_WITH_ANOTHER_RANDOM_VALUE
WORDPRESS_DB_HOST=db:3306
WORDPRESS_DB_NAME=wordpress
WORDPRESS_DB_USER=wordpress
WORDPRESS_DB_PASSWORD=REPLACE_WITH_A_RANDOM_VALUE

Create compose.yaml:

services:
  db:
    image: mysql:8.0
    restart: unless-stopped
    environment:
      MYSQL_DATABASE: ${MYSQL_DATABASE}
      MYSQL_USER: ${MYSQL_USER}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_RANDOM_ROOT_PASSWORD: '1'
    volumes:
      - db_data:/var/lib/mysql

  wordpress:
    image: wordpress:latest
    restart: unless-stopped
    depends_on:
      - db
    environment:
      WORDPRESS_DB_HOST: ${WORDPRESS_DB_HOST}
      WORDPRESS_DB_NAME: ${WORDPRESS_DB_NAME}
      WORDPRESS_DB_USER: ${WORDPRESS_DB_USER}
      WORDPRESS_DB_PASSWORD: ${WORDPRESS_DB_PASSWORD}
    ports:
      - "127.0.0.1:8080:80"
    volumes:
      - wordpress_data:/var/www/html

volumes:
  db_data:
  wordpress_data:

The default wordpress:latest image bundles Apache and is suitable for most setups. Beginners should start with this image. The fpm variant requires an external web server; if you switch to it, never publish port 9000 to the host โ€” exposing the FPM socket is a security risk.

Since March 2021 the official WordPress Docker image automatically generates wp-config.php from the supplied environment variables on first start. Do not create or edit this file inside the container โ€” configure WordPress entirely through environment variables.

Start the stack and check its state:

docker compose up -d
docker compose ps
docker compose logs --tail 100 wordpress

The database can take a moment to accept connections. Do not delete db_data while diagnosing a connection error.

Step 4, Configuring the reverse proxy

The WordPress container listens only on localhost port 8080, so it is not directly exposed to the internet. Put it behind a host proxy such as Caddy or Nginx, or use the proxy already provided by your VPS platform. The proxy should forward requests for www.example.com to 127.0.0.1:8080 and obtain a certificate through its supported ACME workflow.

Open ports 80 and 443 in the provider firewall and the host firewall. Keep port 8080 closed publicly. Configure WordPress's site URL with the final HTTPS address during the browser setup, otherwise login cookies and redirects can use the wrong scheme. If WordPress sits behind an HTTPS proxy, the reverse proxy must forward the X-Forwarded-Proto header so that WordPress generates correct HTTPS links. Without it the login page and admin redirects cause infinite redirect loops.

Step 5, First access and initial setup

Visit https://www.example.com. Choose the language, set the site title and create the administrator account with a unique password. Delete any unused sample content, update the permalink structure and install only plugins you have reviewed.

Set the correct timezone and check that media uploads work. If the site is behind a proxy, verify that the dashboard reports HTTPS and that canonical redirects do not loop. Create a non-administrator editor account for routine publishing.

Maintenance

Back up both named volumes โ€” wordpress_data (themes, plugins, uploads) and db_data (database) โ€” as well as the Compose file and .env file through a protected process. Test restoring the database and uploads on a separate machine. Update WordPress, plugins and images in a maintenance window, and read compatibility notes before changing the MySQL major version.

Watch disk, memory and container logs. If the site becomes unavailable, inspect docker compose ps, the WordPress logs and the database logs before restarting everything. A restart can hide the first useful error.

Tools mentioned

WordPress

โ†—

Open-source CMS powering a large portion of the web, with plugins, themes and a built-in block editor.

FreeNo cardOSS

Completely free self-hosted software. Host it anywhere with PHP and MySQL.

ABOUT US

Honest, independent, no fluff.

No paid placements. Just a clear look at what this does, what it costs, and what to know before you commit.

Read moreโ†’

FAQ

Questions, answered.

How much RAM does a small WordPress site need?๏ผ‹

A small site can start with 2 GB of RAM, but traffic, plugins and image processing may require more. Monitor memory before increasing limits.

Should WordPress use MySQL or MariaDB?๏ผ‹

Use a database image supported by the current WordPress documentation and pin a compatible major version. Do not upgrade the database blindly.

Where are WordPress uploads stored?๏ผ‹

Store them in a persistent Docker volume or a separate backup target. The container filesystem is not a backup.