WordPress Installation
WordPress installation within Ubuntu 20.04 (or later), Apache 2.4 and PHP 7.4. This post is based on my answer of the question WordPress Installation Failed at Ask Ubuntu, but covers only the general line.
Here we assume there is a FQDN which points to the servers public IP address and there is installed Apache2 that listen to ports 80 and 443
. As illustrational example for that FQDN we will use wp.example.com
.
Download the latest WordPress release
cd /var/www/
sudo wget https://wordpress.org/latest.tar.gz && \
sudo tar -xvzf latest.tar.gz && \
sudo rm ./latest.tar.gz*
sudo mv wordpress wp.example.com
sudo chown -R www-data:www-data wp.example.com/
sudo -u www-data mkdir wp.example.com/wp-content/uploads
sudo -u www-data cp html/favicon.ico wp.example.com/
- Change the name of the document root directory from
/var/www/wp.example.com
to the name of the actual directory in use.
Create MySQL Database for the new WordPress instance
For MariaDB read the article: Migrate MySQL to MariaDB.
sudo mysql
CREATE DATABASE wp_example_com;
CREATE USER 'wp_example_com_user'@'localhost' IDENTIFIED WITH mysql_native_password BY '<your-strong-password>';
GRANT ALL PRIVILEGES ON wp_example_com.* TO 'wp_example_com_user'@'localhost' WITH GRANT OPTION;
FLUSH PRIVILEGES;
exit
- Replace
wp_example_com
with the actual database name in use. - Replace
wp_example_com_user
with the actual database username in use. - Replace
<your-strong-password>
with an actual strong password.
Create LetsEncrypt certificate for the new WordPress instance
Disable ModSecurity (it it is enabled) for a while. It could block Let's encrypt authentication engine when there are not appropriate exception rules.
sudo a2dismod security2 && sudo systemctl restart apache2.service
Generate a certificate for wp.example.com
– replace it with the actual FQDN in use (you could add the option –rsa-key-size 4096
if you think this could bring more security).
sudo letsencrypt certonly --apache --email admin@wp.example.com -d wp.example.com
Alternatively you could create wildcard certificat by a command as the follow.
sudo letsencrypt certonly --email admin@example --apache \
--preferred-challenges=dns -d example -d *.example
Enable ModSecurity – it is not presented you could do systemctl reload apache2.service
instead restarting it.
sudo a2enmod security2 && sudo systemctl restart apache2.service
More commands.
- List of all certificates:
sudo letsencrypt certificates
- Remove a certificate:
sudo letsencrypt delete --cert-name example.com
- Remove all certificates:
sudo letsencrypt delete
Create Apache2 Virtual Host for the new WordPress instance
sudo nano /etc/apache2/sites-available/wp.example.com.conf
<VirtualHost *:80>
ServerName wp.example.com
ServerAlias www.wp.example.com
ServerAdmin support@wp.example.com
# Redirect Requests to HTTPS
Redirect permanent "/" "https://wp.example.com/"
ErrorLog ${APACHE_LOG_DIR}/wp.example.com.error.log
CustomLog ${APACHE_LOG_DIR}/wp.example.com.access.log combined
</VirtualHost>
<IfModule mod_ssl.c>
<VirtualHost _default_:443>
ServerName wp.example.com
ServerAlias www.wp.example.com
ServerAdmin support@wp.example.com
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP_HOST} www.wp.example.com$ [NC]
RewriteRule ^(.*)$ https://wp.example.com/$1 [R=301,NC,L]
</IfModule>
ErrorLog ${APACHE_LOG_DIR}/wp.example.com.error.log
CustomLog ${APACHE_LOG_DIR}/wp.example.com.access.log combined
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/wp.example.com/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/wp.example.com/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/wp.example.com/chain.pem
#SSLCertificateChainFile /etc/letsencrypt/live/wp.example.com/fullchain.pem
<IfModule pagespeed_module>
# For the dev stage
ModPagespeed off
</IfModule>
Define newIinstanceWP_DocumentRoot "/var/www/wp.example.com"
DocumentRoot "${newIinstanceWP_DocumentRoot}"
<Directory "${newIinstanceWP_DocumentRoot}">
DirectoryIndex index.php
Options None FollowSymLinks
Require all granted
#AllowOverride None
AllowOverride All
<IfModule security2_module>
# For the dev stage
SecRuleEngine Off
</IfModule>
</Directory>
<Location />
# For the dev stage
#Require ip 172.16.1.0/24
#Require ip 192.168.1.0/24
</Location>
<LocationMatch "/wp-admin/admin-ajax.php">
<IfModule security2_module>
SecRequestBodyNoFilesLimit 1310720
SecRequestBodyInMemoryLimit 1310720
</IfModule>
</LocationMatch>
<LocationMatch "/wp-admin/post.php">
<IfModule security2_module>
SecRequestBodyLimit 131072000
SecRequestBodyNoFilesLimit 1310720
SecRequestBodyInMemoryLimit 1310720
</IfModule>
</LocationMatch>
# The following section is according to this scarnnr response:
# https://securityheaders.com/?q=szs.space&followRedirects=on
# https://scotthelme.co.uk/hsts-the-missing-link-in-tls/
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains"
# https://scotthelme.co.uk/content-security-policy-an-introduction/
# https://content-security-policy.com/
# https://www.mediawiki.org/wiki/Requests_for_comment/Content-Security-Policy
#Header set Content-Security-Policy "default-src 'self'"
#Header set Content-Security-Policy "script-src 'self'"
#Header set Content-Security-Policy "default-src https://"
# https://scotthelme.co.uk/a-new-security-header-referrer-policy/
#Header always set Referrer-Policy "same-origin"
#Header set Access-Control-Allow-Origin "*"
#Header set X-Frame-Options "allow-from youtube.com"
# https://scotthelme.co.uk/a-new-security-header-feature-policy/
Header always set Feature-Policy "microphone 'none'; payment 'none'; sync-xhr 'self' https://wp.example.com"
</VirtualHost>
</IfModule>
- Replace the name of the configuration file from
wp.example.com.conf
to an actual name. - Replace
wp.example.com
andwww.wp.example.com
with the actual FQDNs in use. - Replace the name of the variable
newIinstanceWP_DocumentRoot
with something else. - Replace the name of the document root directory from
/var/www/wp.example.com.wp
to the name of the actual directory in use.
sudo a2ensite wp.example.com.conf
sudo systemctl restart apache2.service
Setup the new WordPress instance via the Web interface
WP-CLI Setup
Installation.
cd /tmp && \
curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
php wp-cli.phar --info
chmod +x wp-cli.phar
sudo mv wp-cli.phar /usr/local/bin/wp
Update.
sudo wp cli update
Tab completions.
# https://raw.githubusercontent.com/wp-cli/wp-cli/v2.5.0/utils/wp-completion.bash
cd /tmp && \
curl -O https://raw.githubusercontent.com/wp-cli/wp-cli/master/utils/wp-completion.bash && \
sudo mv wp-completion.bash /usr/local/bin/
cat << EOF | tee -a ~/.profile
# wp-cli tab completions, https://wp-cli.org/
. /usr/local/bin/wp-completion.bash
EOF
References:
- https://wp-cli.org/
- https://make.wordpress.org/cli/handbook/guides/installing/