Objective

Configure a single Ubuntu Server 22.04 LTS virtual machine to simultaneously host three critical network services: an OpenSSH server for secure remote administration, an Apache2 HTTP server for web content delivery, and a BIND9 DNS server for name resolution. The assignment required full deployment, firewall configuration with UFW, and end-to-end service verification from a separate client machine.

Tools & Technologies

  • Ubuntu Server 22.04 LTS — base operating system
  • OpenSSH Server — secure shell remote access
  • Apache2 — HTTP web server
  • BIND9 — Berkeley Internet Name Domain DNS server
  • UFW — Uncomplicated Firewall for port management
  • systemctl — service lifecycle management
  • dig / nslookup — DNS resolution verification
  • curl / wget — HTTP connectivity testing
  • VirtualBox — virtualization platform with host-only networking

Architecture Overview

flowchart TD Client[Client Machine\n192.168.56.10] -->|SSH :22| Server Client -->|HTTP :80| Server Client -->|DNS :53| Server Server[Ubuntu Server\n192.168.56.20] Server --> SSH[sshd\nOpenSSH] Server --> Web[apache2\nHTML/Virtual Hosts] Server --> DNS[named\nBIND9 Forward Zone] DNS --> Zone[lab.local zone\nA records] style Client fill:#1a1a2e,stroke:#00d4ff,color:#e0e0e0 style Server fill:#1a1a2e,stroke:#00d4ff,color:#e0e0e0 style SSH fill:#181818,stroke:#1e1e1e,color:#888 style Web fill:#181818,stroke:#1e1e1e,color:#888 style DNS fill:#181818,stroke:#1e1e1e,color:#888 style Zone fill:#1a1a2e,stroke:#00ff88,color:#e0e0e0

Step-by-Step Process

01
Base System Preparation & SSH Configuration

Updated the system, installed OpenSSH, hardened the SSH daemon configuration, and set up key-based authentication for the admin user.

sudo apt update && sudo apt upgrade -y
sudo apt install -y openssh-server

# Harden SSH config
sudo nano /etc/ssh/sshd_config
# Key settings:
# PermitRootLogin no
# PasswordAuthentication no
# PubkeyAuthentication yes
# Port 22
# AllowUsers labadmin

# Generate key pair on client, copy public key to server
ssh-keygen -t ed25519 -C "lab-admin-key"
ssh-copy-id [email protected]

sudo systemctl restart ssh
sudo systemctl enable ssh
sudo systemctl status ssh
02
Apache2 Web Server Deployment

Installed Apache2, created a custom virtual host for the lab domain, deployed a test HTML page, and enabled necessary modules.

sudo apt install -y apache2
sudo systemctl enable apache2

# Create virtual host config
sudo nano /etc/apache2/sites-available/lab.local.conf
<VirtualHost *:80>
    ServerName lab.local
    ServerAlias www.lab.local
    DocumentRoot /var/www/lab.local
    ErrorLog ${APACHE_LOG_DIR}/lab-error.log
    CustomLog ${APACHE_LOG_DIR}/lab-access.log combined
</VirtualHost>
sudo mkdir -p /var/www/lab.local
echo "<h1>Lab Server Online</h1>" | sudo tee /var/www/lab.local/index.html
sudo a2ensite lab.local.conf
sudo a2dissite 000-default.conf
sudo apache2ctl configtest
sudo systemctl reload apache2
03
BIND9 DNS Server Configuration

Installed BIND9, created a forward zone for lab.local, added A records for the server hostname and service aliases, and configured the server to listen on its static IP.

sudo apt install -y bind9 bind9utils bind9-doc

# Edit named.conf.local to add zone
sudo nano /etc/bind/named.conf.local
zone "lab.local" {
    type master;
    file "/etc/bind/zones/db.lab.local";
};
sudo mkdir -p /etc/bind/zones
sudo cp /etc/bind/db.local /etc/bind/zones/db.lab.local
sudo nano /etc/bind/zones/db.lab.local
; db.lab.local
$TTL    604800
@   IN  SOA ns1.lab.local. admin.lab.local. (
            2025010101  ; Serial
            604800      ; Refresh
            86400       ; Retry
            2419200     ; Expire
            604800 )    ; Negative TTL

@       IN  NS  ns1.lab.local.
ns1     IN  A   192.168.56.20
server  IN  A   192.168.56.20
www     IN  A   192.168.56.20
sudo named-checkconf
sudo named-checkzone lab.local /etc/bind/zones/db.lab.local
sudo systemctl enable bind9
sudo systemctl restart bind9
04
UFW Firewall Rules

Configured UFW to allow only the required service ports and denied all other inbound traffic by default.

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp comment 'SSH'
sudo ufw allow 80/tcp comment 'HTTP'
sudo ufw allow 53/tcp comment 'DNS TCP'
sudo ufw allow 53/udp comment 'DNS UDP'
sudo ufw enable
sudo ufw status verbose
05
End-to-End Service Verification

Tested all three services from the client machine, confirming SSH login, HTTP response, and DNS resolution all functioned correctly.

# SSH test
ssh [email protected] "hostname && uptime"

# HTTP test (point DNS at server first)
curl -H "Host: lab.local" http://192.168.56.20/
# Expected: <h1>Lab Server Online</h1>

# DNS test
dig @192.168.56.20 www.lab.local A
nslookup server.lab.local 192.168.56.20

# Service status summary
ssh [email protected] "systemctl is-active ssh apache2 bind9"

Complete Workflow

flowchart LR A[Install Ubuntu Server] --> B[Configure Static IP\n192.168.56.20] B --> C[Install & Harden\nOpenSSH] C --> D[Install Apache2\nCreate Virtual Host] D --> E[Install BIND9\nCreate lab.local Zone] E --> F[Configure UFW\nAllow 22/80/53] F --> G[Verify from Client\nSSH + HTTP + DNS] G --> H{All Tests Pass?} H -->|yes| I[Assignment Complete] H -->|no| J[Debug Service\nCheck Logs] J --> G style A fill:#1a1a2e,stroke:#00d4ff,color:#e0e0e0 style I fill:#1a1a2e,stroke:#00ff88,color:#e0e0e0 style H fill:#181818,stroke:#1e1e1e,color:#888 style J fill:#181818,stroke:#1e1e1e,color:#888

Challenges & Solutions

  • BIND9 refused to start — Zone file had a syntax error (missing trailing dot on SOA record). Fixed with named-checkzone which pinpointed the exact line.
  • Apache virtual host not serving content — Default site was still enabled and overriding the lab.local vhost. Resolved with a2dissite 000-default.conf.
  • DNS queries timing out through UFW — Initially only opened port 53/tcp. DNS primarily uses UDP; added ufw allow 53/udp to fix.
  • SSH key authentication failing — Permissions on ~/.ssh/authorized_keys were world-readable. Fixed with chmod 600 ~/.ssh/authorized_keys.

Key Takeaways

  • Running multiple services on one server requires careful firewall management — open only required ports per protocol (TCP vs UDP matters for DNS).
  • Always use named-checkconf and named-checkzone before restarting BIND9 — cryptic startup errors are almost always zone file syntax issues.
  • Key-based SSH authentication with PasswordAuthentication no is mandatory for any production or lab system exposed beyond localhost.
  • Apache virtual hosts must be explicitly enabled with a2ensite and the default site disabled to avoid routing conflicts.
  • Methodical service-by-service verification from a client machine is the only reliable way to confirm a multi-service deployment works end-to-end.