Nick Romney


Nick Romney


AMP stack script on Ubuntu

Nick Romney's photo
Nick Romney
·Jan 14, 2021·

7 min read

This article is about several things:

  • shell scripting with bash
  • using GitHub Actions
  • developing a re-usable script to prepare an Ubuntu server (or Docker container) to run Moodle.


  • A single bash script
  • Use functions for better programming style
  • Support installing just a few options with switches
  • Make script idempotent - to re-run without failing


  • Use a public GitHub repository
  • Use GitHub actions to lint the script
  • Use GitHub actions to quickly test whether the code works (option for an ubuntu-20.04 agent, which corresponds to the desired server, and also because I'm using Ubuntu 20.04 on Windows Subsystem for Linux 2).

Script use cases

  • Install Apache
  • Install PHP
  • Install PHP-FPM
  • Install php-mysql module
  • Install Memcached
  • Set up virtual hosts with SSL certificates (even if self-signed)
  • Backup script for code and databases - local destination, and then synced to AWS S3

Set up GitHub repository

  • Sign in to GitHub with my personal account
  • Create a new repository - [nickromney/amp-moodle], with description "Install AMP stack on Ubuntu, with optional Moodle"
    • Added a README
    • Left default branch with the new default of main
  • Under Code, choose Clone, and SSH
  • Copy
  • Open a terminal (for me, ZSH on WSL2 running Ubuntu 20.04)
  • Change the domain to to prompt for my personal SSH key while I clone the repository locally
  • git clone

Set up GitHub actions and linting

  • Check what default software is available on the Ubuntu 20.04.1 LTS virtual environment. We see that there's already some software which could speed us up:
    • curl
    • git
    • unzip
    • wget
    • AWS CLI
    • PHP 7.4.13
    • Google Chrome and ChromeDriver
    • PostgreSQL
    • MySQL 8.0.22
    • MySQL Server
  • And installed apt packages:
    • dnsutil
    • shellcheck

Set up ShellCheck

Create a GitHub workflow to lint with ShellCheck

cd amp-moodle
git checkout -b add-linting-workflow
  • In VSCode, add .github/workflows/lint.yml, and adapt the example from GitHub Action for Shellcheck, because we want to:
    • lint all branches except main (we want to protect the main branch, and ensure we only merge into main via Pull Requests)
    • specifically use the Ubuntu 20.04 image (by choosing runs-on: ubuntu-20.04 rather than runs-on: ubuntu-latest)
name: Lint

      - '**'
      - '!main'

    name: Shellcheck
    runs-on: ubuntu-20.04
    - uses: actions/checkout@v2
    - name: Run ShellCheck
      uses: ludeeus/action-shellcheck@master

This runs a workflow of two actions

  • checks out the code
  • runs shellcheck against matching files
git add .github/
git commit -m "Add linting workflow"
git push --set-upstream origin add-linting-workflow

Now we're in a position to merge the lint check to main, and then write a shell script.

  • Create Pull Request
  • Merge
  • Delete add-linting-workflow branch from GitHub


git checkout main
git fetch origin
git reset --hard origin/main

And I see

HEAD is now at 6b8e12b Merge pull request #1 from nickromney/add-linting-workflow

Run the script on merges to main

Then we need to actually run our script (which we are yet to write) on merges to main For this, we'll need an additional workflow

git checkout main
git checkout -b add-ci-workflow

Create .github/workflows/ci.yml

name: CI

      - main

    name: Run
    runs-on: ubuntu-20.04
    - uses: actions/checkout@v2
      name: Checkout Code

    - name: Run
      run: |
        [[ -f ./ ]] && ./ || echo "./ file not present"
git add .github/workflows/ci.yml
git commit -m "Add CI workflow"
git push --set-upstream origin add-ci-workflow
  • Pull Request
  • Merge

Write the bash script

git checkout main
git checkout -b php-install
  • Create a new file
  • We need a shebang to tell the script to use bash
  • Helper function to test if a command is available (using this StackOverflow answer with 3323 votes)
  • PHP function to install PHP if not available
  • We start with PHP because we believe it to be installed already

# Helper functions

checkIsCommandAvailable() {
    local commandToCheck="$1"
    if command -v "${commandToCheck}" &> /dev/null
        echo "${commandToCheck} command available"
        # propagate error to caller
        return $?

phpInstall() {
    if ! checkIsCommandAvailable php
        echo "PHP is not yet available. Starting installation of PHP"
        apt -qy install php

git add
git update-index --chmod +x ./
git commit -m "Add helper function and install PHP"
git push --set-upstream origin php-install
  • Pull Request
  • Merge
Share this