Operating Systems Weekly Reports

By Jack Turner

Week 1: System Planning and Distribution Selection

24/10/2025

System Architecture Diagram

Systems Architecture Diagram

Distribution Selection Justification

Distribution Pros Cons
Ubuntu Server Widely supported, stable LTS, large community, compatible with VirtualBox Slightly heavier base install
Debian Extremely stable, secure, minimal setup Older packages, smaller repositories for new tools
CentOS Enterprise-level stability, SELinux enabled by default Steeper learning curve, enterprise-focused tools

After comparing several Linux server distributions, I decided to use Ubuntu Server for my project. I chose Ubuntu because it is stable, easy to configure, and well-documented, which makes it suitable for developing my command-line and remote administration skills. Although Debian is extremely reliable and secure, its slower updates and smaller repositories make it less flexible for experimenting. On the other hand, CentOS is designed more for enterprise environments and has a steeper learning curve. Overall, Ubuntu provides the best balance between usability, support, and performance for a headless SSH-based setup.

Workstation Configuration Decision

The workstation used is my host operating system running on macOS. MacOS provides built in terminal SSH access to the server virtual machine; this method ensures that all administration is performed remotely, and aligning with professional practices. VirtualBox is used to host the server image and isolating it from the host environment.

Network Configuration Documentation

Due to university network restrictions preventing LAN connections over Wi-Fi, I configured my virtual machine to use a NAT network in VirtualBox 7.2.4 instead of a host-only adapter. To enable secure remote administration, I created a port forwarding rule that maps SSH traffic from the host (MacBook) to the guest virtual machine. This forwards connections from 127.0.0.1:2222 on the host to port 22 on the virtual machine, allowing me to connect locally using the command ssh -p 2222 admin@127.0.0.1. This approach avoids university network restrictions while maintaining a realistic remote management workflow.

System Specifications

I used the uname, free, df -h, ip addr, lsb_release commands to provide the following specifications.


      # uname -a
      Linux
      
      # free -h
                    total        used        free      shared  buff/cache   available
      Mem:         2001372      246300     1165364        1024      678632     1755072
      Swap:              0           0           0
      
      # df -h
      Filesystem      Size  Used Avail Use% Mounted on
      tmpfs           196M  1.2M  195M   1% /run
      /dev/sda2        24G  2.7G   20G  12% /
      tmpfs           981M     0  981M   0% /dev/shm
      /dev/sda1       1.1G  6.4M  1.0G   1% /boot/efi
      tmpfs           196M  4.0K  196M   1% /run/user/1000
      
      # ip addr
      1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
          inet 127.0.0.1/8 scope host lo
      2: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
          inet 10.0.2.15/24 scope global dynamic enp0s8
      
      # lsb_release -a
      Distributor ID: Ubuntu
      Description:    Ubuntu 22.04 LTS
      

Week 2: Security Planning and Testing Methodology

31/10/2025

Performance Testing Plane

For this phase, I plan to design a performance testing and monitoring approach that ensures my Linux server remains stable and secure during remote administration. I will monitor resource usage using command-line tools such as top, free, and df -h to assess CPU load, memory utilisation, and disk activity. Network responsiveness will be tested using ping and traceroute, while service reliability will be checked through systemctl status ssh and log analysis with journalctl. These results will form the foundation for comparing performance before and after security hardening, helping to identify any negative impact caused by configuration changes. By maintaining a clear testing methodology and consistent monitoring approach, I aim to ensure the system remains efficient, responsive, and secure throughout the deployment.

Security Configuration Checklist

Area Action Purpose
SSH Hardening Disabled root login, limited login attempts Prevent brute-force and root access
Firewall Configuration Installed & configured UFW Restrict inbound traffic
Mandatory Access Control Verified AppArmor/SELinux active Enforce application-level security
Automatic Updates Enabled unattended-upgrades Maintain up-to-date security patches
User Priviledge Management Created limited user, removed default admin Principle of least privilege
Network Security Checked open ports Identify unnecessary exposed services

Threat Model

The threat model outlines three seperate security concerns and suggests mitigation strategies for each of them.

Week 3: Application Selection for Performance Testing

14/11/2025

Application Selection Matrix

For performance evaluation, I selected a variety of applications that each represent a different type of workload. These applications allow me to test CPU, memory, network load and disk I/O to understand how the system performs under different stress conditions.

Application Workload Type Justification
stress-ng --cpu 2 CPU-intensive Generates sustained CPU load, good for analysing processor performance.
stress-ng --vm 1 --vm-bytes 512M RAM-intensive Allows controlled memory allocation to test RAM pressure and swapping.
iperf3 Network-intensive Measures network throughput and latency under controlled conditions.
dd if=/dev/zero of=testfile bs=1M count=500 I/O-intensive Creates a large file to simulate heavy disk write operations.

Installation Documentation

All applications were installed remotely over SSH to maintain a headless, command-line focused administration environment. The following commands were executed after connecting to the server via: ssh -p 2222 admin@127.0.0.1.

Update any repositories sudo apt install
Install network testing tools sudo apt install -y iperf3
Intsall stress testing tools sudo apt install -y stress-ng
Install I/O performance analyser sudo apt intall -y fio

Resource Profiles and Usage

Monitoring Strategy

To measure system performance during each workload, I created a monitoring strategy using a range of command-line tools that provide real-time system metrics. CPU and memory usage will be observed using top and vmstat, which allow me to track load averages, process activity, and overall memory utilisation. Disk performance will be monitored using iostat and df -h to measure throughput and file system usage, while network-intensive workloads will be analysed using ss -tuln and ping to monitor socket activity and latency. Logs will be collected using journalctl to identify any unusual behaviour or performance issues. Each workload will be measured before, during, and after execution to compare performance changes across different scenarios and identify any potential bottlenecks.

Week 4: Initial System Configuration & Security Implementation

21/11/25

I focused on securing my Linux server while managing it entirely through SSH. I implemented key-based authentication, configured a restrictive firewall, created a non-root administrative user, and documented all changes. This phase strengthened the server’s security and ensured that all administration was performed remotely and securely.

Configure SSH

In this section, I configured the server to use key-based SSH authentication instead of passwords. I generated a secure key pair, added my public key to the server, and disabled password authentication in the SSH configuration. This significantly improved the security of remote access by preventing brute-force login attempts.

Configure SSH Configure SSH Config

Configure Firewall

Here, I implemented a strict firewall policy to ensure that SSH access is only permitted from my workstation. By allowing a single source IP, I reduced the server’s attack surface and ensured that no other device can attempt an SSH connection. This follows the principle of least privilege.

Configure Firewall

Manage Users

In this section, I created a dedicated non-root administrative user and granted them the necessary sudo privileges. This allowed me to disable direct root login while still being able to perform administrative tasks when required. This step improved accountability and aligned the system with Linux security best practices.

Manage Users

SSH Access Evidence

Here, I collected screenshots showing that I could successfully connect to the server via SSH after applying the security changes. These screenshots provide proof that key-based authentication works and that I can administer the system without relying on insecure methods.

SSH Access Evidence

Configuration Files

In this section, I documented the changes I made to important configuration files, such as sshd_config. I included “before and after” comparisons to clearly show how I modified system settings and explain why each change was necessary for security.

Before:

Configuration Files Before

After:

Configuration Files After

Firewall Documentation

For this part, I captured the full firewall ruleset using commands such as ufw status numbered. I explained what each rule does and how it contributes to securing the server. This documentation provides a clear overview of the system’s network-level protections.

Firewall Documentation

Remote Administration Evidence demonstrating commands executed via SSH

In the final section, I demonstrated that all system changes were carried out remotely via SSH, in line with the module’s requirements. I gathered evidence of administrative commands being executed from my workstation to show that I managed the server headlessly without relying on the VirtualBox console.

I had to update both UFW and my SSH key configuration because the VM was blocking legitimate SSH traffic and rejecting my authentication. VirtualBox NAT forwards connections from the host as coming from 10.0.2.2, not 127.0.0.1, so UFW was silently dropping the packets until I added a rule allowing SSH from the NAT gateway. At the same time, password authentication had been disabled for security, but the VM did not yet contain the correct public key from my Mac. This caused SSH to reject every login attempt until I added my key to authorized_keys and configured my Mac to use the correct private key.

SSH Evidence Config File SSH Evidence Firewall SSH Evidence Update SSH Evidence Exit

Week 5: Advanced Security and Monitoring Infrastructure

28/11/2025

Implementing Access Control Using AppArmor

To strengthen the server’s security posture, I enabled mandatory access control using AppArmor, which restricts program behaviour through profile-based rule enforcement. This adds an additional layer of defence beyond standard UNIX permissions, ensuring that even if an application is compromised, its actions remain tightly controlled by its assigned security profile. I installed the necessary AppArmor tools using sudo apt update and sudo apt install -y apparmor apparmor-utils, then ensured the service was active with sudo systemctl enable --now apparmor. To generate evidence for my journal and confirm that AppArmor was correctly enforcing policies, I used sudo aa-status to list all active profiles and their modes. This provides a clear demonstration of how access control is applied at the system level and how profile enforcement can be monitored and reported as part of continuous security management.

Configuring Automatic Security Updates

To ensure the server stays protected against newly discovered vulnerabilities, I configured automated security updates using the unattended-upgrades package. Automated patching is essential for reducing the window of exposure caused by delayed manual updates, especially on headless or remotely administered systems. I installed the update automation tools with sudo apt install -y unattended-upgrades apt-listchanges and enabled them using sudo dpkg-reconfigure --priority=low unattended-upgrades, which configures the system to automatically apply security patches. I verified that the service was functioning properly with sudo systemctl enable --now unattended-upgrades and sudo systemctl status unattended-upgrades, then collected evidence of recent patch activity using sudo journalctl -u unattended-upgrades --no-pager | tail -n 50. These commands demonstrate that the system is consistently receiving security patches without manual intervention, strengthening long-term system resilience.

Configure fail2ban

To protect the server against brute-force attacks, I deployed and configured fail2ban, which automatically monitors authentication logs and bans IP addresses that repeatedly fail login attempts. This significantly reduces the attack surface for SSH and protects against automated intrusion attempts, which are common across public networks. I began by installing fail2ban with sudo apt install -y fail2ban, then created a local jail configuration using


          sudo bash -c 'cat > /etc/fail2ban/jail.d/ssh.local EOF
          [sshd]
          enabled = true
          port = 22
          filter = sshd
          logpath = /var/log/auth.log
          maxretry = 3
          bantime = 3600
          EOF'
to enable SSH protection, set a maximum of three failed attempts, and apply a one-hour ban time. I activated the service with sudo systemctl restart fail2ban and verified its operation using both sudo fail2ban-client status and sudo fail2ban-client status sshd. These commands confirm that fail2ban is actively monitoring /var/log/auth.log and automatically enforcing bans, providing a strong intrusion detection and mitigation mechanism for the server.

Security Baseline Verification Script

The security-baseline.sh script runs on the server and automatically checks that all security controls from weeks 4 and 5 are correctly configured. It verifies AppArmor, automatic updates, fail2ban, SSH hardening, firewall rules, and authorised keys. This script is needed because it provides a quick, repeatable way to confirm that the system’s security posture is stable and has not drifted from the intended configuration.


        #!/bin/bash
        # security-baseline.sh
        # Purpose: verify the server's security configuration (Phase 4 & 5). Run as root or with sudo.
        # Usage: sudo ./security-baseline.sh
        
        set -euo pipefail
        
        # Helper: print section header
        header() {
          echo
          echo "==================== $1 ===================="
        }
        
        header "Date / Host"
        date
        hostnamectl
        
        header "1) AppArmor status"
        if command -v aa-status >/dev/null 2>&1; then
          aa-status || apparmor_status || true
        else
          echo "AppArmor tools not installed."
        fi
        
        header "2) Unattended upgrades"
        if systemctl is-active --quiet unattended-upgrades 2>/dev/null; then
          echo "unattended-upgrades: active"
          sudo journalctl -u unattended-upgrades --no-pager | tail -n 10
        else
          echo "unattended-upgrades: NOT active"
        fi
        
        header "3) fail2ban"
        if command -v fail2ban-client >/dev/null 2>&1; then
          sudo fail2ban-client status || true
          echo "SSH jail status:"
          sudo fail2ban-client status sshd || echo "sshd jail not configured"
        else
          echo "fail2ban not installed."
        fi
        
        header "4) SSH hardening checks"
        SSHD_CONFIG="/etc/ssh/sshd_config"
        echo "Checking $SSHD_CONFIG for common hardening settings..."
        sudo grep -E "^(PermitRootLogin|PasswordAuthentication|PubkeyAuthentication|PermitEmptyPasswords|ChallengeResponseAuthentication)" "$SSHD_CONFIG" || true
        
        # Check that password authentication is disabled
        if sudo grep -qE "^PasswordAuthentication\s+no" "$SSHD_CONFIG" ; then
          echo "PasswordAuthentication disabled (OK)"
        else
          echo "Warning: PasswordAuthentication not set to 'no'"
        fi
        
        # Check root login disabled
        if sudo grep -qE "^PermitRootLogin\s+no" "$SSHD_CONFIG" ; then
          echo "PermitRootLogin disabled (OK)"
        else
          echo "Warning: PermitRootLogin not set to 'no'"
        fi
        
        header "5) UFW rules (firewall)"
        if command -v ufw >/dev/null 2>&1; then
          sudo ufw status verbose
        else
          echo "UFW not installed."
        fi
        
        header "6) Authorized keys for 'admin' user"
        ADMIN_HOME=$(getent passwd admin | cut -d: -f6 2>/dev/null || echo "/home/admin")
        if [ -f "$ADMIN_HOME/.ssh/authorized_keys" ]; then
          echo "authorized_keys exists:"
          sudo ls -l "$ADMIN_HOME/.ssh/authorized_keys"
          sudo tail -n 5 "$ADMIN_HOME/.ssh/authorized_keys"
        else
          echo "No authorized_keys file for admin"
        fi
        
        header "7) Basic resource snapshot"
        echo "Memory:"
        free -h
        echo "Disk:"
        df -h /
        echo "Uptime and load:"
        uptime
        
        echo
        echo "Security baseline verification complete."
      
Verification Script 1 Verification Script 2 Verification Script 3 Verification Script 4 Verification Script 5

Remote Monitoring Script

The monitor-server.sh script runs from my workstation and connects to the server via SSH to collect live performance and security metrics. It captures information such as memory usage, disk space, active processes, and recent authentication logs, saving everything into a timestamped report. This script is important because it allows remote health monitoring without direct server access, demonstrating automated administration and early issue detection.


        #!/bin/bash
        # monitor-server.sh
        # Connect to server via SSH and collect performance metrics for remote monitoring.
        # ./monitor-server.sh admin@127.0.0.1 -p 2222
        
        set -euo pipefail
        
        # Parse args (simple)
        REMOTE="${1:-admin@127.0.0.1}"
        SSH_OPTS="-p 2222 -o BatchMode=yes -o StrictHostKeyChecking=accept-new"
        OUTDIR="./monitor-output"
        mkdir -p "$OUTDIR"
        TIMESTAMP=$(date -u +"%Y%m%dT%H%M%SZ")
        OUTFILE="$OUTDIR/metrics-$TIMESTAMP.txt"
        
        echo "Collecting metrics from $REMOTE at $TIMESTAMP"
        {
          echo "==== Host info ===="
          ssh $SSH_OPTS "$REMOTE" 'hostnamectl; uname -a'
        
          echo
          echo "==== Memory ===="
          ssh $SSH_OPTS "$REMOTE" 'free -h'
        
          echo
          echo "==== Disk ===="
          ssh $SSH_OPTS "$REMOTE" 'df -h'
        
          echo
          echo "==== Top processes (snapshot) ===="
          ssh $SSH_OPTS "$REMOTE" 'ps -eo pid,ppid,cmd,%mem,%cpu --sort=-%cpu | head -n 15'
        
          echo
          echo "==== Network connections ===="
          ssh $SSH_OPTS "$REMOTE" 'ss -tuln | head -n 20'
        
          echo
          echo "==== Recent auth logs (last 100 lines) ===="
          ssh $SSH_OPTS "$REMOTE" 'sudo tail -n 100 /var/log/auth.log || sudo journalctl -u ssh -n 100 --no-pager'
        
          echo
          echo "==== Security baseline (quick) ===="
          ssh $SSH_OPTS "$REMOTE" 'sudo /usr/local/bin/security-baseline.sh || echo "security-baseline.sh not present"'
        
        } > "$OUTFILE"
        
        echo "Saved metrics to $OUTFILE"
      

Week 6: Performance Evaluation and Analysis

5/12/2025

Documentation of Approach

I conducted performance tests using selected workloads to measure CPU, memory, disk I/O, network throughput, and latency. Baseline measurements were collected with monitoring tools (vmstat, free, iostat, ping). Stress tests were executed using stress-ng, iperf3, and dd, with outputs captured for comparison. After identifying bottlenecks, I applied two optimisations (noatime and reduced swappiness), re-ran tests, and recorded improvements. Data was organised into structured tables and visualised with charts for clear analysis

Performance Data Table

Workload Test Type CPU Usage Memory Usage Disk I/O Network Latency
Baseline Idle System 9% (top) 284 MB used / 1065 MB free
CPU-Intensive stress-ng --cpu 2 ~198% across 2 vCPUs 290 MB used
RAM-Intensive stress-ng --vm 1 --vm-bytes 512M ~15% 400 MB used / 950 MB free
Disk I/O dd if=/dev/zero of=testfile ~35% (top) 300 MB used 2.3 GB/s write throughput
Network Throughput iperf3 -c 10.0.2.2 18% (top) 620 Mbps (2 retransmits) avg 0.355 ms

Performance Visualisations

CPU Usage Ram Usage Disk I/O Network

Testing Evidence

Test Data 1 Test Data 2

Network Performance Analysis

Network performance testing was carried out to measure both latency and throughput between the virtual machine and the host system. Latency was assessed using the ping -c 20 10.0.2.2 command, which sent 20 ICMP echo requests to the host gateway and recorded a low and stable average round-trip time of approximately 0.327 ms with 0% packet loss, indicating reliable network connectivity. Network throughput was then evaluated using iperf3, with the server started on the VM using iperf3 -s and the client connecting via the loopback interface using iperf3 -c 127.0.0.1. This approach was used due to VirtualBox NAT networking limitations and allowed accurate testing of the operating system’s TCP/IP stack. The test achieved an average throughput of approximately 71.1 Gbit/s, demonstrating high network stack performance within the virtualised environment.

Network Analysis 1 Network Analysis 2 Network Analysis 3

Optimisation Analysis

System swappiness was reduced to minimise unnecessary use of swap memory and prioritise keeping active processes in physical RAM. By lowering the swappiness value using sysctl, the system is less likely to move memory pages to swap under normal workloads, reducing disk I/O and improving overall responsiveness. This optimisation is particularly beneficial for a virtualised server with sufficient available RAM, resulting in more predictable memory performance under load.

Optimisation Swappiness

The apport.service was disabled to remove unnecessary background processes related to crash reporting, which are not required in a controlled server environment. Disabling Apport reduces background resource usage and prevents the generation of diagnostic data during faults, improving system efficiency and stability. This optimisation aligns with best practices for production servers where performance and reliability are prioritised over interactive debugging features.

Optimisation Auto Service 1 Optimisation Auto Service 2

Week 7: Security Audit and System Evaluation

12/12/2025

I completed a comprehensive security audit to evaluate the overall system configuration and identify any remaining weaknesses. The audit combined automated security scanning, network analysis, access control verification, and service auditing to assess the effectiveness of security controls implemented in previous phases.

Infrastructure Security Assessment (Lynis)

Lynis was used to perform a detailed security audit of the operating system, assessing kernel configuration, authentication settings, logging, and system hardening measures. The audit was run before and after remediation to demonstrate measurable security improvements.

sudo apt install lynis -y sudo lynis audit system

Network Security Testing (nmap)

Network exposure was assessed using nmap to identify open ports and confirm that only essential services were accessible. This validated that firewall rules and service hardening were correctly applied.

nmap -sS -p- 127.0.0.1 nmap -sS -p 22 127.0.0.1

SSH Security Verification

SSH configuration was manually verified to ensure password authentication was disabled, key-based authentication was enforced, and root login was restricted. This confirms secure remote administration practices are in place.

sudo sshd -T | grep -E "passwordauthentication|pubkeyauthentication|permitrootlogin"

Access Control Verification (AppArmor)

Mandatory Access Control was verified using AppArmor to ensure that active security profiles were enforced, reducing the attack surface of system services.

sudo aa-status

Service Inventory and Justification

All enabled and running services were reviewed to ensure they were necessary for the server’s role. Non-essential services were identified and removed, while critical services such as SSH, UFW, and Fail2Ban were retained.

systemctl list-unit-files --type=service --state=enabled systemctl list-units --type=service --state=running

Risk Assessment

The system demonstrates a strong security posture following hardening and remediation. Remaining risks include potential zero-day vulnerabilities and reliance on SSH for administration. These risks are mitigated through restricted access, automated security updates, firewall controls, and intrusion detection mechanisms.

Coursework Demonstration Video

This video demonstrates the practical implementation of system configuration, security hardening, monitoring, performance testing, and auditing as required for the Operating Systems module coursework.