Install HTTP/2 LAMP Stack on Ubuntu 18.04 Server (Linux, Apache, MySQL, PHP)

This tutorial shows you how to install a super-fast HTTP/2 LAMP stack (Linux, Apache, MySQL, PHP) on Ubuntu 18.04 LTS server (Bionic Beaver) with your own domain name, and secure it with Ubuntu’s built-in firewall UFW (Uncomplicated Firewall), Fail2ban, and a free SSL certificate from Let’s Encrypt. We’ll be using PHP-FPM processor running on PHP7.2, MySQL using the MariaDB engine, and phpMyAdmin for database management.

HTTP/2 is the evolution of the HTTP/1.1 protocol that enables cutting-edge features like binary transfers instead of textual, request/response multiplexing from a single server, and much more.

I’ll be using a VPS from DigitalOcean for this guide, but you can easily adapt it to virtually any VPS provider (Google Cloud, AWS, Rackspace etc). You can also setup a stand-alone server in your home or business, but you’d need to install Ubuntu first, and leave out the SSL certificate step in this tutorial.


  • A VPS (Virtual Private Server) with root access and Ubuntu 18.04 LTS installed, I suggest a $10 DigitalOcean droplet with 1vCPU and 2GB RAM
  • An SSH client like PuTTY/OpenSSH for Windows, Linux and BSD, or Dropbear for macOS
  • A registered domain name with DNS record access via your registrar (i.e. GoDaddy)

Preliminary notes

I’ll be using the domain name and IP address so when you see these, replace them with your domain name and VPS IP address.

You’ll also need to replace any nameserver information with your VPS providers nameservers, for example, DigitalOcean’s nameservers are, and so replace these with your VPS providers nameservers.

There is also a text version of this article which you can do a find-and-replace for and to replace them with your servers info, this makes it a lot faster and easier to enter commands via copy/paste.

Configure DNS records and hostname

Configure DNS records

Once you’ve setup your VPS, login to your VPS provider and head over to Networking > Add a domain and enter without www or http/s prefixes, then click Add Domain. DigitalOcean will automatically create nameserver records, but we need to setup the A records so any requests to your domain name will resolve to your VPS’ IP address.

  • Click on from the Networking section
  • Select the “A” record tab, enter the “@” symbol inside “Hostname” box
  • Enter the IP address of your VPS into “Will Direct To” box (DigitalOcean will have a drop-down VPS list)
  • Leave “TTL” at 3600 and click “Create Record
  • Repeat steps 2 to 4 except this time enter “www” Instead of the “@” symbol

Now head over to your domain name registrar (the folks you registered your domain name with, i.e. GoDaddy) and change the DNS nameserver records to point to your VPS providers nameservers, in my case I will enter, and so replace those with your VPS providers nameservers. Please note* It can take between 1 hour to 48 hours for DNS to propagate the Internet.

Configure hostname

Now we’ll update your VPS and configure the hostname records, so connect to your VPS via SSH as root user and enter the following commands:

apt-get update && apt-get upgrade -y

If you see a message “System restart required” then go ahead and reboot:


…otherwise continue by opening your hosts file:

nano /etc/hosts

You should see something like this:  example localhost
    # The following  lines are desirable for IPv6 capable hosts
    ::1 ip6-localhost  ip6-loopback
    fe00::0 ip6-localnet
    ff00::0  ip6-mcastprefix
    ff02::1 ip6-allnodes
    ff02::2  ip6-allrouters
    ff02::3 ip6-allhosts

You need to add records for your VPS IP address and hostname as follows (replace and with your details):  example localhost example

    # The following  lines are desirable for IPv6 capable hosts
    ::1 ip6-localhost  ip6-loopback
    fe00::0 ip6-localnet
    ff00::0  ip6-mcastprefix
    ff02::1 ip6-allnodes
    ff02::2  ip6-allrouters
    ff02::3 ip6-allhosts

Now save the file Ctrl+O and exit Ctrl+X then enter the following on the command line replacing with your domain name:

echo > /etc/hostname

Then reboot…


Login to your VPS and confirm that your hostname was updated correctly by entering the following command:

hostname -f

You should see (except with your domain name).

Create a non-root user with sudo privileges

It’s good security policy to create a user with sudo privileges instead of logging in with root credentials, so let’s go ahead and do that (replace richie with your name) and optionally answer the questions, or just hit enter:

    adduser richie

    Adding user `richie' ...
    Adding new group `richie' (1001) ...
    Adding new user `richie' (1001) with group `richie' ...
    Creating home directory `/home/richie' ...
    Copying files from `/etc/skel' ...

    Enter new UNIX password: [enter password]
    Retype new UNIX password: [enter password]

    passwd: password updated successfully

    Changing the user information for richie
    Enter the new value, or press ENTER for the default
            Full Name []: Richie
            Room Number []: [enter]
            Work Phone []: [enter]
            Home Phone []: [enter]
            Other []: [enter]
    Is the information correct? [Y/n] y [enter]

Now we’ll give your new user sudo privileges using the flags -a (add) and G (group):

usermod -aG sudo richie

Logout of your SSH terminal and login using your new user. From this point on, every command will be prefixed with sudo which will sometimes prompt for your password (not root password, your new users’ password).

Install and configure Apache web server

Install Apache

Now we can begin installing our LAMP stack starting with Apache web server including Python support, enter the following:

sudo apt-get install apache2 apache2-doc apache2-utils libapache2-mod-python -y

…then create a new file/mod to fix the HTTPOXY vulnerability:

sudo nano /etc/apache2/conf-available/httpoxy.conf

…and copy/paste the following inside our new file:

<IfModule mod_headers.c>
	RequestHeader unset Proxy early

…then save Ctrl+O and exit Ctrl+X. Now we enable mod_rewrite, http2, ssl mods and httpoxy conf, then restart Apache:

    sudo a2enmod rewrite http2 ssl headers expires
    sudo a2enconf httpoxy
    sudo systemctl restart apache2

Configure Apache

We need to allow the use of certain Apache .htaccess directives including mod_rewrite as Apache disables them by default. Open Apache’s config file:

sudo nano /etc/apache2/apache2.conf

…then change AllowOverride None to AllowOverride All in the /var/www directory:

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

Now we can use all of Apache’s directives including mod_rewrite but be careful, and make sure you have an .htaccess file at the root/top directory with the following:

    Options -Indexes
    DirectoryIndex index.php index.html

This will ensure directories are not automatically listed, and an index.php or index.html must be present in each directory otherwise a http 403 Forbidden will be thrown.

We need to create a web directory for your website under the /var/www folder, and an index.html file for testing (replace with your domain name):

    sudo mkdir /var/www/
    sudo mkdir /var/www/
    sudo nano /var/www/

…then enter the following code into the open index.html file:

		<title>Welcome to!</title>
		<h1>Success!  The virtual host is working!</h1>

…then save Ctrl+o and exit Ctrl+X and give ownership using the chown command (user: www-data and group www-data), then permissions using chmod command (directories to 755 and index.html to 644).

    sudo chown -Rf www-data:www-data /var/www/
    sudo chmod -R 755 /var/www/
    sudo chmod 644 /var/www/

Let’s configure Apache’s VirtualHost file so it knows where requests for your hostname should be delivered. Copy the default VirtualHost file using the copy command cp (replace with your domain name) and then open it:

    sudo cp /etc/apache2/sites-enabled/000-default.conf /etc/apache2/sites-available/
    sudo nano /etc/apache2/sites-available/

…which should look like this (comments removed):

<VirtualHost *:80>
    ServerAdmin webmaster@localhost
    DocumentRoot /var/www/html
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined

We need to change <VirtualHost *:80> to <VirtualHost> (replace with your VPS’ IP address) then add/edit the following replacing with your domain name, so your finished config file should look like this:


        ServerAlias *
        DocumentRoot /var/www/

        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined


Now let’s enable the new website and restart Apache:

    sudo a2ensite
    sudo systemctl restart apache2

Let’s make sure Apache is working by opening up your web browser and visiting your website URL without https, you should see the “Success! The virtual host is working!” Make sure you leave this page open for the next step.

Install and configure PHP7.2 and PHP-FPM

Install PHP7.2 and PHP-FPM

Let’s install PHP7.2 and PHP-FPM plus a few modules required for it to run. We start by manually installing libapache-mod-fastcgi package because it’s unavailable in Ubuntu’s repository for some reason. We then install PHP-FPM and enable some mods including mpm_event because mpm_prefork no longer supports HTTP/2:

    cd /tmp
    sudo dpkg -i libapache2-mod-fastcgi_2.4.7~0910052141-1.2_amd64.deb
    sudo apt install -f
    sudo apt-get install php7.2-fpm php7.2 -y
    sudo a2enmod actions fastcgi alias proxy_fcgi setenvif mpm_event
    sudo a2enconf php7.2-fpm
    sudo systemctl restart apache2

Now let’s check that it was installed successfully:

php-fpm7.2 -v

…you should see this:

	PHP 7.2.19-0ubuntu0.18.04.1 (fpm-fcgi) (built: Jun  4 2019 14:48:12)
	Copyright (c) 1997-2018 The PHP Group
	Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
	with Zend OPcache v7.2.19-0ubuntu0.18.04.1, Copyright (c) 1999-2018, by Zend Technologies

Configure PHP7.2 and PHP-FPM

We need to edit some settings for PHP-FPM for good performance, so open up the main config file:

sudo nano /etc/php/7.2/fpm/pool.d/www.conf

At this point, it really does depend on the workload and workload type that you’re expecting from this server. I won’t go into how to configure PHP-FPM for every scenario here, but I urge you to read this article which explains it in further detail. What I will do is show you the optimal settings for the server specification I have in this tutorial (2GB RAM, 1 vCPU) which are the following:

    pm = dynamic
    pm.max_children = 10

    pm.start_servers = 3
    pm.min_spare_servers = 2
    pm.max_spare_servers = 5
    pm.max_requests = 500

…you can go ahead and change the settings in your www.conf file to the above or use other settings if required, then save Ctrl+O and exit Ctrl+X. Next we need to edit the php.ini file because by default, PHP settings are terribly modest. Open the main php.ini file:

sudo nano /etc/php/7.2/fpm/php.ini

…and change the settings as follows:

    upload_max_filesize = 64M 
    post_max_size = 64M 
    memory_limit = 512M 
    max_execution_time = 600 
    max_input_vars = 10000 
    max_input_time = 1000

…then save Ctrl+O and exit Ctrl+X. In order to make these change effective, we need to reboot the entire server:

sudo reboot

Once you’ve logged in again as your sudo user richie, we’ll install some common PHP packages that you’ll likely need:

sudo apt-get install php7.2-common php7.2-gd php7.2-mysql php7.2-imap php7.2-cli php-pear mcrypt imagemagick php7.2-curl php7.2-intl php7.2-pspell -y
sudo apt-get install php7.2-recode php7.2-sqlite3 php7.2-tidy php7.2-xmlrpc php7.2-xsl memcached php-memcache php-imagick php-gettext php7.2-zip -y
sudo apt-get install php7.2-mbstring php-soap php7.2-soap -y

…and enable OPcache for super-fast page serving:

    sudo phpenmod opcache
    sudo systemctl restart apache2

Now let’s make sure PHP is working by creating a PHP-Info page:

    cd /var/www/
    sudo nano phpinfo.php

…then enter the following PHP code:

<?php phpinfo(); ?>

Now save Ctrl+O and exit Ctrl+X, then delete the default HTML page we viewed earlier:

sudo rm index.html

Go back to your web browser and visit: Near top you should see an item called Server API: FPM/FastCGI which means you’re now running PHP-FPM.

Install MySQL and phpMyAdmin

Install MySQL

Now we’ll install the MySQL packages using the MariaDB engine variant, enter the following:

sudo apt-get install mariadb-server mariadb-client php-mysql -y

Now let’s setup and secure MySQL using the mysql_secure_installation wizard and answer the questions as follows:

    sudo mysql_secure_installation

    Enter current password for root (enter for none): [enter]
    Set root password? [Y/n] y
    New password: [enter password]
    Re-enter new password: [enter password]
    Remove anonymous users? [Y/n] y
    Disallow root login remotely? [Y/n] y
    Remove test database and access to it? [Y/n] y
    Reload privilege tables now? [Y/n] y
    Thanks for using MariaDB!

Install phpMyAdmin

Now we’ll install phpMyAdmin package so you can manage your databases. You’ll be asked 3 questions during installation that should be answered as follows:

    sudo apt-get install phpmyadmin -y
    Web server to reconfigure automatically: Apache2
    Configure database for phpmyadmin with dbconfig-common? Yes
    MySQL application password for phpmyadmin: [enter a password]
    Confirm password: [repeat password]

Now let’s make sure phpMyAdmin is working by heading back to your web browser and entering the phpMyAdmin URL: You should now see the admin interface. You can login via username: “phpmyadmin” and the password you used during setup of phpMyAdmin. You won’t be able to login as root as we disabled that during the secure installation of MySQL, instead, just create users for each database separately which ensures granular permissions.

Note* If you get “ERROR: The configuration file now needs a secret passphrase (blowfish_secret) ” error or “Warning in ./libraries/sql.lib.php#613 count(): Parameter must be an array or an object that implements Countable” error, you’ll need to upgrade phpMyAdmin to the latest version (which is pretty easy), follow this guide.

Install a free SSL certificate from Let’s Encrypt

Now we’ll install a free SSL certificate from Let’s Encrypt. We need to install some packages first (some of which may already be installed) then add the Let’s Encrypt repository:

    sudo apt-get update
    sudo apt-get install software-properties-common
    sudo add-apt-repository universe
    sudo add-apt-repository ppa:certbot/certbot
    sudo apt-get update
    sudo apt-get install certbot python-certbot-apache -y

You can now install an SSL certificate for both and and be sure to add any other subdomains you require (i.e. and remember, replace with your domain name, then answer the questions as per further below making sure you select option 2 for HTTPS redirect (strongly recommended):

    sudo certbot --apache -d -d
    Plugins selected: Authenticator apache, Installer apache
    Enter email address (used for urgent renewal and security notices) (Enter 'c' to

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Please read the Terms of Service at You must
    agree in order to register with the ACME server at
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    (A)gree/(C)ancel: A

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Would you be willing to share your email address with the Electronic Frontier
    Foundation, a founding partner of the Let's Encrypt project and the non-profit
    organization that develops Certbot? We'd like to send you email about our work
    encrypting the web, EFF news, campaigns, and ways to support digital freedom.
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
	   (Y)es/(N)o: Y

	   Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    1: No redirect - Make no further changes to the webserver configuration.
    2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for
    new sites, or if you're confident your site works on HTTPS. You can undo this
    change by editing your web server's configuration.
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Congratulations! You have successfully enabled and
    You should test your configuration at:
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Open up your web browser and type in: and hit enter, you should have no warnings and a green lock icon identifying a secure connection.

We need to add some information to your VirtualHost file that Let’s Encrypt generated automatically. Change to Apache’s sites-enabled directory and enter the dir command, you should see 3 VirtualHost conf’s. The one we’re after is the

    cd /etc/apache2/sites-enabled

    000-default.conf  example.conf
    sudo nano

…you should see something like this (comments removed):

<IfModule mod_ssl.c>
        ServerAlias *
        DocumentRoot /var/www/
        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined
        Include /etc/letsencrypt/options-ssl-apache.conf
        SSLCertificateFile /etc/letsencrypt/live/
        SSLCertificateKeyFile /etc/letsencrypt/live/

We need to add a line to enable the HTTP/2 protocol: Protocols h2 http/1.1 which can be added anywhere, but I suggest just after the DocumentRoot directive, so your file should now look like this:

<IfModule mod_ssl.c>
        ServerAlias *
        DocumentRoot /var/www/
        Protocols h2 http/1.1
        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined
        Include /etc/letsencrypt/options-ssl-apache.conf
        SSLCertificateFile /etc/letsencrypt/live/
        SSLCertificateKeyFile /etc/letsencrypt/live/

…then restart Apache:

sudo systemctl restart apache2

Configure UFW firewall and install Fail2Ban

Configure UFW

Ubuntu comes with a built-in firewall called UFW (Uncomplicated Firewall) which is a front-end for IP Tables. It’s quite easy to configure so we’ll go through it now. We start by listing the applications available:

    sudo ufw app list
    Available applications:
    Apache Full
    Apache Secure

All we need is Apache Full and OpenSSH, so we’ll go ahead and enable those now, then enable the firewall:

    sudo ufw allow "Apache Full"
    sudo ufw allow "OpenSSH"
    sudo ufw enable
    Command may disrupt existing ssh connections. Proceed with operation (y|n)? y
    Firewall is active and enabled on system startup

…now check if your website is still available by refreshing your webpage

Install Fail2Ban

Fail2Ban is an important security step to prevent brute-force attacks on your SSH service, Apache, and other services. It scans log files and bans IPs that show malicious activity and doesn’t require any configuration. Let’s install it now:

sudo apt-get install fail2ban -y

You can also tweak Fail2Ban’s settings and add other services to monitor.

And that’s it folks, your server is now fully setup. Let’s move onto the testing section below.

HTTP/2 and ALPN verification

Now let’s test that your new server supports the HTTP/2 protocol and the ALPN extension. Head over to KeyCDN HTTP/2 Test Tool, enter your web address and after a few seconds, you should see this success message:

Testing with PageSpeed Insights on WordPress (optional)

PageSpeed Insights results

As of July 2018, Google’s PageSpeed Insights has a new algorithm that gives much more emphasis on mobile load speed and experience, rather than desktop. You may have checked your website previously and found that you used to get around 85/100, but now it’s suddenly dropped to 20/100 or less, especially if you’re running WordPress.

I installed WordPress on my server after following this guide just to test using the TwentySeventeen theme, and straight out of the box I scored 99/100 for mobile and 100/100 for desktop (see screenshots below).

Now given it’s a pretty basic page, and real-world will likely rank lower due to more images and plugin scripts, it’s still an excellent start! It would also help using an optimization plugin like PageSpeed Ninja and making sure you properly size and optimize your images.

Download WordPress

To download WordPress, enter the following code (replace with your domain name and richie with your username), but please note, this will delete anything in your website’s root folder, so if needed, backup before proceeding:

    cd /var/www/
    sudo rm -rf ./*
    sudo wget
    sudo tar xzf latest.tar.gz
    sudo mv wordpress/* .
    sudo rm -rf wordpress latest.tar.gz
    sudo chown -R www-data:www-data ./

Create MySQL database

To create the WordPress database, login to the MySQL shell using the -u flag for user root, and the -p flag for password (you’ll need your MySQL root password to replace the [enter password] field):

sudo mysql -uroot -p[enter password]

Now we’re inside the MySQL shell. You’ll need another password for the WordPress user we’re about to create, so choose one and record it somewhere before continuing, then replace [enter password] with your new password:

    create user 'wordpress'@'localhost' identified by '[enter password]';
    create database wordpress;
    grant all privileges on wordpress.* to 'wordpress'@'localhost';
    flush privileges;

Install WordPress

To install WordPress, open your web browser and type in your web address and you’ll be presented with the WordPress installation screen. Enter details as follows:

  • Database Name: wordpress
  • Username: wordpress
  • Password: [your password]
  • Database Host: localhost
  • Table Prefix: wp_ (for extra security, place some random numbers or characters between wp and _ for example: wp834_)

Click Submit and then you’ll then be presented with the WordPress administrator username and password screen, so go ahead and enter details of your choice and record them somewhere. You can then login to your new WordPress installation. But be sure to change permissions on your wp-config.php file afterwards (remember to replace with your domain name):

sudo chmod 640 /var/www/

PageSpeed Insights testing

Let’s head on over to Google’s PageSpeed Insights and enter the URL of your website (I suggest using the Hello World! example post that comes with WordPress). You should get over 90/100 for both mobile and desktop (post your results in the comments). I highly recommend installing the PageSpeed Ninja plugin and using the “Ultra” setting making sure “HTTP/2 server push” is enabled.


Congratulations, you now have a fully-fledged, super-fast HTTP/2 LAMP server ready for development and publishing.

Please let me know if you have any issues via the comment form below. If you have hit any errors, make sure you’ve changed all references of and with your domain name and VPS IP address as this is what causes most issues.

Until next time, cheers!

Sources and further reading

Here are the sources I used to put this tutorial together, and I urge you to read them as there’s much more information on each page, particularly source 9.

  1. How To Install Linux, Apache, MySQL, PHP (LAMP) stack on Ubuntu 18.04
  2. Initial Server Setup with Ubuntu 18.04
  3. Setup LAMP Server on Raspberry Pi 3 – [Updated 2019] Complete DIY Guide
  4. The Perfect Server – Ubuntu 18.04 (Bionic Beaver) with Apache, PHP, MySQL, PureFTPD, BIND, Postfix, Dovecot and ISPConfig 3.1 – Page 2
  5. How to install PHP 7.3 on Ubuntu 18.04
  6. How to Manually Upgrade phpMyAdmin
  7. How to Run Apache2 with PHP7.2-FPM on Ubuntu 16.04 | 17.10 | 18.04
  8. Using PHP-FPM with Apache on Ubuntu 16.04
  9. How to enable HTTP/2 support in Apache
  10. KeyCDN HTTP/2 Test Tool
  11. PageSpeed Insights

I was a musician till the age of 30 with a keen interest in technology. I did a short web design course which sparked my interest in programming and in 2009 I launched Ricmedia Guitar, then Ricmedia PC Help. I now publish tech articles and tutorials on the main domain.

Recent Posts

Build a Mini-ITX NAS RAID Server with Enterprise SAS Hard Drives

Today I'll show you how to build a rock-solid home/office NAS server using a Mini-ITX… Read More

1 year ago

Reset Apple Safari to default settings

Since Safari version 9.0 (macOS El Capitan), Apple have removed the menu option to Reset… Read More

2 years ago

Enable God Mode on Windows 10

How would you like to see all the hidden expert settings available on your Windows… Read More

2 years ago

Perform disk error check (chkdsk) on Windows 10

Today, I'll show you how to run Windows Check Disk (chkdsk) to find and fix… Read More

2 years ago

Set permanent DNS nameservers on Ubuntu/Debian with resolv.conf

Setting custom DNS servers on Linux can increase performance, security and even thwart some websites… Read More

2 years ago

How to install Debian Linux – Complete Guide

Today, I'll show you how to download and install Debian Linux, simply follow each step… Read More

2 years ago