Skip to content

Installing WordPress on a VPS#

WordPress runs a quarter of the web for a reason: once installed properly, it keeps working. "Properly" is doing a lot of work in that sentence, and this page is about that part.

The shortcut

WordPress can be installed on a VeriTeknik VPS with one click from the panel - pick it from the application list when you order the server or afterwards.

What follows is for doing it yourself, or for understanding what happened.


0. Point the domain#

Your A record must point at the server's IP. Do this first, because the certificate step depends on it.

dig +short example.com

1. Install the packages#

sudo apt update
sudo apt install -y nginx mariadb-server php-fpm php-mysql \
  php-curl php-gd php-mbstring php-xml php-zip php-intl unzip
sudo dnf install -y nginx mariadb-server php-fpm php-mysqlnd \
  php-curl php-gd php-mbstring php-xml php-zip php-intl unzip
sudo systemctl enable --now php-fpm

With Morpheus

"install the nginx, mariadb and php packages needed for WordPress"

Morpheus detects the distribution and picks the right package names - PHP package naming differs between Debian and RHEL, and you do not need to know that.


2. Prepare the database#

sudo systemctl enable --now mariadb
sudo mysql_secure_installation

mysql_secure_installation is interactive; you have to answer its questions. Set a root password, remove anonymous users and the test database.

Morpheus will not run this

This command is deliberately blocked at Morpheus' gate: interactive commands hang a non-interactive SSH session. Do this step yourself, or have Morpheus run the equivalent SQL.

Create the database and user:

sudo mysql -e "CREATE DATABASE wordpress DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
sudo mysql -e "CREATE USER 'wpuser'@'localhost' IDENTIFIED BY 'PUT_A_STRONG_PASSWORD_HERE';"
sudo mysql -e "GRANT ALL ON wordpress.* TO 'wpuser'@'localhost';"
sudo mysql -e "FLUSH PRIVILEGES;"

Generate a genuinely strong password: openssl rand -base64 24


3. Put the files in place#

cd /tmp
curl -O https://wordpress.org/latest.tar.gz
tar xzf latest.tar.gz
sudo mkdir -p /var/www/example.com
sudo cp -r wordpress/* /var/www/example.com/
sudo chown -R www-data:www-data /var/www/example.com
sudo find /var/www/example.com -type d -exec chmod 755 {} \;
sudo find /var/www/example.com -type f -exec chmod 644 {} \;

Permissions

On Rocky/AlmaLinux the user may be nginx rather than www-data. Do not use 777 - most of the "this fixes the permission error" advice you find online actually opens your server up.


4. Nginx configuration#

server {
    listen 80;
    server_name example.com www.example.com;
    root /var/www/example.com;
    index index.php index.html;

    client_max_body_size 64M;

    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php-fpm.sock;
    }

    location ~* /(?:uploads|files)/.*\.php$ {
        deny all;
    }

    location ~ /\.(?!well-known) {
        deny all;
    }
}

The fastcgi_pass path varies by version; find yours:

ls /run/php/
sudo nginx -t && sudo systemctl reload nginx

The last two location blocks are security: they stop PHP executing from the uploads directory and block hidden files. That is the classic WordPress attack path.


5. Certificate#

sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d example.com -d www.example.com
sudo certbot renew --dry-run

6. Finish the install#

Go to https://example.com and complete the WordPress wizard using the database details from step 2.

Once done:

  • Do not name the admin user admin
  • Install a two-factor authentication plugin
  • Delete unused themes and plugins; deactivating is not enough

7. Backups and maintenance#

WordPress needs two separate things backed up: files and database.

sudo mysqldump wordpress | gzip > /opt/backup/wp-db-$(date +%F).sql.gz
sudo tar czf /opt/backup/wp-files-$(date +%F).tar.gz -C /var/www example.com

A panel snapshot covers both and is easier.

With Morpheus

"back up the wordpress database every night at 03:00 and delete backups older than 7 days"

"check whether wordpress and its plugins have updates"

Never update without a backup

WordPress core updates are usually fine; plugin updates are not always. Take a snapshot first. Snapshots take minutes; repairing a broken site by hand takes days.


Checklist#

  • [ ] https://example.com opens with the padlock
  • [ ] http:// redirects to https://
  • [ ] Admin username is not admin, 2FA enabled
  • [ ] sudo nginx -tsyntax is ok
  • [ ] PHP does not execute from the uploads directory (deny all blocks in place)
  • [ ] A backup has actually been taken and a restore tested
  • [ ] sudo certbot renew --dry-run passes
  • [ ] Unused themes and plugins deleted