Installing and securing Wordpress from scratch
In the next article we cover multiple topics related with Wordpress. It could be used as a full guide or as a reference related to a specific subject.
All technical instructions are specified for Debian 9 (stretch).
Date of last update December 6th, 2019 Here is the index with all points:
- Secure installation
- Virtual hosts configuration
- Let’s Encrypt setup
- Enabling HTTPS in Wordpress
- Hardening Wordpress
- Multiple Wordpress with different domains
- Backup
- References
Secure installation
We could find online thousands of tutorials covering this topic, but it’s hard to find one where you don’t install old (and unsecure) software.
Main problem here is PHP version hosted in repositories. Usually, the standard installation will be 5.6.x (maybe 7.0.x if you are lucky), which is a kind of lottery in terms of security. Unless you need a extremely specific version because of plugins you’ll need for Wordpress, you should install the latest version available.
Here is a summary of all steps for a fresh installation, including PHP 7.3.
Core packages
Preparing MySQL database
Although this step could be considered as part of hardening, it’s mandatory to perform it in the installation phase, due of the final Wordpress configuration.
First, we need to create a new database and a new user with privileges:
I suggest to use mnemonic names related to the blog but, at the same time, hard to guess by an attacker. For example, if our website is https://www.cellphonereviews.com
, one customization could be cprevs_db
(database) and adm_cpr
(username).
PHP 7.3
If we perform a search like apt-cache search php7.3
, probably we will get no results. In this case, we have to add a new repository to our sources list:
Now install the last version of PHP hosted in the added repository:
Check the version is the expected one with php -v
.
Wordpress
Download with wget
or curl
the last version of Wordpress:
Now you can open a browser, navigate to http://<your_ip_address>/wordpress
and perform the final installation with Wordpress’ wizard.
As we saw in the previous step Preparing MySQL database, here is another hardening chance to secure our installation. When the Wordpress’ wizard will ask for a database prefix, instead of leave wp_
, we could set whatever we want. Related to the previous example (https://www.cellphonereviews.com
), some options could be cprwp_
or rpc570_
.
Virtual hosts configuration
Fresh Apache2 installations includes a 000-default.conf
site enabled, allowing HTTP access to files under /var/www/html
. But, if we store all Wordpress files on a subfolder or other path, we could get some display issues (or even disclose information of our system).
On Let’s Encrypt setup step we will get a brand-new configuration site. For now, we need an initial configuration which will be upgraded later. We can edit 000-default.conf
or create a new one (if you choose this option, don’t forget to enable with a2ensite
!):
Our starting configuration will be the next one:
Lets Encrypt setup
In order to enable HTTPS into Wordpress, one of the requirements (if we don’t want to get a “THIS CONNECTION IS NOT SECURE” window message) is to have installed a certificate signed by a trusted Certification Authority (CA). If we are not a big company, the best and cheapest option is use one provided by Let’s Encrypt via CertBot.
Due of development of OS and CertBot, installation instructions and requirements can be slighty different (for example, all procedure change between Debian 8 and Debian 9). Remember, this article is based on Debian 9. If you need other distribution or HTTP server, check this link to see all alternatives available.
CertBot installation and configuration
Before start, we need to enable stretch backports repository. To achieve this step, open /etc/apt/sources.list
and add the next line at the end:
deb http://deb.debian.org/debian stretch-backports main
Now we can install CertBot from backports repository:
apt-get install certbot python-certbot-apache -t stretch-backports
After installing Certbot, create a file for Let’s Encrypt to validate our domain in the ${webroot-path}/.well-known/acme-challenge directory
.
To do that, create the directory and give Apache2 access to it:
mkdir -p /var/lib/letsencrypt/.well-known
chgrp www-data /var/lib/letsencrypt
chmod g+s /var/lib/letsencrypt
Next, create a well-known challenge file and enable it with a2enconf
:
At this point, your domain should be configured with your server IP address (which is something not covered in this tutorial). Before we request the certificate, we’ll check our apache2 configuration to see all mods are enabled with the next commands:
a2enmod ssl headers http2
a2enconf well-known
Now we could execute certbot to perform some checks and get our certs:
certbot certonly --agree-tos --email admin@example.com --webroot -w /var/lib/letsencrypt/ -d example.com -d www.example.com
If everything works fine, you will get a message like:
Now it’s time to generate a Diffie–Hellman key exchange (DH) certificate to securely exchange cryptographic keys. To do that, run the commands below to generate a certificate with 2048 bit:
openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048
When it finish (it could take some time), we will update our previous apache configuration file created on step Virtual host configuration. The new one should look like the next one:
Next you will need to configure a server cache for the OCSP status information. This will be done in the Apache SSL config file:
nano /etc/apache2/mods-available/ssl.conf
# Set the location of the SSL OCSP Stapling Cache
SSLStaplingCache shmcb:/tmp/stapling_cache(128000)
Our final step is to check the auto-renew command, to see if we have to do a troubleshooting and avoid to expire our certificate. Execute the following command to test:
certbot renew --dry-run
You can add it to crontab to automatically update:
30 2 * * * /usr/bin/certbot renew & > /dev/null
Enabling HTTPS in Wordpress
In the administration panel, under Settings -> General
, we need to edit the URL of the blog. Just change the http
header into https
and apply changes.
Usually other docs and sites (like StackOverflow) talk about editing .htaccess
. Although I didn’t need it on my installation, here is the snippet with the code in case you need it:
This code (excluding IfModule
XML tags) can be added in the virtual host file instead of .htaccess
.
Note: if you are going to change Worpress configuration to use a non-default permalink option, please take a look at our issues section.
Hardening Wordpress
- https://mythemeshop.com/blog/custom-wordpress-login-url/
- Change files and directories permissions
- https://make.wordpress.org/hosting/handbook/handbook/security/
Multiple Wordpress with different domains
Although Wordpress Codex documentation covers a lot of topics, sometimes it’s hard to find (or even it doesn’t exist) the information we require for our use case. One example is how to get multiple Wordpress with different domains and different installations (it seems they focus on multisite option with one WP installation, named as Network.
Here you will a custom example where we follow all previous steps to install two Wordpress with different domains, www.myportfolio.com
and www.myhobbies.com
, and focusing only on the code we need to customize and explain:
1. Secure installation
When we configure MySQL, we should create a new database AND user, to isolate websites.
After untar zip Wordpress file, instead of move the folder, we could copy it and rename it for each website. For example:
2. Virtual hosts configuration
Every blog must have an initial virtual host configuration, specially if we want to make CertBot work. To achieve this task, we need to copy and modify the configuration file previously seen under CertBot installation and configuration, without forgetting the next points:
- Modify all variables related to new site (ServerName, ServerAlias, DocumentRoot paths…)
- Enable the site with
a2ensite
- Restart Apache
3. Let’s Encrypt setup
certbot certonly --agree-tos --email admin@example.com --webroot -w /var/lib/letsencrypt/ -d myportfolio.com -d www.myportfolio.com
certbot certonly --agree-tos --email admin@example.com --webroot -w /var/lib/letsencrypt/ -d myhobbies.com -d www.myhobbies.com
4. Enabling HTTPS in Wordpress
As showed before.
Backup
Here is a little script I’ve customized from the original one found in James Rascal’s repository.
Although here is the code, you could find the latest version here.
Issues
Here is a recopilation of usual erros I’ve found during/after a Wordpress installation.
0x00 - Let’s Encrypt repository is not signed
If you are getting an error message related to a repository which is not signed after adding it to /etc/apt/sources.list
and executing apt-get update
, probably your distribution is not a Debian 9 Stretch. You will have to look for the repository which is related to your OS and use it instead of the suggested one. I saw this problem when I tried to install on a Raspberry Pi 4.
0x01 - Wordpress is not sending emails
This issue is still being reviewed on my own instance. If you need a starting point to begin to deal with, here is a link