Week 3 – Apache

This post is part of Linux Servers -course ran by Tero Karvinen (http://terokarvinen.com)

Introduction

Another week and another assignment. This week’s exercises centered around installing and testing of Apache and LAMP. Apache is world’s most popular web server, and LAMP is just an abbreviation of Linux, Apache, MySQL and PHP. The assignment consisted of a total of 12 steps, of which 5 were mandatory. I started working on this on Saturday at 20:30, finished at 24:00 (which includes writing of this blog) and then worked again on Sunday from 17:30 to 21:00.

In this article I have covered:

  1. Installing and configuring Apache
  2. Setting up firewall
  3. Analyzing Apache’s access.log
  4. Installation and configuration of LAMP (Apache, MariaDB\MySQL, PHP)
  5. Making MariaDB work with PHP
  6. Running everything above with a single command
  7. Using configtest for checking of syntax-errors
  8. Installing PHPmyadmin and configuring it for Mariadb\Apache

The tasks

The task descriptions are freely translated from the course page written in finnish by Tero Karvinen

Task a)
Install Apache, make the website work at http://example.com/~tero. Test with a sample home page.

Setting up firewallB

Before doing anything else, I wanted to set up the firewall which we were instructed to do in class. This was done with:

sudo ufw allow 22/tcp
sudo ufw enable

Installing Apache

Installing of Apache consisted of nothing more than firing up the terminal and using the package manager. I did this with:

sudo apt-get install apache2 

After this, the Apache2 server started running and displayed the default ‘it works’ -page when I browsed to localhost.

Making the server run under the current user’s directory

The task wasn’t just about installing Apache, but also about serving the website from the url webpage.com/~username. For this to work, I used our teacher’s guide from 2008.

Enabling the userdir module

To begin, I had to enable Apache’s userdir -module, which would then allow me to work with userdirs. This works by running the following command in the terminal:

sudo a2enmod userdir

After this, a restart of apache2 service was required, which I did with:

sudo service apache2 restart 

Configuring userdir 

Now Apache knew that there might be things under the user’s home directory that can be shown to the world, as opposed to just in the root of Linux. Specifically, Apache is by default looking for a public_html directory, which currently didn’t exist under the user’s directory, so I had to browse with cd to my /home/xubuntu folder (xubuntu is my username) and make a new folder with mkdir public_html. Now opening localhost/~xubuntu in web browser gave me a page with directory listing.


Creating a sample home page

To make it show something else than directory listing, I had to create a basic html file inside the public_html folder which I created in the previous step. To succeed in this, I used nano, which is a built-in text editor. The full command in this case was nano index.html the latter being the file name, which can also include a file path.

Task b)
Surf the webpages of your server. From Apache’s log, find an example log entry of a successful (200 OK) page load and a failed one (404 not found, for example). Analyze the rows.

Apache and It’s logs

Linux’ logs are stored under /var/log/, which is where I assumed Apache’s logs would reside aswell. So I cd‘d into /var/log and upon ls -a ‘ing, I noticed the existence of apache2 folder. cd’ing inside it and using ls again showed the existence of 3 logs: access.log, error.log, other_vhosts_access.log.

Making log entries

Opening the first one with tail access.log -f gave me several log entries from the past 15 minutes. I then attempted to produce some log lines by first entering a working url and then a made up one. These actions should then cause a 200 OK and a 404 not found status codes, respectively. I first browsed to localhost/~xubuntu and then localhost/nonexistingpage and sure enough, I got the log ones I wanted.

127.0.0.1 - - [02/Feb/2019:19:07:33 +0000] "GET /~xubuntu/ HTTP/1.1" 200 437 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:63.0) Gecko/20100101 Firefox/63.0"
127.0.0.1 - - [02/Feb/2019:19:07:33 +0000] "GET /favicon.ico HTTP/1.1" 404 500 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:63.0) Gecko/20100101 Firefox/63.0"
127.0.0.1 - - [02/Feb/2019:19:07:50 +0000] "GET / HTTP/1.1" 200 3477 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:63.0) Gecko/20100101 Firefox/63.0"
127.0.0.1 - - [02/Feb/2019:19:07:50 +0000] "GET /favicon.ico HTTP/1.1" 404 500 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:63.0) Gecko/20100101 Firefox/63.0"
127.0.0.1 - - [02/Feb/2019:19:07:56 +0000] "GET /favicon.ico HTTP/1.1" 404 501 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:63.0) Gecko/20100101 Firefox/63.0"
127.0.0.1 - - [02/Feb/2019:19:08:04 +0000] "GET /nonexistingpage HTTP/1.1" 404 505 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:63.0) Gecko/20100101 Firefox/63.0"
127.0.0.1 - - [02/Feb/2019:19:08:04 +0000] "GET /favicon.ico HTTP/1.1" 404 500 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:63.0) Gecko/20100101 Firefox/63.0"
127.0.0.1 - - [02/Feb/2019:19:08:34 +0000] "GET /favicon.ico HTTP/1.1" 404 501 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:63.0) Gecko/20100101 Firefox/63.0"
127.0.0.1 - - [02/Feb/2019:19:08:57 +0000] "GET /kll HTTP/1.1" 404 493 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:63.0) Gecko/20100101 Firefox/63.0"
127.0.0.1 - - [02/Feb/2019:19:08:57 +0000] "GET /favicon.ico HTTP/1.1" 404 500 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:63.0) Gecko/20100101 Firefox/63.0"

Analyzing the log entries

I was familiar with most of the things that were logged, but I wanted to be thorough and did some googling. What I found was this well written post by a company called keycdn. With the help of this, I found out the following:

127.0.0.1 
The IP the user is connecting with. In this case, it points to localhost.

- -
These are reserved for other events that didn't occur or couldn't be retrieved, such as the identity of the client.

[02/Feb/2019:19:07:33 +0000]
The timestamp of the event

"GET /~xubuntu/ HTTP/1.1"
Type of request, the path of the request and the protocol

200
The status code which was sent to the client (in this case 200 OK)

437
The size of the requested object (web page)

"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:63.0) Gecko/20100101 Firefox/63.0"
This is the browser, It's framework-version, version and other info of the client's operating system followed by information of the browser's user agent, in this case, Gecko.



Task J)
Install LAMP (Linux, Apache, MySQL,
PHP). Test every component and everything as a whole.

The order of these exercises are a bit silly as task C requires one to make an error in PHP, but no PHP is installed yet, so I decided to do task J before I would do task C.


Installing and configuring LAMP

Lamp is basically just Linux, Apache, MySQL and PHP bundled together. With this full stack, one can easily build a good web application with a database and PHP. To succeed, I used our teacher’s old LAMP instructions as well as howtoubuntu’s instructions as a reference.

PHP


To find out which PHP packages are available, I typed apt-cache search php | grep apache which first searched apt-cache for packages related to php and then fed that result to grep, which searched the result for apache. 

From this list I the most relevant to me was libapache2-mod-php7.2, which I then installed with apt-get install.

Configuring PHP for Apache


As explained in Tero’s instructions, PHP requires some configuration to work with Apache’s user directories, so I had to sudoedit php7.2.conf which is located in /etc/apache2/mods-available and comment out the last 4 lines of said file:

Testing that it works

Before I would move to MySQL, I wanted to test that the module worked. So I changed my index.html file located in public_html/ to index.php with mv index.html index.php and added some basic PHP code, such as echo and summing of two integers:

And it worked as expected. Now I knew that if something broke in the next step, it had been working before I started doing it.


MySQL \ MariaDB

I wanted to use MariaDB instead of MySQL, so the packages I needed were mariadb-client and mariadb-server. Also, I learned from googling for MariaDB’s PHP-drivers that the MySQL ones should work just fine, so I did a search for apt-cache search mysql |grep php and found out that the package in question is php7.2-mysql

Configuring MariaDB

After installing the above mentioned three packages, I ran
sudo mysql_secure_installation
Which prompted me with a few questions related to configuring Mariadb.

I then tested mariadb by running
sudo mysql -u root
CREATE DATABASE testdb;
And got a response saying ‘QUERY OK, 1 row affected (0.00 sec)’
which means that everything works as expected.

Testing all three packages as a whole

Now I basically had a full stack installed and everything seemed to work just fine. But I hadn’t tested if they all worked together, which is what I had to find out next. What I decided to do was a simple program that would allow me to display something from the database to php website.

Creating a new database and SQL-user

Even though this is just a test environment, using the root user for this purpose would still be a bit dirty, so I wanted to create a new user with less privileges. Luckily, I’ve gotten used to SQL so well that I remember most of the commands from the top of my head.

I ran the following commands in sudo mysql -u root:

CREATE DATABASE tvshowdb; /* Create a new DB */


GRANT ALL ON 
    tvshowdb.* 
TO 
   tvshowfanatic@localhost 
   IDENTIFIED BY 'vfJPtAdUn9qxKnr'; /* Make a new user and give them all permissions on all tables in  tvshow database. Probably insert and select etc would be enough, but I was a bit lazy */

And then created tables with:

USE tvshowdb; /* Select DB as the active DB */


CREATE TABLE tvshows 
	(
	   id SERIAL,
	   name VARCHAR(1024),
	   year YEAR
	); /* Create a table with the above columns */

And then inserted some sample data:

INSERT INTO tvshows (name, year) VALUES ('The Wire', 2001);
INSERT INTO tvshows (name, year) VALUES ('Extras', 2003);
INSERT INTO tvshows (name, year) VALUES ('Generation Kill', 2008);
INSERT INTO tvshows (name, year) VALUES ('The Office UK', 2001);

Now the database was ready and I could move on to figuring out how to show this for the client.

Connecting to MariaDB from PHP

As I mentioned before, MariaDB uses the same PHP-drivers as MySQL, so using a tutorial for MySQL worked fine. Many of the tutorials I found used deprecated things which didn’t work for me, so I ended up using W3School’s sample code for connecting and displaying data from the database. Writing SQL-access credentials to index.php page doesn’t exactly sound as the best idea in the world, but in this case it didn’t matter.

And everything worked as it was supposed to. Whole LAMP had now been tested and proven to be working just fine.


Task C)
Cause an error to code that is ran on the webserver (in PHP or Python, for example), then find this from the log and analyze the row.

In the previous task, I had some problems with connecting to the database, which were logged into apache’s error log, which as mentioned earlier in this post, is located in /var/log/apache2/

This is when Linux went into permanent sleep and I thought it would be a good idea to call this one a night and continue later on. Which I did on the next day.

Doing everything again with an oneliner

Well, not an onliner, but close. Since I’m using a live USB-stick, I had to setup everything again to the point when Linux decided that It’s time to quit. This, however was not a problem as you can do most of the things (and probably all, if you want to) with an oneliner. In my case, I only had to type:
sudo ufw allow 22/tcp && sudo ufw enable && sudo apt-get update && sudo apt-get install apache2 libapache2-mod-php7.2 mariadb-client mariadb-server php7.2-mysql -y && sudo a2enmod userdir && sudo service apache2 restart && mkdir public_html
To get all of the required packages. After that, only things left to do were configuration of MariaDB, PHP and making a default page to /home/xubuntu/public_html folder.

Recreating an error into Apache’s logs

To do this, I just wrote invalid php code in which I called a non-existing function called undefined_function() and sure enough, I received an error.

[Mon Feb 03 16:00:43.607658 2019] [php7:error] [pid 14110] [client 127.0.0.1:44340] PHP Fatal error:  Uncaught Error: Call to undefined function undefined_function() in /home/xubuntu/public_html/index.php:7\nStack trace:\n#0 {main}\n  thrown in /home/xubuntu/public_html/index.php on line 7 

Analyzing the logline

Apache’s own documentation provides a good insight into error.log, so I went with that.

[Mon Feb 03 16:00:43.607658 2019] 
This is the timestamp of the event.

[php7:error]
This is the kind of the event. It can be an error, warning, notice, etc. In this case it also knew where the error happened.

[pid 14110]
This is the process ID and sometimes it also shows thread ID.

[client 127.0.0.1:44340]
This is the address of the client that made the request

PHP Fatal error: Uncaught
Error: Call to undefined function undefined_function() in /home/xubuntu/public_html/index.php:7\nStack trace:\n#0 {main}\n thrown in /home/xubuntu/public_html/index.php on line 7
This is the actual error itself that also contains the stack trace, which everyone should always follow when wondering why their code doesn't work.


Task d) Cause an error into some of Apache’s config files. Find and analyze this row. Suitable tools for the search include for example Apache’s own logs, syslog and ‘apache2ctl configtest’.

To do this, I first ran

tail /var/log/apache2/access.log -f  
tail /var/log/syslog -f   
tail /var/log/apache2/error.log -f   

In 3 separate terminals so I’d immediately notice if a log entry was written into one of these logs.

Breaking Apache’s configuration filesA

Apache’s configuration files are located in /etc/apache2  and the main configuration file is apache2.conf. Before doing anything malicious, I took a backup of this config file with

sudo cp apache2.conf apache2.conf.backup 

And then I opened the apache2.conf with sudoedit apache2.conf and started breaking things like that mean kid during your childhood’s sandbox play sessions.

Oh yeah? Who’s going to stop me?
Let’s see how well you understand this
How’s your Finnish?

After this misconfiguration spree, I saved the file. The logs didn’t show anything yet, so I restarted the Apache2 service with

service apache2 restart

After the smoke had cleared

Now it was time to check the damages.

Xubuntu’s syslog

 xubuntu@xubuntu:/var/log$ tail -n 0 syslog -f
 Feb  3 16:42:24 xubuntu systemd[1]: Stopping The Apache HTTP Server…
 Feb  3 16:42:24 xubuntu apachectl[14779]: apache2: Syntax error on line 163 of /etc/apache2/apache2.conf: Expected  but saw 
 Feb  3 16:42:24 xubuntu apachectl[14779]: Action 'stop' failed.
 Feb  3 16:42:24 xubuntu apachectl[14779]: The Apache error log may have more information.
 Feb  3 16:42:24 xubuntu systemd[1]: apache2.service: Control process exited, code=exited status=1
 Feb  3 16:42:24 xubuntu systemd[1]: apache2.service: Failed with result 'exit-code'.
 Feb  3 16:42:24 xubuntu systemd[1]: Stopped The Apache HTTP Server.
 Feb  3 16:42:24 xubuntu systemd[1]: Starting The Apache HTTP Server…
 Feb  3 16:42:24 xubuntu apachectl[14784]: apache2: Syntax error on line 163 of /etc/apache2/apache2.conf: Expected  but saw 
 Feb  3 16:42:24 xubuntu apachectl[14784]: Action 'start' failed.
 Feb  3 16:42:24 xubuntu apachectl[14784]: The Apache error log may have more information.
 Feb  3 16:42:24 xubuntu systemd[1]: apache2.service: Control process exited, code=exited status=1
 Feb  3 16:42:24 xubuntu systemd[1]: apache2.service: Failed with result 'exit-code'.
 Feb  3 16:42:24 xubuntu systemd[1]: Failed to start The Apache HTTP Server. 

The syslog basically contained sentences “I tried starting apache2 service twice, but there were some errors. They’re saying it was a syntax error, go check their logs for more information”a

Apache’s error.log

Apache’s own error.log on the other hand had generated just one log line:

[Mon Feb 03 16:42:24.296342 2019] [mpm_prefork:notice] [pid 14095] AH00169: caught SIGTERM, shutting down 

Which, judging from a quick google-search, meant that Apache had only logged the shutdown event, which in turn means that nothing gets generated to the error.log if the service doesn’t start.

Apache2ctl & configtest

As described by Apache’s own documentation, Apache2ctl is a control interface for the Apache http server. It has a script for analyzing Apache’s configuration files for possible syntax errors and other things. Running sudo apache2ctl configtest gave me the following:

apache2: Syntax error on line 163 of /etc/apache2/apache2.conf: Expected </Hakemisto> but saw </Directory>
Action 'configtest' failed. The Apache error log may have more information. 

This means that the part when I changed <Directory> to <Hakemisto> caused a syntax error, even though the other things in the config are read before this part.

Trying again

Out of curiosity, I wanted to test if Apache would start after fixing the above part of the config. I sudoedit’ed it back to <Directory> and attempted to start apache2 service with service apache2 start. After this, the following appeared to syslog:

Feb  3 17:09:43 xubuntu systemd[1]: Starting The Apache HTTP Server...
Feb  3 17:09:43 xubuntu apachectl[15006]: AH00526: Syntax error on line 92 of /etc/apache2/apache2.conf:
Feb  3 17:09:43 xubuntu apachectl[15006]: Timeout takes one argument, Timeout duration (sec)
Feb  3 17:09:43 xubuntu apachectl[15006]: Action 'start' failed.
Feb  3 17:09:43 xubuntu apachectl[15006]: The Apache error log may have more information.
Feb  3 17:09:43 xubuntu systemd[1]: apache2.service: Control process exited, code=exited status=1
Feb  3 17:09:43 xubuntu systemd[1]: apache2.service: Failed with result 'exit-code'.
Feb  3 17:09:43 xubuntu systemd[1]: Failed to start The Apache HTTP Server.

Which meant that now it crashed on the part where I changed ‘Timeout: 300’ to ‘Timeout million seconds haha’.

Task e) Install and try PhpMyAdmin or some other web-inferface for managing databases

Installing and configuring PhpMyAdmin

Phpmyadmin is a tool for managing databases over web. With it, one can easily control their databases and do various SQL-queries.

After installing phpmyadmin -package with sudo apt-get install phpmyadmin, I was prompted with a configuration window:

And after configuring it for apache2 and setting a default password, it should’ve worked. But it didn’t. Browsing to localhost/phpmyadmin gave me a 404 and restarting apache2 service and reconfiguring the package didn’t fix it. So I resorted to google, and found this article from ubuntu.com.

What I had to do was run the following commands:

sudo ln -s /etc/phpmyadmin/apache.conf /etc/apache2/conf-available/phpmyadmin.conf && sudo a2enconf phpmyadmin sudo /etc/init.d/apache2 reload

Which basically links apache.conf to phpmyadmin.conf and the latter part reloads apache2 and phpmyadmin.

Testing PHPmyadmin & Fixing ‘no privileges’ issue

Now phpmyadmin showed up in localhost/phpmyadmin so I logged in with the username ‘phpmyadmin’ and password which I had set up earlier. However, phpmyadmin showed ‘no privileges’ on database -tag. Also, logging in with MariaDb’s root user and password didn’t work either. So I had to resort to googling and found this guide by https://websiteforstudents.com/, where this issue is explained:

When you attempt to logon using MariaDB root account it will fail… That’s because MariaDB and MySQL have switch their authentication method to auth_socket
The auth_socket plugin authenticates users that connect from the localhost through the Unix socket file… which prevents users from connecting with password… So, you won’t be able to connecto via phpMyAdmin…

What I had to do in order to fix this was run the following commands from mysql shell:

use mysql; 
update user set plugin='' where User='root';
flush privileges;
exit

And I could now login to phpmyadmin with my root username and password. I then tried inserting some sample lines and querying for them from Mariadb shell.

And it worked just fine.


Task F) Make a server-sided web application that does some simple math, such as a BMI-calculator && Task G) Make a server-sided web application that uses the database. You can for example make a simple CRUD-application, such as a TODO-list.


I have a Nokia body+ scale, which handily logs body mass, body water, muscle mass, bone mass and weight. However, the app they provide doesn’t show your fat mass percentage, only the amount in kilos. Therefore, I made a simple application where I added some of the 200 measurements I had done last year:

I was running low on time and did this quickly without even giving my usual 60%, which resulted in a mistake: I didn’t take into account the datatype which was sent to MariaDB when the form has ‘decimal’ as input value. Therefore decimal’s weren’t included in the measurements, which I didn’t notice until I had finished entering the data. Oh well, close enough.

References:

Howtoubuntu.org – How to install lamp on ubuntu
https://howtoubuntu.org/how-to-install-lamp-on-ubuntu

Itzgeek.com – Install mariadb on ubuntu
https://www.itzgeek.com/how-tos/linux/ubuntu-how-tos/install-mariadb-on-ubuntu-16-04.html

w3schools.com – selecting from database with php
https://www.w3schools.com/php/php_mysql_select.asp

Apache documentation – logs
https://httpd.apache.org/docs/2.4/logs.html

Phpmyadmin.net – what is phpmyadmin
https://www.phpmyadmin.net/

Websiteforstudents.com – Fixing privilege-error with mariadb and phpmyadmin
https://websiteforstudents.com/install-apache2-mariadb-and-php-7-2-with-phpmyadmin-on-ubuntu-16-04-18-04-18-10-lamp-phpmyadmin/

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this:
search previous next tag category expand menu location phone mail time cart zoom edit close