Bar
SpaceWire UK
Specialist providers of VHDL Intellectual Property & Design Services
BarBarBarBar
Tutorial
Missing Image!
Part 18 - Add LAMP (Linux-Apache-MySQL-PHP) style stack to PetaLinux

Introduction

This tutorial details the steps required to install a LAMP style stack on PetaLinux. The previously installed busybox-httpd is OK but not quite as flexible as the likes of say Apache. The stack to be installed shall consist of Apache2, SQLite3 & PHP7, and for good measure phpLiteAdmin. The latter offers a graphical interface for SQL databases much the same as myPHPAdmin.

Aims

The aims of this tutorial are as follows :-

    Part 1 - Project Setup

    1. Setup environment
    2. Obtain tutorial files from Bitbucket (optional)
    3. Change present working directory
    4. Bump Version

    Part 2 - OS Development

    1. Disable busybox-httpd webserver
    2. Configure PetaLinux for LAMP
    3. Build & package PetaLinux

    Part 4 - Hardware Deployment

    1. Setup Zedboard hardware
    2. Launch MiniCom terminal emulator
    3. Deploy firmware & software on Zedboard
    4. Check boot is working as expected

    Part 5 - Configure & validate LAMP style setup

    1. Check PetaLinux boot
    2. Check HTML
    3. Check CGI shell scripts
    4. Check PHP
    5. Check SQLite
    6. Check phpLiteAdmin
    7. Migration
    8. Make changes permanent

    Part 6 - Revision Control

    1. Commit new & updated files

    Part 7 - Final checks

    1. Create a Production Release
    2. Deploy Production Release on the Zedboard
    3. Check everything is working as expected
    #### Part 1 - Project Setup ####

    1. Setup environment

    Setup Xilinx design environment for the 2021.2 toolset.
    steve@Desktop:~$ xilinx
    Xilinx tools available tools at /opt/Xilinx :-
    1) 2021.2 - Vivado - SDK - Vitis - PetaLinux
    0) Exit
    Please select tools required or exit : 1
    
    Tools are as follows :-
    vivado @ /opt/Xilinx/Vivado/2021.2/bin/vivado
    vitis @ /opt/Xilinx/Vitis/2021.2/bin/vitis
    petalinux-build @ /opt/Xilinx/PetaLinux/2021.2/tool/tools/common/petalinux/bin/petalinux-build
    

    2. Obtain tutorial files from Bitbucket (optional)

    Starting from this point, having not followed the previous tutorials, can be achieved by obtaining the required files from BitBucket. The only prerequisite is that Part 1 - Installation of tools, setup of environment and creation of project area as been completed.

    Obtain OS source.
    steve@Desktop:~$ cd ~/projects
    steve@Desktop:~/projects$ git clone -b v11.0 https://bitbucket.org/spacewire_firmware/zedboard_linux
    

    3. Change present working directory

    Change the present working directory to be the project directory.
    steve@Desktop:~$ cd ~/projects/zedboard_linux
    

    4. Bump Version

    Change the version (or revision) number for this new development, this prevents ghost (post-release, same version) builds from appearing.
    steve@Desktop:~/projects/zedboard_linux$ sed -i 's/11.0/12.0/g' os/petalinux/project-spec/meta-user/recipes-apps/website/files/project.txt
    

    project.txt

    Zedboard PetaLinux Example Design
    SpaceWire UK
    Steve Haywood
    12.0
    
    Direct download available here :-
    steve@Desktop:~/projects/zedboard_linux$ wget https://spacewire.co.uk/tutorial/shared/repos/0024/zedboard_linux/os/petalinux/project-spec/meta-user/recipes-apps/website/files/project.txt -O os/petalinux/project-spec/meta-user/recipes-apps/website/files/project.txt
    
    #### Part 2 - OS Development ####

    5. Disable busybox-httpd webserver

    Launch the PetaLinux configuration tool.
    steve@Desktop:~/projects/zedboard_linux$ cd os/petalinux
    steve@Desktop:~/projects/zedboard_linux/os/petalinux$ petalinux-config -c rootfs
    steve@Desktop:~/projects/zedboard_linux/os/petalinux$ cd ../..
    
    Navigate the menu selecting Filesystem Packages » base » busybox, disable busybox-httpd and then save the configuration and exit the tool. Missing Image!

    6. Configure PetaLinux for LAMP

    Configure PetaLinux to use Apache, SQLite & Apache's PHP Module. For good measure also add the nano text editor.

    Edit the petalinuxbsp.conf as shown below.
    steve@Desktop:~/projects/zedboard_linux$ subl os/petalinux/project-spec/meta-user/conf/petalinuxbsp.conf
    

    petalinuxbsp.conf

    #User Configuration
    
    #OE_TERMINAL = "tmux"
    
    IMAGE_INSTALL_append = " ntp ntpdate ntpq sntp nano"
    PACKAGECONFIG_append_pn-php = " apache2"
    IMAGE_INSTALL_append = " apache2 sqlite3 php-modphp"
    
    Direct download available here :-
    steve@Desktop:~/projects/zedboard_linux$ wget https://spacewire.co.uk/tutorial/shared/repos/0024/zedboard_linux/os/petalinux/project-spec/meta-user/conf/petalinuxbsp.conf -O os/petalinux/project-spec/meta-user/conf/petalinuxbsp.conf
    
    Check out the changes.
    steve@Desktop:~/projects/zedboard_linux$ git difftool os/petalinux/project-spec/meta-user/conf/petalinuxbsp.conf
    

    7. Build & package PetaLinux

    steve@Desktop:~/projects/zedboard_linux$ cd os/petalinux
    steve@Desktop:~/projects/zedboard_linux/os/petalinux$ petalinux-build
    steve@Desktop:~/projects/zedboard_linux/os/petalinux$ petalinux-package --prebuilt --force
    
    #### Part 4 - Hardware Deployment ####

    8. Setup Zedboard hardware

    If not already, connect up the hardware as follows :-
    1. Xubuntu PC USB ⇄ Zedboard USB JTAG/Debug
    2. Xubuntu PC USB ⇄ Zedboard USB UART
    3. Zedboard Ethernet ⇄ Router
    4. Xubuntu PC Ethenet ⇄ Router
    5. Router ⇄ Internet
    Missing Image!Set the boot mode jumpers on the Zedboard for JTAG.Missing Image!Power on the Zedboard.

    9. Launch MiniCom terminal emulator

    If not already running, open up a new terminal and launch the MiniCom terminal emulator.
    steve@Desktop:~$ minized
    
    Welcome to minicom 2.7.1
    
    OPTIONS: I18n
    Compiled on Dec 23 2019, 02:06:26.
    Port /dev/ttyACM0, 06:34:25
    
    Press CTRL-A Z for help on special keys
    

    10. Deploy firmware & software on Zedboard

    Deploy PetaLinux to the Zedboard via JTAG.
    steve@Desktop:~/projects/zedboard_linux/os/petalinux$ petalinux-boot --jtag --prebuilt 3
    

    11. Check boot is working as expected

    All being well the following sequence of events should be observed.
    1. The blue done LED illuminates indicating the Programmable Logic (PL) has been programmed.
    2. The software runs on the Processor System (PS).
    3. PetaLinux starts to boot.
    4. The led-runner application launches and executes the expanding & contracting LED illumination sequence.
    5. The PetaLinux login prompt appears in the terminal emulator.
    #### Part 5 - Configure & validate LAMP style setup ####

    12. Check PetaLinux boot

    The MiniCom terminal emulator displays the following error message due to a missing file.
    Starting web server: apache2cat: can't open '/run/httpd.pid': No such file or directory
    
    It also displays the help page for grep, most probably due to bad options usage on the call.

    13. Check HTML

    Access the webserver on the Zedboard by pointing a browser at its IP address 192.168.2.87.

    All being well the following page should be displayed. Missing Image! Login to PetaLinux using the root credentials (username = root & password = root).

    Examine Apache's configuration file.
    root@petalinux:~# nano /etc/apache2/httpd.conf
    
    Search for DocumentRoot (press Ctrl + W to search, enter DocumentRoot and then press Enter).

    As can be seen, HTML is being served from /usr/share/apache2/default-site/htdocs.

    Quit Nano (press Ctrl + X).

    Examine the htdocs directory and the files it contains.
    root@petalinux:~# ls -la /usr/share/apache2/default-site/htdocs
    total 4
    drwxr-xr-x    3 root     root            80 Mar  9  2018 .
    drwxr-xr-x    3 root     root            60 Mar  9  2018 ..
    -rw-r--r--    1 root     root            45 Mar  9  2018 index.html
    drwxr-xr-x   14 root     root          4100 Mar  9  2018 manual
    
    The HTML file being served is index.html, examine the file.
    root@petalinux:~# cat /usr/share/apache2/default-site/htdocs/index.html
    <html><body><h1>It works!</h1></body></html>
    
    The HTML service is working OK.

    14. Check CGI shell scripts

    Examine Apache's configuration file again to see what the CGI arrangements are.
    root@petalinux:~# nano /etc/apache2/httpd.conf
    
    Search for cgi-bin. Do this multiple times to find the two lines of interest.

    As can be seen, CGI is being served from /usr/libexec/apache2/modules/cgi-bin.

    Quit Nano.

    Examine the cgi-bin directory and the files it contains.
    root@petalinux:~# ls -la /usr/libexec/apache2/modules/cgi-bin
    total 16
    drwxr-xr-x    2 root     root           120 Mar  9  2018 .
    drwxr-xr-x    3 root     root          1900 Mar  9  2018 ..
    -rw-r--r--    1 root     root           820 Mar  9  2018 printenv
    -rw-r--r--    1 root     root          1074 Mar  9  2018 printenv.vbs
    -rw-r--r--    1 root     root          1133 Mar  9  2018 printenv.wsf
    -rw-r--r--    1 root     root          1261 Mar  9  2018 test-cgi
    
    Download the Test CGI file from PetaLinux and take a look at it.
    steve@Desktop:~/projects/zedboard_linux/os/petalinux$ cd ../..
    steve@Desktop:~/projects/zedboard_linux$ ssh-keygen -f /home/steve/.ssh/known_hosts -R 192.168.2.87
    steve@Desktop:~/projects/zedboard_linux$ ssh-keyscan -H 192.168.2.87 >> ~/.ssh/known_hosts
    steve@Desktop:~/projects/zedboard_linux$ sshpass -p root scp root@192.168.2.87:/usr/libexec/apache2/modules/cgi-bin/test-cgi os/petalinux/project-spec/meta-user/recipes-apps/website/files/cgi-bin
    
    steve@Desktop:~/projects/zedboard_linux$ subl os/petalinux/project-spec/meta-user/recipes-apps/website/files/cgi-bin/test-cgi
    

    test-cgi

    #
    
    # To permit this cgi, replace # on the first line above with the
    # appropriate #!/path/to/sh shebang, and set this script executable
    # with chmod 755.
    #
    # ***** !!! WARNING !!! *****
    # This script echoes the server environment variables and therefore
    # leaks information - so NEVER use it in a live server environment!
    # It is provided only for testing purpose.
    # Also note that it is subject to cross site scripting attacks on
    # MS IE and any other browser which fails to honor RFC2616.
    
    # disable filename globbing
    set -f
    
    echo "Content-type: text/plain; charset=iso-8859-1"
    echo
    
    echo CGI/1.0 test script report:
    echo
    
    echo argc is $#. argv is "$*".
    echo
    
    echo SERVER_SOFTWARE = $SERVER_SOFTWARE
    echo SERVER_NAME = $SERVER_NAME
    echo GATEWAY_INTERFACE = $GATEWAY_INTERFACE
    echo SERVER_PROTOCOL = $SERVER_PROTOCOL
    echo SERVER_PORT = $SERVER_PORT
    echo REQUEST_METHOD = $REQUEST_METHOD
    echo HTTP_ACCEPT = "$HTTP_ACCEPT"
    echo PATH_INFO = "$PATH_INFO"
    echo PATH_TRANSLATED = "$PATH_TRANSLATED"
    echo SCRIPT_NAME = "$SCRIPT_NAME"
    echo QUERY_STRING = "$QUERY_STRING"
    echo REMOTE_HOST = $REMOTE_HOST
    echo REMOTE_ADDR = $REMOTE_ADDR
    echo REMOTE_USER = $REMOTE_USER
    echo AUTH_TYPE = $AUTH_TYPE
    echo CONTENT_TYPE = $CONTENT_TYPE
    echo CONTENT_LENGTH = $CONTENT_LENGTH
    Edit the file as the header comment suggests, replace the first line # with #!/bin/sh.

    test-cgi (partial)

    1. #
    2. #!/bin/sh
    Direct download available here :-
    steve@Desktop:~/projects/zedboard_linux$ wget https://spacewire.co.uk/tutorial/shared/repos/0024/zedboard_linux/os/petalinux/project-spec/meta-user/recipes-apps/website/files/cgi-bin/test-cgi -O os/petalinux/project-spec/meta-user/recipes-apps/website/files/cgi-bin/test-cgi
    
    Upload the Test CGI file back to PetaLinux for testing.
    steve@Desktop:~/projects/zedboard_linux$ sshpass -p root scp os/petalinux/project-spec/meta-user/recipes-apps/website/files/cgi-bin/test-cgi root@192.168.2.87:/usr/libexec/apache2/modules/cgi-bin
    
    Access the webserver by pointing a browser at http://192.168.2.87/cgi-bin/test-cgi.

    Sadly the test-cgi script is not being executed, instead its contents are simply being dumped to the browser. Missing Image! Take a look at Apache's configuration file again.
    root@petalinux:~# nano /etc/apache2/httpd.conf
    
    Search for mod_cgid.so.

    As can be seen, the LoadModule for this line is commented out. Delete the # at the start of the line and save the file.

    Reload Apache so the updated httpd.conf is being used.
    root@petalinux:~# /etc/init.d/apache2 reload
    
    Access the webserver again by pointing a browser at 192.168.2.87/cgi-bin/test-cgi.

    Sadly the test-cgi script is still not being executed. Missing Image! Thinking back to the previous Webserver tutorial, the BitBake recipe set execute permissions on the shell script CGI's.

    As seen above, the permissions for test-cgi are -rw-r--r--. Change these so the file is executable.
    root@petalinux:~# chmod +x /usr/libexec/apache2/modules/cgi-bin/test-cgi
    
    Access the webserver again by pointing at http://192.168.2.87/cgi-bin/test-cgi.

    All being well the following page should be displayed. Missing Image! The CGI (shell script) service is working OK.

    15. Check PHP

    Perform a quick search for any pre-installed PHP files that may be of use.
    root@petalinux:~# find / -name "*.php"
    
    None found!

    Create the classic Hello World example using basic HTML & PHP.
    steve@Desktop:~/projects/zedboard_linux$ subl os/petalinux/project-spec/meta-user/recipes-apps/website/files/cgi-bin/hello_world.php
    

    hello_world.php

    <html>
    <head>
    <title>PHP Test</title>
    </head>
    <body>
    <?php echo '<p>Hello World</p>'; ?>
    </body>
    </html>
    
    Direct download available here :-
    steve@Desktop:~/projects/zedboard_linux$ wget https://spacewire.co.uk/tutorial/shared/repos/0024/zedboard_linux/os/petalinux/project-spec/meta-user/recipes-apps/website/files/cgi-bin/hello_world.php.txt -O os/petalinux/project-spec/meta-user/recipes-apps/website/files/cgi-bin/hello_world.php
    
    Upload the Hello World PHP file to PetaLinux for testing.
    steve@Desktop:~/projects/zedboard_linux$ sshpass -p root scp os/petalinux/project-spec/meta-user/recipes-apps/website/files/cgi-bin/hello_world.php root@192.168.2.87:/usr/libexec/apache2/modules/cgi-bin
    
    Note that PHP files do not need to be executable as they are interpreted by Apache and not executed.

    Access the webserver again by pointing at http://192.168.2.87/cgi-bin/hello_world.php.

    All being well the following page should be displayed. Missing Image! The CGI (PHP) service is working OK.

    16. Check SQLite

    Note that Apache is run using the daemon account, the old busybox-httpd used the root account. Due to this care must be taken with file & directory permissions such that correct access can be obtained.

    As seen above, the permissions for cgi-bin are drwxr-xr-x and the directory is owned by root. Creating a database in this directory via a PHP page will not be possible without changing the permissions first. Instead create a db directory with full access.
    root@petalinux:~# mkdir /usr/libexec/apache2/modules/cgi-bin/db
    root@petalinux:~# chmod 777 /usr/libexec/apache2/modules/cgi-bin/db
    
    Create a very simple HTML, PHP & SQLite test page that creates/opens a database, creates a table, inserts a row inside the table and closes the database.
    steve@Desktop:~/projects/zedboard_linux$ subl os/petalinux/project-spec/meta-user/recipes-apps/website/files/cgi-bin/sqlite_test.php
    

    sqlite_test.php

    <?php
    //
    // File .......... sqlite_test.php
    // Author ........ Steve Haywood
    // Version ....... 1.0
    // Date .......... 3 August 2023
    // Description ...
    //   Simple HTML, PHP & SQLite example code that checks the basic operation of
    // SQLite. SQL queries used are :-
    //
    // 1. Create/open database
    // 1. Create table
    // 3. Insert row
    // 4. Close database
    //
    ?>
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <title>SQLite Test</title>
    </head>
    
    <?php
    
    class MyDB extends SQLite3 {
      function __construct() {
        $this->open('db/test.db');
      }
    }
    
    echo 'Creating/opening database<br>';
    $db = new MyDB();
    if ($db) {
      echo 'Success';
    } else {
      echo 'Failure : ' . $db->lastErrorMsg();
    }
    echo '<br><br>';
    
    echo 'Creating table<br>';
    $return = $db->exec("CREATE TABLE fruit (item VARCHAR(30) NOT NULL PRIMARY KEY UNIQUE, quantity int unsigned NOT NULL)");
    if ($return) {
      echo 'Success';
    } else {
      echo 'Failure : ' . $db->lastErrorMsg();
    }
    echo '<br><br>';
    
    echo 'Inserting 1st row in table<br>';
    $result = $db->exec("INSERT INTO fruit (item, quantity) VALUES ('Apple', '5')");
    if ($result) {
      echo 'Success';
    } else {
      echo 'Failure : ' . $db->lastErrorMsg();
    }
    echo '<br><br>';
    
    echo 'Inserting 2nd row in table<br>';
    $result = $db->exec("INSERT INTO fruit (item, quantity) VALUES ('Orange', '12')");
    if ($result) {
      echo 'Success';
    } else {
      echo 'Failure : ' . $db->lastErrorMsg();
    }
    echo '<br><br>';
    
    echo 'Closing database<br>';
    $result = $db->close();
    if ($result) {
      echo 'Success';
    } else {
      echo 'Failure : ' . $db->lastErrorMsg();
    }
    
    ?>
    
    </body>
    </html>
    
    Direct download available here :-
    steve@Desktop:~/projects/zedboard_linux$ wget https://spacewire.co.uk/tutorial/shared/repos/0024/zedboard_linux/os/petalinux/project-spec/meta-user/recipes-apps/website/files/cgi-bin/sqlite_test.php.txt -O os/petalinux/project-spec/meta-user/recipes-apps/website/files/cgi-bin/sqlite_test.php
    
    Upload the SQLite Test PHP file to PetaLinux for testing.
    steve@Desktop:~/projects/zedboard_linux$ sshpass -p root scp os/petalinux/project-spec/meta-user/recipes-apps/website/files/cgi-bin/sqlite_test.php root@192.168.2.87:/usr/libexec/apache2/modules/cgi-bin
    
    Access the webserver again by pointing at http://192.168.2.87/cgi-bin/sqlite_test.php.

    All being well the following page should be displayed. Missing Image! The SQLite service is working OK.

    17. Check phpLiteAdmin

    phpLiteAdmin is not an installable option on PetaLinux so it must be installed manually. Fortunately this only consists of two PHP files.

    Download the latest Stable version of phpLiteAdmin into ~/Downloads.

    Extract the files from the archive.
    steve@Desktop:~/projects/zedboard_linux$ unzip ~/Downloads/phpLiteAdmin_v*.zip -d os/petalinux/project-spec/meta-user/recipes-apps/website/files/cgi-bin
    Archive:  ~/Downloads/phpLiteAdmin_v1-9-8-2.zip
      inflating: os/petalinux/project-spec/meta-user/recipes-apps/website/files/cgi-bin/phpliteadmin.config.sample.php
      inflating: os/petalinux/project-spec/meta-user/recipes-apps/website/files/cgi-bin/phpliteadmin.php
      inflating: os/petalinux/project-spec/meta-user/recipes-apps/website/files/cgi-bin/readme.md
    
    Delete the readme and rename the configuration file.
    steve@Desktop:~/projects/zedboard_linux$ rm os/petalinux/project-spec/meta-user/recipes-apps/website/files/cgi-bin/readme.md
    steve@Desktop:~/projects/zedboard_linux$ mv os/petalinux/project-spec/meta-user/recipes-apps/website/files/cgi-bin/phpliteadmin.config{.sample,}.php
    
    Edit the configuration file to change the database location.
    steve@Desktop:~/projects/zedboard_linux$ subl os/petalinux/project-spec/meta-user/recipes-apps/website/files/cgi-bin/phpliteadmin.config.php
    

    phpliteadmin.config.php (partial)

    1. $directory = '.';
    2. $directory = 'db';
    Direct download available here :-
    steve@Desktop:~/projects/zedboard_linux$ wget https://spacewire.co.uk/tutorial/shared/repos/0024/zedboard_linux/os/petalinux/project-spec/meta-user/recipes-apps/website/files/cgi-bin/phpliteadmin.config.php.txt -O os/petalinux/project-spec/meta-user/recipes-apps/website/files/cgi-bin/phpliteadmin.config.php
    
    Upload the two PHP files to PetaLinux for testing.
    steve@Desktop:~/projects/zedboard_linux$ ssh-keygen -f /home/steve/.ssh/known_hosts -R 192.168.2.87
    steve@Desktop:~/projects/zedboard_linux$ ssh-keyscan -H 192.168.2.87 >> ~/.ssh/known_hosts
    steve@Desktop:~/projects/zedboard_linux$ sshpass -p root scp os/petalinux/project-spec/meta-user/recipes-apps/website/files/cgi-bin/phpliteadmin.php root@192.168.2.87:/usr/libexec/apache2/modules/cgi-bin
    steve@Desktop:~/projects/zedboard_linux$ sshpass -p root scp os/petalinux/project-spec/meta-user/recipes-apps/website/files/cgi-bin/phpliteadmin.config.php root@192.168.2.87:/usr/libexec/apache2/modules/cgi-bin
    
    Access the webserver again by pointing at http://192.168.2.87/cgi-bin/phpliteadmin.php.

    All being well the following page should be displayed. Missing Image! Log in using the password admin to hopefully reveal the cockpit page.

    The database test.db as created by sqlite_test.php should be should down the left-hand side of the page. View and edit the database by clicking on the links and entering SQL queries. Missing Image! The phpLiteAdmin service is working OK.

    18. Migration

    At this point the directory structure being used is that of Apache. There are two options moving forward :-
    1. The files from /srv/www & /srv/www/cgi-bin can be migrated to /usr/share/apache2/default-site/htdocs & /usr/libexec/apache2/modules/cgi-bin respectively.
    2. The Apache configuration file (httpd.conf) can be modified to use /srv/www & /srv/www/cgi-bin.
    The Apache configuration file as already been edited to enable CGI shell script execution, which will need to become sticky, i.e. part of the PetaLinux build process. It makes sense to go with option 2.

    Take a look at Apache's configuration file again.
    root@petalinux:~# nano /etc/apache2/httpd.conf
    
    Use the replace text command in Nano (Ctrl + \) to make the following changes to lines 221, 222, 338 & 354. Save the file and reload Apache so the updates take effect.
    root@petalinux:~# /etc/init.d/apache2 reload
    
    All being well accessing the webserver should look like it did prior to all the changes made in this tutorial.

    Check the following pages to confirm :- For the latter change the Address in the Peek/Poke table from 0x41200000 to 0x40010000 (the LED register).

    Attempt to Peek & Poke this register. The two operations should fail with the error message Failed to open /dev/mem.

    Note again that Apache is run using the daemon account, the old busybox-httpd used the root account. To access /dev/mem requires root privileges, hence the failures.

    Files can be executed using root privileges by non-root users by adding the s attribute (not recommended). Execute the following command to set root execution privileges on the three files of concern.
    root@petalinux:~# chmod a+s /srv/www/cgi-bin/{peek,poke,peekstring}
    
    Attempt to Peek & Poke the register again, this time the operations should work as expected. The Firmware Information should also now display upon pressing the Read ID button.

    Check all the modifications made in /usr/libexec/apache2/modules/cgi-bin work /srv/www/cgi by simply moving the related files.
    root@petalinux:~# mv /usr/libexec/apache2/modules/cgi-bin/{db,test-cgi,*.php} /srv/www/cgi-bin
    
    Check the following pages to confirm :-

    19. Make changes permanent

    To make the changes to PetaLinux permanent they need to be included in the build process.

    Apply a slight modification to the uptime.cgi call inside uptime.js - Add a / before cgi-bin on line 73. This is now the same as the calls to peek, poke & peekstring.
    steve@Desktop:~/projects/zedboard_linux$ subl os/petalinux/project-spec/meta-user/recipes-apps/website/files/uptime.js
    

    uptime.js (partial)

    1.   var url = "cgi-bin/uptime.cgi";
    2.   var url = "/cgi-bin/uptime.cgi";
    Direct download available here :-
    steve@Desktop:~/projects/zedboard_linux$ wget https://spacewire.co.uk/tutorial/shared/repos/0024/zedboard_linux/os/petalinux/project-spec/meta-user/recipes-apps/website/files/uptime.js -O os/petalinux/project-spec/meta-user/recipes-apps/website/files/uptime.js
    
    Do a quick & dirty conversion of index.cgi (shell script) into index.php (PHP).
    steve@Desktop:~/projects/zedboard_linux$ cp os/petalinux/project-spec/meta-user/recipes-apps/website/files/cgi-bin/index.cgi os/petalinux/project-spec/meta-user/recipes-apps/website/files/cgi-bin/index.php
    
    steve@Desktop:~/projects/zedboard_linux$ subl os/petalinux/project-spec/meta-user/recipes-apps/website/files/cgi-bin/index.php
    

    index.php

    <?php
    // Get information
    $sys_host = exec('hostname', $retval);
    $sys_time = exec('date', $retval);
    $sys_load = exec('awk \'{print $1}\' /proc/loadavg', $retval);
    $sys_up = exec('awk \'{print $1}\' /proc/uptime', $retval);
    $cpu_model = exec('grep model /proc/cpuinfo | cut -d : -f2 | tail -1 | sed \'s/\s//\'', $retval);
    $cpu_cores = exec('grep -c ^processor /proc/cpuinfo', $retval);
    $mem_total = exec('free -m | awk \'NR==2{print $2}\'', $retval);
    $mem_used = exec('free -m | awk \'NR==2{print $3}\'', $retval);
    $mem_free = exec('free -m | awk \'NR==2{print $4}\'', $retval);
    $net_mac = exec('cat /sys/class/net/eth0/address', $retval);
    $net_ip_loc = exec('ip a | grep inet | grep -vw lo | grep -v inet6 | cut -d \/ -f1 | sed \'s/[^0-9\.]*//g\'', $retval);
    $net_ip_ext = exec('wget -q -O- http://ipecho.net/plain', $retval);
    ?>
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <link href="../styles.css" rel="stylesheet">
    <title>Zedboard Webserver</title>
    </head>
    <body onload="add_register()">
    
    <div class="section"><h2>Zedboard Webserver</h2></div>
    
    <div class="section">
    <table>
    <thead>
    <tr><th colspan="3">Operating System Information <button onclick="read_os_ids()">Read ID</button></th>
    </tr>
    </thead>
    <tbody>
    <tr>
    <td style="text-align:right">Description :</td>
    <td style="text-align:left" id="oid_0">Unknown</td>
    <td><img id="osid_0" style="vertical-align:middle" src="../amber.gif" title="Unknown!" alt="Missing Image!"></td>
    </tr>
    <tr>
    <td style="text-align:right">Company :</td>
    <td style="text-align:left" id="oid_1">Unknown</td>
    <td><img id="osid_1" style="vertical-align:middle" src="../amber.gif" title="Unknown!" alt="Missing Image!"></td>
    </tr>
    <tr>
    <td style="text-align:right">Author :</td>
    <td style="text-align:left" id="oid_2">Unknown</td>
    <td><img id="osid_2" style="vertical-align:middle" src="../amber.gif" title="Unknown!" alt="Missing Image!"></td>
    </tr>
    <tr>
    <td style="text-align:right">Version :</td>
    <td style="text-align:left" id="oid_3">Unknown</td>
    <td><img id="osid_3" style="vertical-align:middle" src="../amber.gif" title="Unknown!" alt="Missing Image!"></td>
    </tr>
    <tr>
    <td style="text-align:right">Timestamp :</td>
    <td style="text-align:left" id="oid_4">Unknown</td>
    <td><img id="osid_4" style="vertical-align:middle" src="../amber.gif" title="Unknown!" alt="Missing Image!"></td>
    </tr>
    <tr>
    <td style="text-align:right">Hash :</td>
    <td style="text-align:left" id="oid_5">Unknown</td>
    <td><img id="osid_5" style="vertical-align:middle" src="../amber.gif" title="Unknown!" alt="Missing Image!"></td>
    </tr>
    </tbody>
    </table>
    <table>
    <thead>
    <tr><th colspan="3">Firmware Information <input type="submit" value="Read ID" id="read_ids" onclick="read_ids()"></th>
    </tr>
    </thead>
    <tbody>
    <tr>
    <td style="text-align:right">Description :</td>
    <td style="text-align:left" id="id_0">Unknown</td>
    <td><img id="sid_0" style="vertical-align:middle" src="../amber.gif" title="Unknown!" alt="Missing Image!"></td>
    </tr>
    <tr>
    <td style="text-align:right">Company :</td>
    <td style="text-align:left" id="id_1">Unknown</td>
    <td><img id="sid_1" style="vertical-align:middle" src="../amber.gif" title="Unknown!" alt="Missing Image!"></td>
    </tr>
    <tr>
    <td style="text-align:right">Author :</td>
    <td style="text-align:left" id="id_2">Unknown</td>
    <td><img id="sid_2" style="vertical-align:middle" src="../amber.gif" title="Unknown!" alt="Missing Image!"></td>
    </tr>
    <tr>
    <td style="text-align:right">Version :</td>
    <td style="text-align:left" id="id_3">Unknown</td>
    <td><img id="sid_3" style="vertical-align:middle" src="../amber.gif" title="Unknown!" alt="Missing Image!"></td>
    </tr>
    <tr>
    <td style="text-align:right">Timestamp :</td>
    <td style="text-align:left" id="id_4">Unknown</td>
    <td><img id="sid_4" style="vertical-align:middle" src="../amber.gif" title="Unknown!" alt="Missing Image!"></td>
    </tr>
    <tr>
    <td style="text-align:right">Hash :</td>
    <td style="text-align:left" id="id_5">Unknown</td>
    <td><img id="sid_5" style="vertical-align:middle" src="../amber.gif" title="Unknown!" alt="Missing Image!"></td>
    </tr>
    </tbody>
    </table>
    </div>
    
    <div class="section"><img src="../zedboard.png" alt="Missing Image!"></div>
    
    <div class="section">
    
    <table>
    <tr><th colspan="2">System</th></tr>
    <tr><td>Hostname</td>
    <td><?php echo $sys_host ?></td>
    </tr><tr><td>Time</td><td><?php echo $sys_time ?></td></tr>
    <tr><td>Uptime</td><td><span id="uptime_text"><?php echo $sys_up ?></span> seconds <button onclick="get_uptime()">Refresh</button> Auto :
    <select id="uptime" onchange="uptime();">
      <option value="0">Off</option>
      <option value="1">1s</option>
      <option value="5">5s</option>
    </select>
    </td></tr>
    </table>
    
    <table>
    <tr><th colspan="2">CPU</th></tr>
    <tr><td>Model</td>
    <td><?php echo $cpu_model ?></td></tr>
    <tr><td>Cores</td><td><?php echo $cpu_cores ?></td></tr>
    <tr><td>Load</td><td><?php echo $sys_load ?></td></tr>
    </table>
    
    <table>
    <tr><th colspan="2">Memory</th></tr>
    <tr><td>Total</td><td><?php echo $mem_total ?> Mb</td></tr>
    <tr><td>Used</td><td><?php echo $mem_used ?> Mb</td></tr>
    <tr><td>Free</td><td><?php echo $mem_free ?> Mb</td></tr>
    </table>
    
    <table>
    <tr><th colspan="2">Network</th></tr>
    <tr><td>MAC Address</td><td><?php echo $net_mac ?></td></tr>
    <tr><td>Internal IP</td><td><?php echo $net_ip_loc ?></td></tr>
    <tr><td>External IP</td><td><?php echo $net_ip_ext ?></td></tr>
    </table>
    
    </div>
    
    <div class="section">
    <table id="registers">
    <tr>
    <th>Address</th>
    <th>Peek Value</th>
    <th>Sel</th>
    <th>Peek</th>
    <th>Status</th>
    <th>Copy</th>
    <th>Poke Value</th>
    <th>Sel</th>
    <th>Poke</th>
    <th>Status</th>
    <th>Description</th>
    </tr>
    </table>
    <br><br>
    <input title="Add new row to end of address table" type="button" value="Add" onclick="add_row()">
    <select title="Set type of row to add to address table" id="type">
      <option value="0">Register</option>
      <option value="1">Section</option>
    </select>
    <input title="Remove last address from table" type="button" value="Remove" onclick="rem_register()">
    <input title="Peek all selected addresses in table" type="button" value="Peek All" onclick="peek_all()">
    <input title="Copy all table peek values into poke values" type="button" value="Copy All" onclick="copy_all()">
    <input title="Poke all selected addresses in table" type="button" value="Poke All" onclick="poke_all()">
    Peek Refresh :
    <select title="Set timer interval for automatic peek of table addresses" id="timer" onchange="timer()">
      <option value="0">Off</option>
      <option value="1">1s</option>
      <option value="5">5s</option>
    </select>
    Number Format :
    <select title="Set number format for peek and poke values" id="format" onchange="format()">
      <option value="0">Hexadecimal</option>
      <option value="1">Unsigned</option>
    </select>
    Configuration :
    <button title="Create configuration file from table" onclick="create_config()">Create...</button> <a title="Right click and Save Link As... to locate and rename this file" download="config.txt" id="download" href="" style="display: none">config.txt</a>
    <input title="Read configuration file into table" type="file" id="load_config">
    </div>
    
    <div class="section">Designed by Steve Haywood @ 2021</div>
    
    <script src="../uptime.js"></script>
    
    </body>
    </html>
    
    Direct download available here :-
    steve@Desktop:~/projects/zedboard_linux$ wget https://spacewire.co.uk/tutorial/shared/repos/0024/zedboard_linux/os/petalinux/project-spec/meta-user/recipes-apps/website/files/cgi-bin/index.php.txt -O os/petalinux/project-spec/meta-user/recipes-apps/website/files/cgi-bin/index.php
    
    Check out the changes.
    steve@Desktop:~/projects/zedboard_linux$ git difftool v11.0:zedboard_linux/os/petalinux/project-spec/meta-user/recipes-apps/website/files/cgi-bin/index.cgi os/petalinux/project-spec/meta-user/recipes-apps/website/files/cgi-bin/index.php
    
    Modify index.html such that it becomes an index page for accessing all the other pages.
    steve@Desktop:~/projects/zedboard_linux$ subl os/petalinux/project-spec/meta-user/recipes-apps/website/files/index.html
    

    index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <title>Zedboard webserver</title>
    </head>
    <body>
    <h3>Index</h3>
    <ul>
    <li><a href="cgi-bin/test-cgi" target=_blank>cgi-bin/test-cgi</a></li>
    <li><a href="cgi-bin/hello_world.php" target=_blank>cgi-bin/hello_world.php</a></li>
    <li><a href="cgi-bin/sqlite_test.php" target=_blank>cgi-bin/sqlite_test.php</a></li>
    <li><a href="cgi-bin/phpliteadmin.php" target=_blank>cgi-bin/phpliteadmin.php</a></li>
    <li><a href="cgi-bin/index.php" target=_blank>cgi-bin/index.php</a></li>
    </ul>
    </body>
    </html>
    
    Direct download available here :-
    steve@Desktop:~/projects/zedboard_linux$ wget https://spacewire.co.uk/tutorial/shared/repos/0024/zedboard_linux/os/petalinux/project-spec/meta-user/recipes-apps/website/files/index.html -O os/petalinux/project-spec/meta-user/recipes-apps/website/files/index.html
    
    Check out the changes.
    steve@Desktop:~/projects/zedboard_linux$ git difftool os/petalinux/project-spec/meta-user/recipes-apps/website/files/index.html
    
    Modify the website BitBake recipe to install the new & modified files.
    steve@Desktop:~/projects/zedboard_linux$ subl os/petalinux/project-spec/meta-user/recipes-apps/website/website.bb
    

    website.bb

    #
    # This file is the website recipe.
    #
    
    SUMMARY = "Simple website application"
    SECTION = "PETALINUX/apps"
    LICENSE = "MIT"
    LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
    
    SRC_URI = "file://index.html"
    SRC_URI += "file://uptime.js"
    SRC_URI += "file://zedboard.png"
    SRC_URI += "file://styles.css"
    SRC_URI += "file://cgi-bin/index.php"
    SRC_URI += "file://cgi-bin/uptime.cgi"
    SRC_URI += "file://cgi-bin/test-cgi"
    SRC_URI += "file://cgi-bin/hello_world.php"
    SRC_URI += "file://cgi-bin/sqlite_test.php"
    SRC_URI += "file://cgi-bin/phpliteadmin.php"
    SRC_URI += "file://cgi-bin/phpliteadmin.config.php"
    SRC_URI += "file://amber.gif"
    SRC_URI += "file://green.gif"
    SRC_URI += "file://red.gif"
    SRC_URI += "file://project.txt"
    
    FILES_${PN} += "/srv/www"
    
    S = "${WORKDIR}"
    
    do_install() {
         install -d ${D}/srv/www
         install -m 0644 ${S}/index.html ${D}/srv/www/index.html
         install -m 0644 ${S}/uptime.js ${D}/srv/www
         install -m 0644 ${S}/zedboard.png ${D}/srv/www
         install -m 0644 ${S}/styles.css ${D}/srv/www
         install -m 0644 ${S}/amber.gif ${D}/srv/www
         install -m 0644 ${S}/green.gif ${D}/srv/www
         install -m 0644 ${S}/red.gif ${D}/srv/www
         install -m 0644 ${S}/project.txt ${D}/srv/www
         install -d ${D}/srv/www/cgi-bin
         install -m 0777 -d ${D}/srv/www/cgi-bin/db
         install -m 0644 ${S}/cgi-bin/index.php ${D}/srv/www/cgi-bin
         install -m 0755 ${S}/cgi-bin/uptime.cgi ${D}/srv/www/cgi-bin
         install -m 0755 ${S}/cgi-bin/test-cgi ${D}/srv/www/cgi-bin
         install -m 0644 ${S}/cgi-bin/hello_world.php ${D}/srv/www/cgi-bin
         install -m 0644 ${S}/cgi-bin/sqlite_test.php ${D}/srv/www/cgi-bin
         install -m 0644 ${S}/cgi-bin/phpliteadmin.php ${D}/srv/www/cgi-bin
         install -m 0644 ${S}/cgi-bin/phpliteadmin.config.php ${D}/srv/www/cgi-bin
    }
    
    Direct download available here :-
    steve@Desktop:~/projects/zedboard_linux$ wget https://spacewire.co.uk/tutorial/shared/repos/0024/zedboard_linux/os/petalinux/project-spec/meta-user/recipes-apps/website/website.bb -O os/petalinux/project-spec/meta-user/recipes-apps/website/website.bb
    
    Check out the changes.
    steve@Desktop:~/projects/zedboard_linux$ git difftool os/petalinux/project-spec/meta-user/recipes-apps/website/website.bb
    
    Modify the peekpokecgi BitBake recipe to add root execution permissions.
    steve@Desktop:~/projects/zedboard_linux$ subl os/petalinux/project-spec/meta-user/recipes-apps/peekpokecgi/peekpokecgi.bb
    

    peekpokecgi.bb

    #
    # This is the peekpokecgi aplication recipe
    #
    #
    
    SUMMARY = "peekpokecgi application"
    SECTION = "PETALINUX/apps"
    LICENSE = "MIT"
    LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
    SRC_URI = "file://peek.c \
               file://poke.c \
               file://peekstring.c \
               file://Makefile \
              "
    FILES_${PN} += "/srv/www/cgi-bin"
    S = "${WORKDIR}"
    CFLAGS_prepend = "-I ${S}/include"
    do_compile() {
            oe_runmake
    }
    do_install() {
            install -d ${D}/srv/www/cgi-bin
            install -m 0755 ${S}/peek ${D}/srv/www/cgi-bin
            install -m 0755 ${S}/poke ${D}/srv/www/cgi-bin
            install -m 0755 ${S}/peekstring ${D}/srv/www/cgi-bin
            chmod a+s ${D}/srv/www/cgi-bin/peek
            chmod a+s ${D}/srv/www/cgi-bin/poke
            chmod a+s ${D}/srv/www/cgi-bin/peekstring
    }
    
    Direct download available here :-
    steve@Desktop:~/projects/zedboard_linux$ wget https://spacewire.co.uk/tutorial/shared/repos/0024/zedboard_linux/os/petalinux/project-spec/meta-user/recipes-apps/peekpokecgi/peekpokecgi.bb -O os/petalinux/project-spec/meta-user/recipes-apps/peekpokecgi/peekpokecgi.bb
    
    Check out the changes.
    steve@Desktop:~/projects/zedboard_linux$ git difftool os/petalinux/project-spec/meta-user/recipes-apps/peekpokecgi/peekpokecgi.bb
    
    Create an Apache BitBake append to realise the changes made to httpd.conf.
    steve@Desktop:~/projects/zedboard_linux$ mkdir -p os/petalinux/components/yocto/layers/meta-openembedded/meta-webserver/recipes-httpd/apache2
    
    Note the last entry is an addition to allow Apache to read index.php pages from directories & subdirectories without specifying the page explicitly.
    steve@Desktop:~/projects/zedboard_linux$ subl os/petalinux/components/yocto/layers/meta-openembedded/meta-webserver/recipes-httpd/apache2/apache2_%.bbappend
    

    apache2_%.bbappend

    do_install_append() {
    
    sed -i 's@^#LoadModule cgid_module /usr/libexec/apache2/modules/mod_cgid.so@LoadModule cgid_module /usr/libexec/apache2/modules/mod_cgid.so@' ${D}/${sysconfdir}/${BPN}/httpd.conf
    
    sed -i 's@^DocumentRoot "/usr/share/apache2/default-site/htdocs"@DocumentRoot "/srv/www"@' ${D}/${sysconfdir}/${BPN}/httpd.conf
    
    sed -i 's@^<Directory "/usr/share/apache2/default-site/htdocs">@<Directory "/srv/www">@' ${D}/${sysconfdir}/${BPN}/httpd.conf
    
    sed -i 's@^    ScriptAlias /cgi-bin/ "/usr/libexec/apache2/modules/cgi-bin/"@    ScriptAlias /cgi-bin/ "/srv/www/cgi-bin/"@' ${D}/${sysconfdir}/${BPN}/httpd.conf
    
    sed -i 's@^<Directory "/usr/libexec/apache2/modules/cgi-bin">@<Directory "/srv/www/cgi-bin">@' ${D}/${sysconfdir}/${BPN}/httpd.conf
    
    sed -i 's@^    DirectoryIndex index.html@    DirectoryIndex index.html index.php@' ${D}/${sysconfdir}/${BPN}/httpd.conf
    
    }
    Direct download available here :-
    steve@Desktop:~/projects/zedboard_linux$ wget https://spacewire.co.uk/tutorial/shared/repos/0024/zedboard_linux/os/petalinux/components/yocto/layers/meta-openembedded/meta-webserver/recipes-httpd/apache2/apache2_%.bbappend -O os/petalinux/components/yocto/layers/meta-openembedded/meta-webserver/recipes-httpd/apache2/apache2_%.bbappend
    
    #### Part 6 - Revision Control ####

    20. Commit new & updated files

    Check GIT status to make sure all is well and there are no spurious elements.
    steve@Desktop:~/projects/zedboard_linux$ git status -u
    On branch master
    Your branch is up-to-date with 'origin/master'.
    
    Changes not staged for commit:
      (use "git add <file>..." to update what will be committed)
      (use "git restore <file>..." to discard changes in working directory)
             modified:   os/petalinux/.petalinux/metadata      
             modified:   os/petalinux/project-spec/configs/config      
             modified:   os/petalinux/project-spec/configs/rootfs_config      
             modified:   os/petalinux/project-spec/meta-user/conf/petalinuxbsp.conf      
             modified:   os/petalinux/project-spec/meta-user/recipes-apps/peekpokecgi/peekpokecgi.bb      
             modified:   os/petalinux/project-spec/meta-user/recipes-apps/website/files/index.html      
             modified:   os/petalinux/project-spec/meta-user/recipes-apps/website/files/project.txt      
             modified:   os/petalinux/project-spec/meta-user/recipes-apps/website/files/uptime.js      
             modified:   os/petalinux/project-spec/meta-user/recipes-apps/website/website.bb      
    
    Untracked files:
      (use "git add <file>..." to include in what will be committed)
            os/petalinux/project-spec/meta-user/recipes-apps/website/files/cgi-bin/hello_world.php      
            os/petalinux/project-spec/meta-user/recipes-apps/website/files/cgi-bin/index.php      
            os/petalinux/project-spec/meta-user/recipes-apps/website/files/cgi-bin/phpliteadmin.config.php      
            os/petalinux/project-spec/meta-user/recipes-apps/website/files/cgi-bin/phpliteadmin.php      
            os/petalinux/project-spec/meta-user/recipes-apps/website/files/cgi-bin/sqlite_test.php      
            os/petalinux/project-spec/meta-user/recipes-apps/website/files/cgi-bin/test-cgi      
    
    no changes added to commit (use "git add" and/or "git commit -a")
    
    Looks good!

    Add and commit the new & updated files, create an annotated tag and push the commits & tag up to the remote repository.
    steve@Desktop:~/projects/zedboard_linux$ git add -A
    steve@Desktop:~/projects/zedboard_linux$ git add -f os/petalinux/components/yocto/layers/meta-openembedded/meta-webserver/recipes-httpd/apache2/apache2_%.bbappend
    steve@Desktop:~/projects/zedboard_linux$ git commit -a -m "Removed busybox-httpd Webserver and replaced it with a LAMP style stack of Apache, SQLite, PHP & myLiteAdmin."
    steve@Desktop:~/projects/zedboard_linux$ git push
    steve@Desktop:~/projects/zedboard_linux$ git tag -a v12.0 -m "PetaLinux, Peek/Poke, LED Runner, LAMP (Apache, SQLite, PHP & myLiteAdmin), Peek/Poke CGI, PL Access, Style Sheet, Register Bank & ID Strings with XSA from zedboard_leds_switches v5.0"
    steve@Desktop:~/projects/zedboard_linux$ git push origin v12.0
    
    steve@Desktop:~/projects/zedboard_linux$ cd os/petalinux
    
    #### Part 7 - Final checks ####

    21. Create a Production Release

    With the project area assumed clean and everything committed & pushed into the repository, a potential production release of PetaLinux (v12.0) can be produced.

    Double check GIT status.
    steve@Desktop:~/projects/zedboard_linux/os/petalinux$ git status
    On branch master
    Your branch is up-to-date with 'origin/master'.
    
    nothing to commit, working tree clean
    
    Optionally, but preferred, clear out all the superfluous files from the project area (non-tracked files).
    steve@Desktop:~/projects/zedboard_linux/os/petalinux$ git clean -fdx
    
    Optionally, but preferred, clear out the transfer area.
    steve@Desktop:~/projects/zedboard_linux/os/petalinux$ rm -rf /tftpboot/*
    
    Build/rebuild PetaLinux.
    steve@Desktop:~/projects/zedboard_linux/os/petalinux$ petalinux-build
    
    Package PetaLinux to produce the boot image BOOT.BIN, this will include the first stage boot loader zynq_fsbl.elf, the programmable logic system.bit, the Linux boot loader u-boot.elf and the device tree blob system.dtb.
    steve@Desktop:~/projects/zedboard_linux/os/petalinux$ petalinux-package --boot --force --fsbl images/linux/zynq_fsbl.elf --fpga images/linux/system.bit --uboot images/linux/u-boot.elf
    

    22. Deploy Production Release on the Zedboard

    Check the Zedboard is present on the network & PetaLinux is up and running.
    steve@Desktop:~/projects/zedboard_linux/os/petalinux$ ping -c 1 192.168.2.87
    
    Enable a pathway to PetaLinux running on the Zedboard.
    steve@Desktop:~/projects/zedboard_linux/os/petalinux$ ssh-keygen -f ~/.ssh/known_hosts -R 192.168.2.87
    steve@Desktop:~/projects/zedboard_linux/os/petalinux$ ssh-keyscan -H 192.168.2.87 >> ~/.ssh/known_hosts
    
    Upload the new PetaLinux boot files to the Zedboard.
    steve@Desktop:~/projects/zedboard_linux/os/petalinux$ sshpass -p root scp /tftpboot/{BOOT.BIN,boot.scr,image.ub} root@192.168.2.87:/media/sd-mmcblk0p1
    
    Reboot PetaLinux running on the Zedboard to make use of the new boot files.
    steve@Desktop:~/projects/zedboard_linux/os/petalinux$ sshpass -p root ssh -t root@192.168.2.87 /sbin/reboot
    

    23. Check everything is working as expected

    Access the webserver running on the Zedboard using a browser pointing at the Zedboard's IP address http://192.168.2.87.

    All being well the following webpage should be displayed. Missing Image! Click on all the links to open the various webpages to ensure they are doing what is expected.

    The last webpage shows the information tables. Click the Read ID buttons in both the Operating System Information & Firmware Information sections to read the Identification information from the OS filesystem & PL address space.

    All being well the following should be displayed in the Operating System Information & Firmware Information sections.

    There should be no unsavoury comments after the version numbers!