Setup Linux, Apache, MySQL, PHP(LAMP) Stack on Ubuntu 18.04
Tags: ubuntu, apache, mysql, php
Published: 2020-11-24 13:18:17

The **LAMP** stack is a set of open-source software used to host web applications. A web application requires an operating system (Linux), an HTTP Server (Apache), a database management system (MySQL), and a programming language (PHP).

While there are other alternatives to MySQL as the database such as MariaDB, PostgreSQL, NoSQL databases, and also alternatives to PHP as the programming language such as Perl and Python. This guide will focus mainly on MySQL as the database and PHP as the programming language.

### Prerequisites
To follow this guide, an Ubuntu server setup with a non-root sudo enabled user is required. In this guide, my domain will be **demoapp.com**.

### Apache
Install Apache using Ubuntu's package manager `apt`:
```bash
sudo apt update
sudo apt install apache2
```
`apt` will display the packages it's about to install and the disk space that will be taken up. Press **Y** and hit **ENTER** to continue, and the installation will proceed.

**Note:** sudo command operations are executed with root privileges, so you might be required to input your user's password.

On your browser navigate to the server's public IP address (http://server_ip) and you should see the Apache2 Ubuntu default page.

![FireShot Capture 115 - Apache2 Ubuntu Default Page_ It works - 18.219.51.161](https://dev-to-uploads.s3.amazonaws.com/i/iu0cjczld7iokcbduihz.png)
 
### PHP
Install the ppa:ondrej/php PPA repository which has the latest build packages of PHP.
```bash
sudo apt install software-properties-common
sudo add-apt-repository ppa:ondrej/php
sudo apt-get update
```
In this guide, we will be installing php7.4;
```bash
sudo apt install php7.4
```
Confirm the installation using the command;
```bash
php -v
```
Next, install some commonly used PHP extensions;
```bash
sudo apt install php7.4-common php7.4-mysql php7.4-xml php7.4-xmlrpc php7.4-curl php7.4-gd php7.4-imagick php7.4-cli php7.4-dev php7.4-imap php7.4-mbstring php7.4-text php7.4-opcache php7.4-soap php7.4-zip php7.4-intl
```
#### Setting Up Virtual Hosts
When using Apache web server, we can create *virtual hosts* to enclose configuration details. This allows us to host more than one domain on a single server. Apache on Ubuntu is enabled by default to serve files from the `/var/www/html` folder. This works well for a single site, so if this is what you need, you can dump in your code files into this folder and skip to the next section.

Create a directory within the `/var/www` for our domain site and assign ownership of the directory;
```bash
sudo mkdir /var/www/demoapp.com
sudo chown -R $USER:$USER /var/www/demoapp.com
```
Create an index.php page using nano;
```bash
nano /var/www/domain/index.php
```
Add the following and save the file;
```html
<html>
    <head>
        <title>Hello World</title>
    </head>
    <body>
        <h1>Hello world from demoapp</h1>
    </body>
</html>
```
Next, create a virtual host file to serve this content. Let's make a copy of the default configuration file and modify;
```bash
cd /etc/apache2/sites-available
sudo cp 000-default.conf demoapp.com.conf
```
Open the file and modify the following directives to the correct value, save and close the file when done.

- ServerName - **demoapp.com** (sets the request scheme, hostname and port that the server uses to identify itself).
- ServerAlias - **www.demoapp.com** (sets the alternate names for a host).
- DocumentRoot - **/var/www/demoapp.com** (sets the directory from which httpd - Apache Hypertext Transfer Protocol Server will serve files).

Enable the new configuration file and disable the default configuration file;
```bash
sudo a2ensite demoapp.com.conf
sudo a2dissite 000-default.conf
```
Check for configuration errors and if no errors restart Apache;
```bash
sudo apache2ctl configtest
sudo systemctl restart apache2
```
Test your changes by visiting the URL in your browser. You should see something like the below;

![FireShot Capture 120 - Welcome! - 18.219.51.161](https://dev-to-uploads.s3.amazonaws.com/i/x4msa1lwmalayxs088xx.png)
 
### MySQL
Run the command below to install from `apt` package manager
```bash
sudo apt install mysql-server
```
Once the installation is complete, we need to run a script pre-installed with MySQL that helps improve the security of our installation in the following ways:
- Sets a password for the user root account.
- Remove root accounts that are accessible from outside the local machine.
- Remove anonymous user accounts (These are accounts that allows anyone to connect into the MySQL server without having a user account).
- Remove the test database, which can be accessed by anonymous users.

```bash
sudo mysql_secure_installation
```
First, you would be asked if you want to enable the **validate password plugin**. It's important to note that if enabled, passwords that don't match the specified criteria will be rejected by MySQL. For this guide, it won't be enabled, and if you do same ensure to use strong and unique passwords for database credentials.

Next, configure a password for the MySQL root user. For the rest of the questions, press **Y** and hit the **ENTER** key at each prompt.

Let's test our installation by logging in as the root user;
```bash
sudo mysql
```
Exit the MySQL console by typing **exit** and hit **ENTER**

#### Password Access For MySQL Account
When you connected with MySQL as the root user, you did not supply a password even though one was supplied during installation. This is because, on Ubuntu systems running MySQL 5.7 and later versions, the default authentication method for the root user is using the auth_socket plugin instead of a password. 

This means, only system users with sudo privileges connecting from the terminal or through an application with the same privileges are allowed to log in as the root user. While this is a nice secure feature, you won’t be able to use the root user to connect from your PHP application or an external program like phpMyAdmin.

It is important to note that for increased security, it is better to create other users with fewer privileges especially if there will be multiple databases hosted on the server.

To switch the authentication method from auth_socket to mysql_native_password for your root user open up the MySQL prompt from your terminal:
```bash
sudo mysql
```
Next, confirm the root user does truly authenticate using the auth_socket plugin with the query below:
```sql
SELECT user,authentication_string,plugin,host FROM mysql.user;
```
Configure the root user to authenticate with a password. Replace 'password' below with a stronger password of your choice.
```sql
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'password';
```
Reload the grant tables to enable your new changes.
```sql
FLUSH PRIVILEGES;
```
At this point, you have successfully set up a **LAMP** Stack. You can continue below for other optional setup options.

### phpMyAdmin
To get started, install phpMyAdmin using Ubuntu's package manager `apt`:

```bash
sudo apt install phpmyadmin
```

This will ask you a few questions to configure your installation correctly. Take note of the following:

- When the prompt appears, "apache2" is highlighted, but not selected. Press **SPACE** to select Apache followed by **TAB** and then **ENTER**.
- When asked whether to use dbconfig-common to set up the database, select **YES**.

Next is to enter a MySQL application password for phpMyAdmin and enable the mbstring PHP extension using the command

```bash
sudo phpenmod mbstring
```

Restart Apache to enable the changes
```bash
sudo systemctl restart apache2
```

Navigate to http://demoapp.com/phpmyadmin to confirm your installation.

**Note**: You might encounter a `count(): Parameter must be an array or an object that implements Countable` error while working with the phpMyAdmin installed. While there are a ton of ways to solve this error on the web, I will go with the simplest option which is to upgrade phpMyAdmin.

#### Upgrading phpMyAdmin 
Navigate to the home directory and install the dependency.
```bash
cd ~
sudo apt install unzip
```
Next, create a backup of the current phpMyAdmin directory.
```bash
sudo mv /usr/share/phpmyadmin/ /usr/share/phpmyadmin.bak
```

Download the latest version of phpMyAdmin and extract its contents.

```bash
wget www.phpmyadmin.net/downloads/phpMyAdmin-latest-all-languages.zip
unzip phpMyAdmin-latest-all-languages.zip
```

Create a new phpMyAdmin directory and move the contents of the extracted folder into the newly-created directory;

```bash
sudo mkdir /usr/share/phpmyadmin
sudo mv phpMyAdmin-*/* /usr/share/phpmyadmin/
```

Clean up the downloaded zip file and the extracted folder;
```bash
sudo rm phpMyAdmin-latest-all-languages.zip
sudo rm -rf phpMyAdmin-*/*
```
Update the TEMP_DIR and CONFIG_DIR constants in the vendor_config.php file.
```bash
sudo nano /usr/share/phpmyadmin/libraries/vendor_config.php
```
and update the value of the constant
```bash
define('TEMP_DIR', '/var/lib/phpmyadmin/tmp/');
define('CONFIG_DIR', '/etc/phpmyadmin/');
```
Save the file and log into phpMyAdmin and you should see you are on the latest version.

#### Secret passphrase in configuration is too short
If you see an error like the above, open the blowfish_secret.inc.php file
```bash
sudo nano /var/lib/phpmyadmin/blowfish_secret.inc.php
```
and update the value of *$cfg['blowfish_secret']*. [This is a good tool to generate a random string](https://www.question-defense.com/tools/phpmyadmin-blowfish-secret-generator)
```bash
$cfg['blowfish_secret'] = '{^QP+-(3mlHy+Gd~FE3mN{gIATs^1lX+T=KVYv{ubK*U0V';
```
Save the file and the error should be gone on your phpMyAdmin dashboard.

### Composer
within the home directory, download the composer installer using curl.

```bash
curl -sS https://getcomposer.org/installer -o composer-setup.php
```

Next, verify that the installer matches the SHA-384 hash for the latest installer found on the [Composer Public Keys/Checksums page](https://composer.github.io/pubkeys.html). Copy the hash and replace appropriately 

```bash
php -r "if (hash_file('sha384', 'composer-setup.php') === '756890a4488ce9024fc62c56153228907f1545c228516cbf63f885e036d37e9a59d27d63f46af1d4d07ee0f76181c7d3') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
```

If you see Installer corrupt, redownload the installation script again and double-check that you’re using the correct hash. Once you have a verified installer, you can continue.

Install composer globally 
```bash
sudo php composer-setup.php --install-dir=/usr/local/bin --filename=composer
```
To test the installation, type composer and hit **ENTER** in your terminal and you should see an output displaying composer's version and available commands.

### Let’s Encrypt Free SSL Wildcard Certificate
Let’s Encrypt is a free, automated, and open certificate authority (CA), that provides digital certificates needed to enable HTTPS (SSL/TLS) for websites in the most user-friendly possible.

Install the ppa:certbot/certbot PPA repository and install certbot

```bash
sudo add-apt-repository ppa:certbot/certbot
sudo apt install certbot
```
Generate a wild card certificate using the command below;
```bash
sudo certbot certonly --manual -d *.demoapp.com -d demoapp.com --agree-tos --no-bootstrap --manual-public-ip-logging-ok --preferred-challenges dns-01 --server https://acme-v02.api.letsencrypt.org/directory
```
You should see something similar once you run the above command

```bash
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator manual, Installer None
Obtaining a new certificate
Performing the following challenges:
dns-01 challenge for demoapp.com
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please deploy a DNS TXT record under the name
_acme-challenge.demoapp.com with the following value:
OGdBk2JteHzs8eWxNomoCWRrOJN83ECovDwRiL51ONY
Before continuing, verify the record is deployed.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
Press Enter to Continue
```
Create a DNS TXT record in your domain provider with the name _acme-challenge. Wait for a few minutes for the record to be propagated over the internet and then press ENTER. You should see a similar output
```bash
Waiting for verification...
Cleaning up challenges
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/demoapp.com/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/demoapp.com/privkey.pem
Your cert will expire on 2021-02-23. To obtain a new or tweaked
version of this certificate in the future, simply run certbot
again. To non-interactively renew *all* of your certificates, run
"certbot renew"
- If you like Certbot, please consider supporting our work by:
Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
Donating to EFF:                    https://eff.org/donate-le
Congratulations!! Your wildcard certificate is generated. You can use this wildcard certificate with any sub-domain you create for your domain name.
```
Modify the virtual host configuration file;
```bash
sudo nano /etc/apache2/sites-available/demoapp.com.conf
```
and add the following. Replace the appropriate values
```bash
<VirtualHost *:443>
    ServerName demoapp.com
    ServerAlias www.demoapp.com
    ServerAdmin info@demoapp.com
    SSLEngine On
    DocumentRoot /var/www/demoapp.com
    ErrorLog ${APACHE_LOG_DIR}/demoapp.com-error.log
    CustomLog ${APACHE_LOG_DIR}/demoapp.com-access.log combined
    SSLCertificateFile /etc/letsencrypt/live/demoapp.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/demoapp.com/privkey.pem
</VirtualHost>
```
Enable SSL module which is responsible for creating and serving SSL connections.
```bash
sudo a2enmod ssl
```
Check for configuration errors and if no errors restart Apache
```bash
sudo apache2ctl configtest
sudo systemctl restart apache2
```
Now you can visit https://demoapp.com

### Conclusion
Following this guide, you should be able to successfully set up a LAMP stack and also install some necessary applications. Hope you found this useful.