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.comopens with the padlock - [ ]
http://redirects tohttps:// - [ ] Admin username is not
admin, 2FA enabled - [ ]
sudo nginx -t→syntax is ok - [ ] PHP does not execute from the uploads directory (
deny allblocks in place) - [ ] A backup has actually been taken and a restore tested
- [ ]
sudo certbot renew --dry-runpasses - [ ] Unused themes and plugins deleted