WordPress Installation: Difference between revisions
mNo edit summary |
m (Text replacement - "mlw-continue" to "code-continue") |
||
(One intermediate revision by the same user not shown) | |||
Line 170: | Line 170: | ||
* Replace the name of the variable <code>newIinstanceWP_DocumentRoot</code> with something else. | * Replace the name of the variable <code>newIinstanceWP_DocumentRoot</code> with something else. | ||
* Replace the name of the document root directory from <code>/var/www/wp.example.com.wp</code> to the name of the actual directory in use. | * Replace the name of the document root directory from <code>/var/www/wp.example.com.wp</code> to the name of the actual directory in use. | ||
<syntaxhighlight lang="shell" line="1" class=" | <syntaxhighlight lang="shell" line="1" class="border-top-gray-next code-continue"> | ||
sudo a2ensite wp.example.com.conf | sudo a2ensite wp.example.com.conf | ||
</syntaxhighlight> | </syntaxhighlight> | ||
<syntaxhighlight lang="shell" line="1" class=" | <syntaxhighlight lang="shell" line="1" class="code-continue-padding-top-07em"> | ||
sudo systemctl restart apache2.service | sudo systemctl restart apache2.service | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Line 350: | Line 350: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
=== Tab completions === | === Tab completions === | ||
<syntaxhighlight lang="bash" class=" | <syntaxhighlight lang="bash" class="code-continue"> | ||
# https://raw.githubusercontent.com/wp-cli/wp-cli/v2.5.0/utils/wp-completion.bash | # https://raw.githubusercontent.com/wp-cli/wp-cli/v2.5.0/utils/wp-completion.bash | ||
</syntaxhighlight><syntaxhighlight lang="shell" line="1"> | </syntaxhighlight><syntaxhighlight lang="shell" line="1"> |
Latest revision as of 07:30, 26 September 2022
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
In addition you cold tweak the cache policy by adding the following code into the .htaacctes
file of the instance (by using an extension or manually) or into the virtual host configuration file.
sudo nano /var/www/wp.example.com/.htaccess
# BEGIN WordPress
# The directives (lines) between "BEGIN WordPress" and "END WordPress" are
# dynamically generated, and should only be modified via WordPress filters.
# Any changes to the directives between these markers will be overwritten.
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
# Compress content before it is delivered to the client
# https://httpd.apache.org/docs/current/mod/mod_deflate.html
<IfModule mod_deflate.c>
# Compress HTML, CSS, JavaScript, Text, XML and fonts
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/vnd.ms-fontobject
AddOutputFilterByType DEFLATE application/x-font
AddOutputFilterByType DEFLATE application/x-font-opentype
AddOutputFilterByType DEFLATE application/x-font-otf
AddOutputFilterByType DEFLATE application/x-font-truetype
AddOutputFilterByType DEFLATE application/x-font-ttf
AddOutputFilterByType DEFLATE application/x-javascript
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE font/opentype
AddOutputFilterByType DEFLATE font/otf
AddOutputFilterByType DEFLATE font/ttf
AddOutputFilterByType DEFLATE image/svg+xml
AddOutputFilterByType DEFLATE image/x-icon
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/javascript
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/xml
# Remove browser bugs (only needed for really old browsers)
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4\.0[678] no-gzip
BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
Header append Vary User-Agent
</IfModule>
# BEGIN CACHE POLICY
# Source: the default settings of WP-HUMMINGBIRD-CACHING
<IfModule mod_headers.c>
Header set Cache-Control "max-age=31536000"
<FilesMatch "\.(txt|xml|js)$">
Header set Cache-Control "max-age=31536000"
</FilesMatch>
<FilesMatch "\.(css)$">
Header set Cache-Control "max-age=31536000"
</FilesMatch>
<FilesMatch "\.(flv|ico|pdf|avi|mov|ppt|doc|mp3|wmv|wav|mp4|m4v|ogg|webm|aac|eot|ttf|otf|woff|woff2|svg)$">
Header set Cache-Control "max-age=31536000"
</FilesMatch>
<FilesMatch "\.(jpg|jpeg|png|gif|swf|webp)$">
Header set Cache-Control "max-age=31536000"
</FilesMatch>
</IfModule>
<IfModule mod_expires.c>
ExpiresActive On
#ExpiresDefault A0
ExpiresDefault A31536000
<FilesMatch "\.(txt|xml|js)$">
ExpiresDefault A31536000
</FilesMatch>
<FilesMatch "\.(css)$">
ExpiresDefault A31536000
</FilesMatch>
<FilesMatch "\.(flv|ico|pdf|avi|mov|ppt|doc|mp3|wmv|wav|mp4|m4v|ogg|webm|aac|eot|ttf|otf|woff|woff2|svg)$">
ExpiresDefault A31536000
</FilesMatch>
<FilesMatch "\.(jpg|jpeg|png|gif|swf|webp)$">
ExpiresDefault A31536000
</FilesMatch>
</IfModule>
# An alternative of the above
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType text/css A31536000
ExpiresByType text/x-component A31536000
ExpiresByType application/x-javascript A31536000
ExpiresByType application/javascript A31536000
ExpiresByType text/javascript A31536000
ExpiresByType text/x-js A31536000
ExpiresByType text/html A3600
ExpiresByType text/richtext A3600
ExpiresByType text/plain A3600
ExpiresByType text/xsd A3600
ExpiresByType text/xsl A3600
ExpiresByType text/xml A3600
ExpiresByType video/asf A31536000
ExpiresByType video/avi A31536000
ExpiresByType image/bmp A31536000
ExpiresByType application/java A31536000
ExpiresByType video/divx A31536000
ExpiresByType application/msword A31536000
ExpiresByType image/gif A31536000
ExpiresByType application/x-gzip A31536000
ExpiresByType image/x-icon A31536000
ExpiresByType image/jpeg A31536000
ExpiresByType image/webp A31536000
ExpiresByType application/json A31536000
ExpiresByType audio/midi A31536000
ExpiresByType video/quicktime A31536000
ExpiresByType audio/mpeg A31536000
ExpiresByType video/mp4 A31536000
ExpiresByType video/mpeg A31536000
ExpiresByType video/webm A31536000
ExpiresByType application/x-font-otf A31536000
ExpiresByType audio/ogg A31536000
ExpiresByType application/pdf A31536000
ExpiresByType image/png A31536000
ExpiresByType audio/x-realaudio A31536000
ExpiresByType image/svg+xml A31536000
ExpiresByType application/x-shockwave-flash A31536000
ExpiresByType application/x-tar A31536000
ExpiresByType image/tiff A31536000
ExpiresByType application/x-font-ttf A31536000
ExpiresByType audio/wav A31536000
ExpiresByType audio/wma A31536000
ExpiresByType application/font-woff A31536000
ExpiresByType application/font-woff2 A31536000
ExpiresByType application/zip A31536000
</IfModule>
# END CACHE POLICY
Setup the new WordPress instance via the Web interface
WP-CLI Setup
WP-CLI is the command-line interface for WordPress. You can update plugins, configure multisite installations and much more, without using a web browser.
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/