Week 1: System Planning and Distribution Selection
24/10/2025
System 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.
- Brute-force SSH attacks: This occurs when an attacker repeatedly attempts to guess login credentials to gain remote access. To prevent this, I will disable root login, reduced the number of allowed authentication attempts, and configured the firewall to restrict repeated SSH connections, significantly lowering the chance of unauthorised access.
-
Privilege escalation: This threat involves a regular user gaining administrative access, often through misconfigured permissions
or exploitation of vulnerabilities. I will mitigate this by enforcing the principle of least privilege, creating dedicated non-root user accounts,
and carefully controlling
sudoaccess to minimise the risk of elevated privilege misuse. -
Unpatched software vulnerabilities: Outdated packages can be exploited by attackers to compromise system security.
To address this, I will enable automatic updates using
unattended-upgradesand scheduled periodic manual patch reviews to ensure that the system remains fully updated with the latest security fixes.
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
- CPU-intensive: The
stress-ng --cpu 2test is expected to cause near 100% CPU utilisation on the selected cores, with minimal RAM, disk, or network usage. - RAM-intensive: The
stress-ng --vm 1 --vm-bytes 512Mtest should significantly increase memory usage, potentially triggering swapping if RAM limits are reached, while CPU and disk activity remain moderate. - Network-intensive: Using
iperf3should produce high network throughput and increased socket activity, while CPU, RAM, and disk remain lightly used. - I/O-intensive: The
dd if=/dev/zero of=testfile bs=1M count=500file creation test is expected to generate high disk write throughput and moderate CPU usage, with minimal RAM and no network activity.
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 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.
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.
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.
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:
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.
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.
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."
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
Testing Evidence
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.
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.
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.
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.