Install WordPress 5 with Apache on Debian 9

This tutorial will show you how to install and configure the latest version of WordPress 5 on top of a LAMP stack in Debian 9 - Stretch. Wordpress, without a doubt, is one of the most popular open-source Content Management System or CMS used in these days for internet publishing, which powers more than 60 million websites worldwide, whether small blogging sites or notable huge name brands. Based on PHP and MySQL engine, Wordpress is often associated with LAMP collection, either installed on dedicated servers or virtual private servers or on shared web-hosting providers. LAMP acronym describes a collection of software, aka software bundle, which usually consists of Linux Open Source kernel, regardless of the chosen distribution, Apache HTTP server, which is one of the most popular open-source web server in internet due to its stability, flexibility and performance, PHP server-side interpreted programming language and MariaDB relational database management system (RDBMS), which one of the most popular database software, forked and simultaneously developed by the open-source community from original MySQL.


  • A clean installation of Debian 9 operating system on a virtual private server or a virtual machine or directly on a dedicated bare-metal machine.
  • SSH remote access in case of a VPS or a remote server or direct console access
  • At least a static IP Address for a network interface configured on the server
  • In case the webpage should be publicly available in internet you would need a registered public domain name with proper DNS records configured. During this tutorial, we’ll be using the as the example domain and a static IP address from private space, in NAT, behind the main router. The domain will be accessible from the internet by port forwarding the Apache 80 and 443 ports from the router side to internal self-hosted virtual machine LAN.

Install LAMP Software Bundle

The first thing you want to do before starting to install all LAMP components is to log in to Debian 9 server and perform an up-to-date procedure for all system components, such as kernel upgrades, package updates or security patches, by issuing the following commands with root privileges.

apt-get update
apt-get upgrade
apt-get dist-upgrade

In the next step, you should set up the name of your machine by replacing the hostname variable with your own descriptive name by running the below command. Be aware that you might need to reboot the system in order to apply the new hostname accordingly.

hostnamectl set-hostname

You should also install the following utilities which will come in handy later for various troubleshooting problems.

apt install net-tools sudo wget curl bash-completion

After the machine hostname has been applied, login again with root privileges and install Apache HTTP server, which is, by default, pre-compiled into a binary package and provided by Debian 9 repositories.

apt install apache2

Next, install the latest version of PHP language interpreter and all required modules needed for Apache web server in order to deploy Wordpress CMS by issuing the following command.

apt install libapache2-mod-php7.0 php7.0 php7.0-gd php7.0-xml php7.0-curl php7.0-mbstring php7.0-mcrypt php7.0-xmlrpc

The last component missing now in order for LAMP stack to be complete is MariaDB database server. Execute the following command to install MariaDB server alongside with PHP module required to access the database from Apache HTTP server.

apt install php7.0-mysql mariadb-server mariadb-client

After MariaDB database has been installed, start the daemon and secure the database my running mysql_secure_installation script as illustrated in the below excerpt. Mainly answer with yes on all question the script prompts you. Also, make sure you choose a strong password for root account. Be aware that MySQL root account is not identical will Linux root account. The first is used only to manage the MariaDB database and the second is the superuser account in every Linux system. These accounts never overlap in a system.

systemctl start mariadb
In order to log into MariaDB to secure it, we'll need the current
password for the root user.  If you've just installed MariaDB, and
you haven't set the root password yet, the password will be blank,
so you should just press enter here.
Enter current password for root (enter for none):
OK, successfully used password, moving on...
Setting the root password ensures that nobody can log into the MariaDB
root user without the proper authorisation.
Set root password? [Y/n] y
New password:
Re-enter new password:
Password updated successfully!
Reloading privilege tables..
 ... Success!
By default, a MariaDB installation has an anonymous user, allowing anyone
to log into MariaDB without having to have a user account created for
them.  This is intended only for testing, and to make the installation
go a bit smoother.  You should remove them before moving into a
production environment.
Remove anonymous users? [Y/n] y
 ... Success!
Normally, root should only be allowed to connect from 'localhost'.  This
ensures that someone cannot guess at the root password from the network.
Disallow root login remotely? [Y/n] y
 ... Success!
By default, MariaDB comes with a database named 'test' that anyone can
access.  This is also intended only for testing, and should be removed
before moving into a production environment.
Remove test database and access to it? [Y/n] y
 - Dropping test database...
 ... Success!
 - Removing privileges on test database...
 ... Success!
Reloading the privilege tables will ensure that all changes made so far
will take effect immediately.
Reload privilege tables now? [Y/n] y
 ... Success!
Cleaning up...
All done!  If you've completed all of the above steps, your MariaDB
installation should now be secure.
Thanks for using MariaDB!

We’re not done with securing MariaDB database yet. By default, you can log in to MariaDB from localhost with the database root account without being asked for a password. To prevent possible security issues, login to the database with root user and issue the following commands.

mysql -u root -p
MariaDB> use mysql;
MariaDB> update user set plugin='' where User='root';
MariaDB> flush privileges;
MariaDB> quit

 Remove plugin from MySQL root user

Now, test the database by trying to log in with root account without the password. You should be denied access to MariaDB database.

In the next step, we’ll enable and configure TLS and rewrite modules for Apache web server, which by default are disabled. Run the below commands to enable both modules.

a2enmod rewrite ssl
a2ensite default-ssl.conf

Then, open Apache configuration files for both enabled sites and add the following block below the DocumentRoot directive as illustrated in the following screenshot.

nano /etc/apache2/sites-enabled/000-default.conf
nano /etc/apache2/sites-enabled/default-ssl.conf

 In both configuration files add the following block of code:

    <Directory /var/www/html>
       Options Indexes FollowSymLinks MultiViews
       AllowOverride All
       Require all granted

 Grant access to /var/www/html directory and allow overrides

In apache default-ssl.conf TLS configuration file you can also add the below content, if not existing, in order to improve security of Apache SSL protocol. These lines of code should fix common SSL vulnerabilities.

SSLProtocol all -SSLv2 -SSLv3
# Add SSL Cipher in one long line
SSLHonorCipherOrder     on
SSLOptions +StrictRequire
Header always set Strict-Transport-Security "max-age=63072000; includeSubdomains"
Header always set X-Frame-Options DENY
Header always set X-Content-Type-Options nosniff

Set strict SSL settings in apache2

If the lines illustrated in the above excerpt already exist in the Apache SSL configuration file, make sure you modify them to look as described above. In order to apply these settings, enable the Apache headers module and restart the service by executing the following commands:

a2enmod headers
systemctl restart apache2.service

For a production website, it should be mandatory to enable Apache TLS module because WordPress CMS generates mostly dynamic content via PHP gateway and also handles the authentication process for its internal users. Using TLS technology guarantees that the transferred information is encrypted at both ends and that the connection is secured. A third-party or a man-in-the-middle can intercept traffic but can not decrypt the content, because the information is not delivered in plain text.

After you’ve made all the above changes, test Apache configuration in order to detect potential syntax errors and if everything is ok then restart LAMP daemons in order to reflect all changes made so far and enable the services system-wide by issuing the following commands.

apache2ctl -t
systemctl restart apache2.service mariadb.service
systemctl enable apache2.service mariadb.service

Finally, check if Apache and MariaDB services have opened ports in listening state by issuing netstat command and filter the output using egrep By now, Apache web server should have ports 80 and 443 (corresponding to HTTP and https protocols) generally exposed and MariaDB should be only binding on localhost:3306 socket. Use the -n flag against netstat command to suppress displaying service names.

netstat -tlp| egrep 'http|mysql'

 Check if MariaDB is started

To make sure your web server is accessible from the internet via HTTP and HTTPS protocols open a browser and navigate to your domain name. Browsing via HTTPS protocol, a certificate error will be displayed in the browser. This is because Apache default TLS configuration file is configured to use Self-Signed Certificates. You should accept the TLS error and continue navigating to the default web page as illustrated below. 

Apache2 test page 

Apache 2 test page in SSL mode

In case you cannot visit your domain default web page from the internet you should first verify if some firewall rules in the system are blocking the requests or make sure the proper ports on the router are forwarded into your internal LAN in case the server sits behind a NAT-ed network. You might also want to check the DNS records in your domain registrar panel and make sure they point to your WAN IP and if the records finished propagating on the internet.

In order to test if PHP is working as expected on the server side, create a PHP php in /var/www/html/ system path, which is the default web document root path of Apache web server, issuing the below command and navigate to the following URI from browser to get the result:

echo '<?php phpinfo(); ?>' > /var/www/html/info.php

 PHP info test page

Install WordPress 5.0

Now that the LAMP stack is fully configured, the installation of Wordpress CMS is relatively straightforward. First, log in to MariaDB database and create an installation database for Wordpress and a user with the proper password for installing and managing Wordpress CMS, by issuing the below commands. Feel free to replace the database name and database credentials to match your own requirements.

mysql -u root -p
GRANT ALL PRIVILEGES ON wordpress.* TO 'wordpress-user'@'localhost' IDENTIFIED BY 'wordpress-pass';

 Create WordPress MySQL database and Database User

Next, download the latest Wordpress tarball from the official website using wget utility and extract the compressed archive with tar utility. Copy the installation files to Apache web server document root path by issuing the below commands. Also, make sure you remove the default index.html webpage.

cd /tmp
tar xfz latest.tar.gz
cp -rf wordpress/* /var/www/html/
rm /var/www/html/index.html

 Download and unpack WordPress on your server

Modify the permissions of Apache webroot path as described below in order to grant web server www-data group full write permissions to the installation directory. This configuration will allow Apache web server to create or modify files and directories under this specific system path. The most important ones would be the uploads directory and .htaccess file, which can be used to control and extend Apache functionality.

chmod -R 775 /var/www/html/
chgrp -R www-data /var/www/html/
ls -al /var/www/html

 WordPress files

Now, that everything is in place, let's start to install Wordpress. The installation process will be performed from the browser. Open a browser and visit your domain via HTTPS protocol. On the first screen of the installation hit on Let’s go button to start the installation.

 WordPress web installer

In the next installation screen, add the name of the database, the database access credentials and the database host you’ve created earlier for Wordpress installation and hit the Submit button to continue. The configuration of the database will be saved in /var/www/html/wp-config.php You can manually modify the file at a later date for special Wordpress purposes.

Database settings

On the next screen click on Run the install button and fill your website title, the website admin credentials, and email address. A strong password should be automatically generated by the installation scripts. You can choose to save this password or provide your own strong password. When you’ve finished, hit Install Wordpress button to complete the installation process.

Run installation

WordPress site information

Finally, after the installation successfully completes, log in to Wordpress dashboard with the credentials created during the installation process and start managing your own website.

 WordPress Installation Success

WordPress admin login

Log into WordPress backend.

WordPress Backend

Wordpress Admin Dashboard.

Editing a post in the new WordPress Gutenberg Editor.

Wordpress 5.0 Frontend with new TwentyNineteen Theme.

Congratulations! You’ve successfully installed the latest version of Wordpress CMS on top of LAMP software bundle in Debian 9, codename Stretch.

Virtual machine image download of this tutorial

This tutorial is available as ready to use virtual machine image in ovf/ova format that is compatible with VMWare and Virtualbox. The virtual machine image uses the following login details:

SSH / Shell Login

Username: administrator
Password: howtoforge

This user has su rights.

Username: root
Password: howtoforge

WordPress Login

Username: admin
Password: howtoforge

MySQL Login

Username: root
Password: howtoforge

The IP of the VM is, it can be changed in the file /etc/network/interfaces. Please change all the above passwords to secure the virtual machine.

Share this page:

Suggested articles

5 Comment(s)

Add comment


By: Zgore

 Thanks for the tutorial, it's perfect !

By: Dirk

Great tutorial, I got it work for me too. For noobs like me there should be also an example how to open ports in the dsl router for 80 and 443 (screenshot for one router, e.g. FB7490). You mentioned it, but how to do is up to the user.

Another hint is, that when copying commands for the config files from this page, there are strange spaces inbetween. You can't see them, they look like spaces but will force apache to fail. If you copy the text into MSWord, you will identifify them, because these space are underlined. That was tricky to find. :-)

But nevertheless great work. I would never get it run without your tutorial. Thanks a lot!

By: Matt

First, thank you for the great instructions.  However, I received an error on the theme installation page:

"You won’t be able to install new themes from here yet since your install requires SFTP credentials"

I found a fix on another blog, which I listed below.  I'm not 100% if there are any other repercussions to this change, but it definitely fixed the error after the changes.

1. Add the following to /var/www/html/wp-config.php:  define('FS_METHOD', 'direct'); 2. chown -R www-data:www-data /var/www 3. find /var/www/ -type d -exec chmod 755 {} \; 4. find /var/www/ -type f -exec chmod 644 {} \; 5. Restart Apache: /etc/initid./apache2 restart

By: drako

its better if you just change the folder permissions with this command

sudo chown -R www-data:www-data /var/www

By: Cristina

Hi, thanks for the tutorial it is very helpful! However, I received an error when installing wordpress: "rm: cannot remove '/var/www/html/index.html': Permission denied". Do you have any idea what i can do to fix this? Thanks