VPS & Servers

How to Install WordPress on an Ubuntu Server

Install WordPress on your own VPS: database, files, permissions, virtual host, SSL and security keys — plus an honest look at whether it beats shared hosting.

WordPress being installed on an Ubuntu server

Installing WordPress on your own Ubuntu server takes about thirty minutes and gives you full control: your own PHP settings, no neighbours slowing you down, and no host deciding what you may install.

It also makes you the system administrator. Before you start, it is worth being honest about whether that trade is right for you.

Is this better than shared hosting?

Your own VPSShared hosting
SpeedMuch fasterDepends on neighbours
ControlCompleteWhatever cPanel allows
Security updatesYour jobHost handles the server
When it breaks at 2amYour problemTheir support
Cost$5–10 / month$3–5 / month

Choose a VPS if you want to learn server administration, run several sites, or need settings shared hosting will not give you.

Choose shared hosting if the site matters commercially and you do not want to be responsible for patching the operating system. That is a perfectly reasonable answer — see the cPanel route instead.

Before you start

You need a working LAMP stack. If you do not have one, follow how to install a LAMP server on Ubuntu first — it covers creating a non-root user and setting the firewall, both of which matter here.

You also need a domain already pointing at the server IP. Check:

dig +short yourdomain.com

Step 1: Install the PHP extensions WordPress needs

A base LAMP install is not enough. Missing extensions cause blank pages and broken media uploads.

sudo apt update
sudo apt install php-curl php-gd php-mbstring php-xml php-zip php-intl php-imagick -y
sudo systemctl restart apache2

Step 2: Create the database

sudo mysql
CREATE DATABASE wordpress DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'wpuser'@'localhost' IDENTIFIED BY 'a-long-random-password';
GRANT ALL ON wordpress.* TO 'wpuser'@'localhost';
FLUSH PRIVILEGES;
EXIT;

Use utf8mb4. Without it, emoji and non-Latin characters in posts break.

Step 3: Download WordPress

cd /tmp
curl -O https://wordpress.org/latest.tar.gz
tar xzvf latest.tar.gz
sudo mkdir -p /var/www/yourdomain.com
sudo cp -a /tmp/wordpress/. /var/www/yourdomain.com/

The -a flag copies hidden files too. Plain cp -r misses .htaccess, which then breaks permalinks in a way that is hard to trace.

Step 4: Set the permissions correctly

This step causes more trouble than any other, and the usual bad advice is to run chmod 777. Never do that — it lets any user on the server write to your site.

sudo chown -R www-data:www-data /var/www/yourdomain.com
sudo find /var/www/yourdomain.com -type d -exec chmod 755 {} \;
sudo find /var/www/yourdomain.com -type f -exec chmod 644 {} \;

That gives directories 755 and files 644, which is what WordPress actually wants. Apache runs as www-data, so it can write uploads and update plugins, and nobody else can.

Step 5: Apache virtual host

sudo nano /etc/apache2/sites-available/yourdomain.com.conf
<VirtualHost *:80>
    ServerName yourdomain.com
    ServerAlias www.yourdomain.com
    DocumentRoot /var/www/yourdomain.com

    <Directory /var/www/yourdomain.com>
        AllowOverride All
        Require all granted
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/yourdomain_error.log
    CustomLog ${APACHE_LOG_DIR}/yourdomain_access.log combined
</VirtualHost>

AllowOverride All is essential. Without it WordPress ignores .htaccess and every page except the homepage returns 404.

sudo a2ensite yourdomain.com.conf
sudo a2dissite 000-default.conf
sudo a2enmod rewrite
sudo apache2ctl configtest
sudo systemctl restart apache2

Step 6: SSL before the installer

Do this now, not later. Installing WordPress over HTTP stores http:// URLs in the database and you then have to clean them out.

sudo apt install certbot python3-certbot-apache -y
sudo certbot --apache -d yourdomain.com -d www.yourdomain.com

Say yes to the HTTPS redirect. Details in the SSL guide.

Step 7: Configure wp-config.php

cd /var/www/yourdomain.com
sudo cp wp-config-sample.php wp-config.php
sudo nano wp-config.php

Set the database details:

define( 'DB_NAME', 'wordpress' );
define( 'DB_USER', 'wpuser' );
define( 'DB_PASSWORD', 'your-password' );
define( 'DB_HOST', 'localhost' );

The security keys — do not skip this

Further down is a block of "Authentication Unique Keys and Salts" full of placeholder text. These encrypt login cookies. Left as the default, session hijacking becomes far easier.

Generate real ones:

curl -s https://api.wordpress.org/secret-key/1.1/salt/

Replace the whole placeholder block with what that returns.

Two more worth adding

define( 'DISALLOW_FILE_EDIT', true );
define( 'WP_DEBUG', false );

The first removes the plugin and theme file editor from wp-admin. If an attacker gets into your dashboard, that editor is how a site turns into a permanent back door.

Step 8: Run the installer

Open https://yourdomain.com:

  • Site title
  • Username — not "admin". Every bot tries that first.
  • Password — long and random
  • Email — one you actually read

Then log in at /wp-admin and immediately set Settings → Permalinks → Post name.

Step 9: Server-side hardening

Four things shared hosting would normally do for you:

Protect wp-config.php

<Files wp-config.php>
    Require all denied
</Files>

Add that to .htaccess in the site root.

Stop PHP running inside uploads

Create /var/www/yourdomain.com/wp-content/uploads/.htaccess:

<FilesMatch "\.php$">
    Require all denied
</FilesMatch>

If someone ever uploads a PHP file through a plugin vulnerability, this stops it executing.

Automatic security updates

sudo apt install unattended-upgrades -y
sudo dpkg-reconfigure --priority=low unattended-upgrades

Set up backups

Database and the wp-content folder, both. Nobody else is doing this for you now.

mysqldump -u wpuser -p wordpress > ~/wp-backup-$(date +%F).sql

Common problems

"Error establishing a database connection"

Wrong credentials in wp-config.php, or MySQL is not running. Test the login directly:

mysql -u wpuser -p wordpress

Every page except the homepage returns 404

AllowOverride All is missing from the virtual host, or mod_rewrite is not enabled. Both are needed. Then re-save permalinks.

WordPress asks for FTP details when installing a plugin

It cannot write to its own folders. Fix ownership:

sudo chown -R www-data:www-data /var/www/yourdomain.com

Media uploads fail

Either permissions on wp-content/uploads, or PHP limits. Raise upload_max_filesize and post_max_size in php.ini and restart Apache.

The white screen of death

A PHP fatal error. Read the real cause:

sudo tail -f /var/log/apache2/yourdomain_error.log

See the whitelabel error guide.

The site is slow

A default Apache and PHP setup is not tuned. Add a caching plugin and consider switching PHP to FPM. See how to increase WordPress speed.

Where to go next

Questions people ask

Is a VPS better than shared hosting for WordPress?
A VPS is faster and gives full control, but you become responsible for security updates and for fixing it when it breaks. Shared hosting is slower and more restricted, but the host patches the server. Choose a VPS to learn or to run several sites; choose shared hosting if the site matters commercially and you do not want that responsibility.
What file permissions should WordPress have?
Directories 755, files 644, owned by www-data. Never use 777 — that lets any user on the server write to your site. Set ownership with chown -R www-data:www-data and use find with -type d and -type f to apply the two modes separately.
Why does every page except my homepage show 404?
AllowOverride All is missing from the Apache virtual host, or mod_rewrite is not enabled. Both are required for WordPress permalinks. Fix them, restart Apache, then re-save Settings then Permalinks.
Why does WordPress ask for FTP details when I install a plugin?
It cannot write to its own directories. Run chown -R www-data:www-data on the site folder so the web server owns the files. This is a permissions problem, not a WordPress setting.
What are the WordPress security keys and do they matter?
They are the salts in wp-config.php that encrypt login cookies. Left as the placeholder text they ship with, session hijacking becomes much easier. Generate real ones from the WordPress secret-key API and replace the whole block.
Should I install SSL before or after WordPress?
Before. Installing over HTTP stores http URLs throughout the database, and you then have to run a search and replace to clean them out. Getting the certificate first avoids that entirely.
What is DISALLOW_FILE_EDIT and should I use it?
It removes the plugin and theme file editor from the WordPress dashboard. Add it. If an attacker ever gets into your admin area, that editor is the quickest way for them to turn the site into a permanent back door.
Why does "Error establishing a database connection" appear?
Wrong credentials in wp-config.php, or MySQL is not running. Test the login directly with mysql -u wpuser -p wordpress. If that fails, the problem is the database user, not WordPress.
How do I back up WordPress on my own server?
Two things: the database with mysqldump, and the wp-content folder which holds uploads, themes and plugins. On a VPS nobody else is doing this for you, so schedule it and test a restore at least once.
Why is WordPress slow on my new VPS?
A default Apache and PHP install is not tuned for WordPress. Add a caching plugin, consider switching PHP to FPM, and make sure images are compressed. A fresh VPS is not automatically fast.

Written by Habib Baloch

I build Android apps, websites and Ubuntu servers, and write down exactly how I did it.

Ask me about this guide →