Z Tech Blog

Building a Website Environment - How to Build a Web Server

How to create a web server running on Debian Linux, Apache, MySQL and PHP (a LAMP Stack)

In this tutorial we will look at how to build a web server. We will build upon what was covered in my series on what goes on Inside the Cloud, and build ourselves an environment to run a website. This tutorial will cover a single server setup running the entire environment, however in later blog posts I will expand on this to create a an entire ecosystem making use of load balancers, and cloud managed services for a Content Delivery Network (CDN) and database (DB).

Website Environment

Before we begin, I’d like to cover briefly how modern-day websites work, i.e. what makes up a website’s environment.

Most websites nowadays are dynamic and use software to management content on the site. This software is known as a Content Management System (CMS). The CMS stores data, such as customer information, site content, etc. in a DB. The CMS uses an HTTPS server to processing user requests and serve web pages using the HTTPS protocol. The communication between the CMS, web server and DB is done using a programming language called PHP. And of course, all of these components must run on an Operating System (OS). When we put all these together we will have a complete web environment, which is commonly referred to as a stack.

For our purposes, to both serve as an example and for practical usage, we will strive to use open source, free components to create our environment. They keep the costs low and are secure and well maintained. The components we will use are:

  • CMS: WordPress
  • Web engine: Apache
  • Database (DB): MySQL
  • PHP
  • Operating System: Debian Linux – Ubuntu

A colloquial name for this is the LAMP stack – Linux, Apache, MySQL and PHP. This is a very common and widely used environment for both large enterprise websites and smaller businesses. CNN, in fact uses (an in-house developed version of) WordPress!

What follows is a step by step guide on setting up and configuring the environment. The guide is platform agnostic, so can be used for any Cloud provider, such as AWS. I will cover setting up the DB using specific AWS services (RDS) in a later tutorial. This tutorial assumes that a website domain has already been purchased and DNS setup to forward to the website. Furthermore, this tutorial assumes familiarity with the Linux terminal and that the firewall config and internet gateway have all been setup (i.e. the server itself is reachable from the internet). The instructions include all required Linux commands.


1.    Install and Secure Apache

1.1.  Install Apache

1.2.  Secure Apache

It is advised to do this immediately after Apache has been installed. As Apache will have installed and the web server started as part of the installation process, the index.html file and the Apache server will be reachable from the internet.

1.2.1.      Setup TLS

Transport Layer Security (TLS) encrypts data sent over the Internet to ensure unauthorised third parties (such as hackers) are unable to see what is being transmitted. TLS is a cryptographic protocol that provides end-to-end security of data sent between applications over the Internet. The encryption the TLS uses makes use of digital certificates — data files that certify the public key of the owner of the certificate, that the owner controls the domain being secured by the certificate and that the owner is trustworthy. These certificates are issued by a Certification Authority (CA). Thus, in our effort to secure our website’s communications with our visitors, we must setup TLS certification and register with a CA.

The CA we will use is letsencrypt.org – a leading provider of free certification. Let’s encrypt requires the certificate owner to verify themselves and their domain. How to do this is outside the scope of this document but will be covered by a blog post at a later time.

In order for our certification system to work, we will install an app (technically known as an ‘agent’) on our server that will communicate with the CA, update the certificates as required, and carry out the myriad tasks required to keep TLS working on our server in the back-ground. The agent we will use is called Certbot

Install certbot

Setup the SSL certification

Complete the wizard accordingly

If during this process you receive an error stating “the Client with the currently selected authenticator does not support any combination of challenges that will satisfy the CA”, then this is because the server is behind a Firewall. The reasons behind this error message and how the way to fix it works behind the scenes will be covered in a later article, but for the moment, enter the following command to fix the error:

This will complete the setup of TLS and encryption.

Test if TLS has been setup correctly

Testing is, as ever, a crucial part of building a solution, so now lets test the system. The tests we will perform are:

  • Check if TLS is carrying out encryption
  • Check if certificate renewal by the CA is being done successfully
  • Check the server is scheduled to renew the certificate every 12 hours

Check if TLS is carrying out encryption

This can be done easily via visiting the following website and entering your website’s name: https://www.ssllabs.com/ssltest/analyze.html?d=example.com&latest

Check if certificate renewal by the CA is being done successfully

Enter the following command. This command will have the agent contact the server, and conduct a test (a dry run) that will carry out all the procedure for updating the certification, and then roll back the update as an updated certificate is not needed at this point (it’s only a test!).

The text returned by the command will state if the test has been successful.

Check the server is scheduled to renew the certificate every 12 hours

Enter the following command. The table returned will contain a row stating that the certbot agent is scheduled to run within the next 12 (or 24) hours.

1.2.2.      (Optional) Enable the Server – Side Universal Firewall (UFW)

All servers come with an in built software firewall. Not all companies have policies for enabling this firewall, as they maintain a more sophisticated enterprise level firewall through a central Networks team. Additionally, maintaining a server side firewall can also lead to different configurations for each server seeping into the ecosystem, and so sometimes this option is discouraged. However, I decided to include this step for anyone that is interested.

The following commands will

  • Allow in ssh
  • Allow in apache
  • Enable ufw
  • Check that it’s active

2.    Setup the MySQL Server

In this tutorial we will be using a DB hosted on the same server – a further tutorial will be published on how to host a server on a managed Cloud service (such as AWS) and configure the webservice to use that at a later date.

The following commands will setup and install MySQL server. Follow the wizard and fill in the password details. The wizard will use the same username as that of the user currently logged into the server. However, a new password, just for the DB will be asked for.

Two important things to note:

  • Do not select the option for secure password authentication. This uses the less secure, default MySQL password storage system. By deselecting this option, the more secure system native to Debian Linux will be used.
  • Disallow remote root login (enter ‘y’ when asked). This will ensure we must authenticate via the more secure authentication systems used by Linux and cannot log in remotely to the DB without first logging onto the server the DB runs on.

3.    Install PHP

I recommend installing the following packages in addition to PHP and PHP-MySQL to provide additional utilities and tools

Enter the following installation command to install all the packages

Amend the dir.conf file so that apache searches for index.php first. This can be done by entering the following command and editing the file to change the placement of index.php so that its before index.html.

Restart Apache

Setup an info.php page to test if php is working. This will be done by creating a file called info.php in the var/www/html folder containing the text below.

Enter the following command to create the file and paste the text above into the file and save it.

4.    Install and Secure phpMyAdmin

Continuing our tutorial on how to build a webserver, we will now install and secure phpMyAdmin. phpMyAdmin is a browser based application that uses PHP to manage DBs. As our CMS uses PHP, and phpMyAdmin is lightweight and open source, we will use it to manage our DB.

phpMyadmin needs additional tools and utilities to provide full capability. The complete set of packages needed to be installed are:

  • Phpmyadmin
  • php-mbstring
  • php-gettext

The command to install all of these are

Note: During the installation, ensure that apache2 is selected in the wizard (when prompted, on the keyboard press: space bar -> tab -> enter)

Enable the mcrypt and mbstring extensions:

4.1.  Secure phpMyAdmin

As phpMyAdmin is used to manage a critical part of our environment, is web based, and if setup, can be accessed via the internet for admins based outside of our network, it is important to secure access to it. This can be done by adding another username and password (i.e. a gateway) that needs to be entered before getting to the login screen for phpMyAdmin. i.e. a credential gateway in front of phpMyAdmin.

This will be done by

  • Configuring the .htaccess file on our server to ask for the username and password
  • Then creating the username and password
  • Enabling .htaccess to over-ride files in Apache
  • Install a tool to create the password

4.1.1.      Configure apache to use .htaccess (i.e. allow file override)

Allow override in the apache by adding the AllowOverride All line in the config file

Add in the highlighted line in the following block of text in the file:

Save and exit the file

Restart apache

The .htaccess file will be a new file you will create. Create the .htaccess file by using the following command:

Populate the newly created file with the following text.

  • AuthType Basic
  • AuthName “Restricted Files”
  • AuthUserFile /etc/phpmyadmin/.htpasswd
  • Require valid-user

It is important to create secure passwords that are secured by encryption when stored on the server. If this is not done, then the password might be stored in a clear text file, that is easily readable by anyone who has access to the server. For this you must install the utility that will enable you to create the username and password (this utility might already be installed by default). Enter the following command:

Create the username and password. The utility will ask you for the password when you enter the following command:

Test that gateway has been enabled successfully by visiting <your web address>/phpMyAdmin — it should ask for the credentials for the gateway first, then ask for the phpMyAdmin credentials.

5.    Install and Configure WordPress

5.1.  Setup the WordPress DB

Will need to setup a DB for WordPress. Best practice will be to use a separate admin account for the DB:

Log in to phpMyAdmin using the root account and create a new DB. The button to create the DB can be found on the left menu.

Once the DB has been created, create a new user (select the user tab at the top of the screen) and enter the password.

Select the check box to ‘give all privileges’.

Do not use CSL authentication for password.

Go to the SQL query tab. Run query:

Install additional php extensions for wordpress. In the Linux terminal, enter

Restart Apache:

5.2.  Configure Apache

WordPress needs the right privileges to configure Apache through configuring the .htaccess file. To enable this to happen, apache will have to be configured to allow WordPress to configure apache through that .htaccess file. This configuration of apache can be done by editing the apache2.conf file:

Add in the following block of code

Save and exit nano

We need to enable the WordPress permalink feature by enabling the rewrite module:

Check to see changes made to the apache config have been successful:

We should see the message “OK”

Restart apache:

5.3  Install WordPress

Download, install and configure WordPress. We will download into the writable temp folder on the server, secure the files by partially configuring them in that folder for security purposes (as moving unconfigured files into the var/www/html folder makes them immediately reachable via the internet), then move the WordPress files to their permanent folder, and then complete the config and setup of wordpress

Move to the temp folder and download WordPress:

Extract the downloaded files:

Create the .htaccess file that WordPress will use to configure apache (the previous .htaccess file is one that phpMyAdmin uses and is stored in the phpMyAdmin directory. This is another .htaccess file that WordPress uses and is stored in a separate directory):

Set the file permissions for the new .htaccess file to be read and written to by WordPress:

Change the name of the sample WordPress config file to the correct default name (by default, WordPress does not set the standard name during install and this has to be done manually using the following command):

Create the WordPress upgrade directory for WordPress to use for upgrades:

Copy the directory to the permanent folder in /var:

Delete the downloaded wordpress install files from /tmp

5.4.  Adjust the ownership and permissions of the Apache and WordPress directories

Add the server admin user and apache group as owners of the apache directory:

Configure the server to set newly created files in WordPress to inherit the permissions of the parent directory (instead of the user’s):

Add group write access to the wp-content folder, themes folder and plugins folder:

Configure WordPress by updating the WordPress config file. The config changes are:

  • Adding in the secure keys to WordPress generated by wordpress.org,
  • Configuring the mysql DB settings
  • (optional) adding in the email credentials for the site’s auto-email plugin:

Generate the secure key by visiting and entering the required information: https://api.wordpress.org/secret-key/1.1/salt/

Add in the secure keys to the config file by copy pasting the values generated by the website into the file (do not exit, further changes will be made):

The following instructions regarding entering the MySQL details can be carried out as part of the WordPress installation GUI wizard later on when configuring the WordPress CMS via the WordPress front end. However, for convenience’s sake, I am including the instructions here in case anyone wants to configure the settings at this moment instead.

Add in the MySQL DB settings in the file. The username and password will be the same as you used when creating the DB in the previous steps. Please ensure that the quotation marks are included in the text in the file:

Note: If the DB is not located on the same server as WordPress, then enter the server address in the following block of text in the file

Add in the following line to set the method WordPress will use to write to the server’s filesystem:

Save the file.

Visit <website or IP address>/wp-admin to complete the installation via the WP wizard. Chose language English UK option

Once WordPress is installed, install the email notification plugin WP Mail SMTP

6.    (Optional) Increasing the default max upload size of wordpress

Follow the instructions here to update the php.ini file (make sure you restart apache after the file has changed). The php.ini file can be found by visiting <website address>/info.php – the table with the row “Loaded Configuration File” will have the php.ini location.

Enter in the linux command line

The lines to edit are

7.    Fixing NTP: Updating and Setting the Time on the Server

In our final part of how to build a web server, we will no look at how the server keeps time using NTP/Chrony. NTP has actually now been deprecated (although still available and widely used) in favour of the new service chrony. So we will be using chrony intead of ntp for our server.

Check the status and current timezone. Enter in the Linux terminal:

It will most likely be UTC. It would be best to set it to the correct time zone.

Find out the time zone you want from the following list:

Note: You could also use timedatectl list-timezones | grep -I Europe for Europe for e.g. to shorten the list displayed and make searching easier

Change the timezone:

Setup and install chrony:

Add the following text to the chrony conf file so that it uses the Time Server of your choice, for e.g. the AWS ntp server. Open conf file:

Before any server or pool statement, add the following line (i.e. at the beginning before any statement configuring a server or pool add the following so that chrony uses AWS first, as the preferred server before using the default Linux ones):

Save the file

Restart chrony to set everything up:

Verify that chrony is using the AWS ntp server:

The output in the list starting with ^* (usually the first line in the table) should be the IP address of the AWS server

Verify that chrony is syncing correctly:

The system time should be minutely fast/slow than the NTP time

Use the following command to double check the sync:

It should give a minute “system clock wrong by” message. This command should also brute force a system time sync with the ntp server

Double-check to see that the system time is showing the correct timezone and time:

Upgrading WordPress

For security purposes, the settings on the server have been disabled to allow the upgrade of WordPress using the WordPress GUI (plugin and theme installation are enabled). To upgrade WordPress, the setting on the server has to be enabled via the Linux terminal (ensuring that the person carrying out the upgrade can verify themselves by logging on as a server admin). You can then upgrade WordPress via the GUI and disable the settings again on the server via the Linux terminal (for security)

When an update becomes available, log back into your server as your sudo user. Temporarily give the web server process access to the whole document root:

Now, go back the WordPress administration panel (<website or IP address>/wp-admin) and apply the update.

When you are finished, lock the permissions down again for security:

Z Tech is a technologist, senior programme director, business change lead and Agile methodology specialist. He is a former solutions architect, software engineer, infrastructure engineer and cyber security manager. He writes here in his spare time about technology, tech driven business change, how best to adopt Agile practices and cyber security.

Posted in Building a Website, Cyber Security, Tutorials and tagged , , .


  1. Pingback: Designing a Scalable, Highly Resilient, Self-Healing Cloud Architecture

  2. Pingback: Firewalls - What they are, what they do and how they work

  3. Pingback: How to Upgrade from Ubuntu 16.04 LTS to 18.04 LTS

  4. Pingback: Set Up CloudWatch Monitoring and Logging

  5. Pingback: DDOS Attacks and Website Hacking - Responding to Attacks and Unauthorised Access Attempts

Leave a Reply

Your email address will not be published. Required fields are marked *