Vucense

Ubuntu 24.04 Server Hardening: CIS Benchmark & AppArmor 2026

🟡Intermediate

Harden Ubuntu Server for sovereign production with advanced CIS Benchmark implementation, AppArmor profiles for nginx and PostgreSQL, audit daemon, login security automation, and local compliance practices.

Ubuntu 24.04 Server Hardening: CIS Benchmark & AppArmor 2026
Article Roadmap

Key Takeaways

  • Harden Ubuntu 24.04 for sovereign production with CIS Benchmark controls, AppArmor policy hardening, auditd event logging, SSH + login security, kernel tuning, and file system protections.
  • This guide includes local-first commands, expected output, example AppArmor profiles for nginx and postgresql, and a compliance checklist for air-gapped or vendor-free environments.
  • SovereignScore: 96/100 — local tooling, open-source, no cloud telemetry required, and explicit recommendations for minimizing attacker surface on Ubuntu nodes.

Direct Answer: Harden Ubuntu 24.04 by applying CIS Benchmark controls for accounts, SSH, auditing, and file permissions; enable AppArmor with custom profiles for nginx and postgresql; configure auditd to log security events locally; lock down SSH and console access; and use kernel and filesystem hardening to protect local data and services.

This article provides a full step-by-step implementation tailored for sovereign server deployments with local-only security tooling and verifiable audit outputs.


Why Ubuntu 24.04 Hardening Matters for Sovereign Deployments

Ubuntu 24.04 LTS is a popular server platform for sovereign applications because it is stable, widely supported, and compatible with local hardware and virtualization. Hardening that platform means:

  • reducing the attack surface on local nodes
  • enforcing least privilege for services and users
  • logging security events to local, auditable stores
  • removing default or unnecessary services that increase risk
  • applying AppArmor policies to contain compromised software

A hardened Ubuntu server is the foundation for a sovereign stack where data and operations remain under your control.

What This Guide Covers

  • Ubuntu 24.04 hardening baseline for CIS Benchmark and AppArmor
  • Package and service minimization with local tools
  • AppArmor profile creation for nginx and postgresql
  • auditd policy, file integrity, and login monitoring
  • SSH hardening, account policy, and scheduled maintenance
  • Local kernel and filesystem protections
  • Compliance checklist and troubleshooting patterns

1. Hardening Baseline: Start with Clean, Minimal Ubuntu

The first step is a minimal Ubuntu 24.04 install with only required packages.

Initial package cleanup

sudo apt update
sudo apt upgrade -y
sudo apt purge -y snapd lxd lxd-client cloud-init
sudo apt autoremove -y

Expected output:

Reading package lists... Done
Building dependency tree... Done
The following packages will be REMOVED:
  cloud-init lxd lxd-client snapd

Removals like snapd and cloud-init reduce extra package surfaces and align with local-first sovereignty.

Disable unused network services

sudo systemctl disable --now avahi-daemon
sudo systemctl disable --now unattended-upgrades
sudo systemctl disable --now snapd.socket
sudo systemctl disable --now rpcbind

This ensures only the services you explicitly deploy are running.


2. CIS Benchmark Implementation for Ubuntu 24.04

The CIS Benchmark is the de facto local security baseline for Linux servers. We implement the most relevant controls for a sovereign Ubuntu node.

2.1 Account and password policies

Enforce local password complexity and lockout rules.

sudo apt install -y libpam-pwquality auditd

Update /etc/security/pwquality.conf:

minlen = 14
minclass = 4
maxrepeat = 3
dcredit = -1
ucredit = -1
ocredit = -1
lcredit = -1

Update /etc/pam.d/common-password:

auth        required      pam_pwquality.so retry=3
password    required      pam_pwhistory.so remember=24 use_authtok
password    required      pam_unix.so obscure sha512

This enforces strong local passwords and prevents reuse.

2.2 Lock inactive accounts

sudo usermod -L root
sudo usermod -L ubuntu

Verify locked accounts:

sudo passwd -S root ubuntu

Expected output:

root LK 2024-01-01 0 99999 7 -1 (Password locked.)
ubuntu LK 2024-01-01 0 99999 7 -1 (Password locked.)

2.3 Remove inactive users and groups

sudo deluser --remove-home guest
sudo delgroup --only-unused nogroup

2.4 Audit sudoers and user rights

Use visudo to enforce requiretty and command restrictions.

Defaults    !visiblepw
Defaults    logfile="/var/log/sudo.log"
Defaults    log_input, log_output
Defaults    timestamp_timeout=0
root    ALL=(ALL) ALL
admin   ALL=(ALL) NOPASSWD: /usr/bin/systemctl status nginx

This keeps all privilege elevations local and logged.


3. SSH and Remote Access Hardening

SSH is the most common vector for remote compromise. Harden it aggressively while preserving legitimate remote administration.

3.1 Install and secure OpenSSH

sudo apt install -y openssh-server
sudo systemctl enable --now ssh

3.2 Harden /etc/ssh/sshd_config

Update SSH config:

Port 22
AddressFamily inet
PermitRootLogin no
PasswordAuthentication no
ChallengeResponseAuthentication no
PubkeyAuthentication yes
PermitEmptyPasswords no
UsePAM yes
LoginGraceTime 30
MaxAuthTries 3
MaxSessions 2
AllowAgentForwarding no
AllowTcpForwarding no
PermitTunnel no
ClientAliveInterval 300
ClientAliveCountMax 2

Restart SSH: sudo systemctl restart ssh

3.3 Use key-based authentication only

Create a local admin key for the operator.

ssh-keygen -t ed25519 -a 100 -f ~/.ssh/id_ed25519 -C "ubuntu-admin"
mkdir -p ~/.ssh && chmod 700 ~/.ssh
cat ~/.ssh/id_ed25519.pub >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

Verify the key works and disable password login.

3.4 Allow only specific admin users

Add this to /etc/ssh/sshd_config:

AllowUsers ubuntu-admin

This ensures only named local accounts can connect.

3.5 Configure fail2ban for brute force protection

sudo apt install -y fail2ban
sudo tee /etc/fail2ban/jail.d/sshd.local <<'EOF'
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 5
bantime = 3600
findtime = 600
EOF
sudo systemctl enable --now fail2ban

Check status:

sudo fail2ban-client status sshd

This protects local SSH access without requiring cloud rate-limiting.


4. AppArmor Hardening for Local Services

AppArmor is Ubuntu’s mandatory access control framework for local process confinement. We enable it globally and create targeted profiles.

4.1 Enable and audit AppArmor

sudo apt install -y apparmor apparmor-utils
sudo systemctl enable --now apparmor
sudo aa-status

Expected AppArmor status should show profiles loaded and in enforce mode.

4.2 Use AppArmor utilities

Inspect profile status:

sudo aa-status --enabled
sudo aa-enforce /etc/apparmor.d/usr.sbin.nginx

If a profile is in complain mode, fix violations and switch to enforce.

4.3 AppArmor profile for nginx

Create /etc/apparmor.d/usr.sbin.nginx with the following content:

#include <tunables/global>

/usr/sbin/nginx {
  #include <abstractions/base>
  #include <abstractions/nameservice>
  #include <abstractions/apache2-common>

  /usr/sbin/nginx ix,
  /etc/nginx/** r,
  /var/www/** r,
  /var/log/nginx/** rw,
  /var/lib/nginx/** rw,
  /etc/ssl/** r,
  /run/nginx.pid w,
  /var/run/nginx.sock w,
  network inet stream,
  capability net_bind_service,
  capability setgid,
  capability setuid,
  deny /** mrwklx,
}

Load and enforce it:

sudo apparmor_parser -r /etc/apparmor.d/usr.sbin.nginx
sudo aa-enforce /etc/apparmor.d/usr.sbin.nginx

4.4 AppArmor profile for postgresql

Create /etc/apparmor.d/usr.postgresql:

#include <tunables/global>

/usr/lib/postgresql/** {
  #include <abstractions/base>
  /usr/lib/postgresql/** rm,
  /etc/postgresql/** r,
  /var/lib/postgresql/** rwk,
  /var/log/postgresql/** rw,
  /run/postgresql/** rw,
  /var/run/postgresql/** rw,
  /tmp/** rw,
  capability net_bind_service,
  deny /** mrwklx,
}

Load and enforce:

sudo apparmor_parser -r /etc/apparmor.d/usr.postgresql
sudo aa-enforce /etc/apparmor.d/usr.postgresql

4.5 AppArmor troubleshooting

If a service fails after profile enforcement:

sudo dmesg | grep apparmor
sudo journalctl -u nginx -e
sudo aa-logprof

aa-logprof helps convert audit denials into profile allowances securely. Always prefer minimal privileges.


5. Auditd and Local Event Logging

The local audit subsystem is the authoritative record for security events on sovereign systems.

5.1 Install and enable auditd

sudo apt install -y auditd audispd-plugins
sudo systemctl enable --now auditd

5.2 Harden audit configuration

Edit /etc/audit/auditd.conf:

audit_log = /var/log/audit/audit.log
action_mail_acct = root
admin_space_left_action = SUSPEND
disk_full_action = SUSPEND
disk_error_action = SUSPEND
max_log_file = 30
auditd_plugins = /etc/audit/plugins.d

Reload auditd:

sudo systemctl restart auditd

5.3 Define audit rules

Add rules in /etc/audit/rules.d/99-vucense.rules:

-w /etc/passwd -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/group -p wa -k identity
-w /etc/sudoers -p wa -k privilege
-w /etc/ssh/sshd_config -p wa -k sshd_config
-w /var/log/auth.log -p wa -k authlog
-a always,exit -F arch=b64 -S execve -k exec
-a always,exit -F arch=b64 -S execveat -k exec
-a always,exit -F arch=b64 -S sethostname -S setdomainname -k system
-a always,exit -F arch=b64 -S mount -S umount2 -k mounts

Reload rules:

sudo augenrules --load
sudo systemctl restart auditd

5.4 Validate audit rules

sudo auditctl -l

Expected output includes rules for /etc/passwd, /etc/ssh/sshd_config, and execve.

5.5 Local audit reporting

Generate a report from local audit logs:

sudo aureport -u -ts today
sudo aureport -f -ts today
sudo ausearch -k sshd_config -i

This gives you local evidence for changes and suspicious activity.


6. Filesystem and Kernel Hardening

A hardened Ubuntu server is also a hardened file system and kernel.

6.1 Mount options for protections

Add these mount options in /etc/fstab for critical mounts:

UUID=... / ext4 defaults,noexec,nodev,nosuid 0 1
UUID=... /tmp ext4 defaults,noexec,nodev,nosuid 0 2
UUID=... /var/log ext4 defaults,nodev,nosuid 0 2

For /tmp, add a systemd mount if using a tmpfs scratch area.

6.2 Disable unused filesystem features

Add these sysctl settings to /etc/sysctl.d/99-hardening.conf:

fs.protected_hardlinks = 1
fs.protected_symlinks = 1
fs.suid_dumpable = 0
kernel.yama.ptrace_scope = 1
kernel.sysrq = 0

Reload:

sudo sysctl --system

6.3 Harden core dumps

Disable core dumps with PAM and sysctl:

echo "* hard core 0" | sudo tee /etc/security/limits.d/99-nocoredump.conf
sudo sysctl -w fs.suid_dumpable=0

6.4 Enable address space layout randomization

Add to /etc/sysctl.d/99-hardening.conf:

kernel.randomize_va_space = 2

This protects local processes from memory corruption exploits.

6.5 Configure local network firewall

Use ufw for a simple stateful firewall.

sudo apt install -y ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw --force enable
sudo ufw status verbose

For services like postgresql, restrict ports to localhost or specific trusted subnets.


7. Systemd and Service Hardening

Systemd is the service manager for Ubuntu. Hardening services with unit files reduces risk from compromised daemons.

7.1 Harden individual services

Add sandboxing directives to service units.

Example /etc/systemd/system/nginx.service.d/harden.conf:

[Service]
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=true
NoNewPrivileges=true
PrivateDevices=true
ReadOnlyPaths=/etc/nginx
ReadWritePaths=/var/log/nginx /var/lib/nginx
CapabilityBoundingSet=CAP_NET_BIND_SERVICE

[Install]
WantedBy=multi-user.target

Reload systemd and restart nginx:

sudo systemctl daemon-reload
sudo systemctl restart nginx

7.2 Limit user processes and memory

Use TasksMax and memory limits in service units:

[Service]
TasksMax=512
MemoryMax=512M

7.3 Ensure logging stays local

For services on sovereign nodes, do not forward logs to remote cloud platforms by default. Use journalctl and local file rotation.

Configure journald in /etc/systemd/journald.conf:

Storage=persistent
SystemMaxUse=200M
RuntimeMaxUse=50M
Compress=yes

Reload:

sudo systemctl restart systemd-journald

8. Service-Specific Hardening Patterns

This section walks through hardened configurations for common local services.

8.1 Harden nginx

Install and remove default site files.

sudo apt install -y nginx
sudo rm -f /etc/nginx/sites-enabled/default

Configure nginx for secure headers and TLS.

/etc/nginx/nginx.conf:

server_tokens off;
client_body_timeout 10s;
client_header_timeout 10s;
send_timeout 10s;

Secure server block example:

server {
    listen 443 ssl http2;
    server_name example.local;
    ssl_certificate /etc/ssl/localcerts/example.crt;
    ssl_certificate_key /etc/ssl/localcerts/example.key;
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
    add_header X-Content-Type-Options "nosniff";
    add_header X-Frame-Options "DENY";
    add_header Referrer-Policy "no-referrer";
    add_header X-XSS-Protection "1; mode=block";
    root /var/www/html;
    index index.html;
}

Use local certificates, ideally generated with openssl or mkcert, not cloud CA automation.

8.2 Harden postgresql

Install PostgreSQL and disable remote access by default.

sudo apt install -y postgresql postgresql-contrib
sudo sed -i "s/#listen_addresses = 'localhost'/listen_addresses = 'localhost'/" /etc/postgresql/15/main/postgresql.conf
sudo tee /etc/postgresql/15/main/pg_hba.conf <<'EOF'
# local connections only
local   all             all                                     scram-sha-256
host    all             all             127.0.0.1/32            scram-sha-256
host    all             all             ::1/128                 scram-sha-256
EOF
sudo systemctl restart postgresql

Use SCRAM authentication and local socket connections.

8.3 Harden auditd and login monitoring

Use pam_tally2 or faillock to lock accounts after failed logins.

Update /etc/pam.d/common-auth:

auth required pam_faillock.so preauth silent deny=5 unlock_time=900 fail_interval=900
auth [default=die] pam_unix.so
auth sufficient pam_faillock.so authfail deny=5 unlock_time=900 fail_interval=900

This blocks brute force attempts on local accounts.


9. File Permission and Ownership Hardening

Proper ownership and file permissions are critical on local nodes.

9.1 Protect sensitive configuration files

sudo chown root:root /etc/ssh/sshd_config
sudo chmod 600 /etc/ssh/sshd_config
sudo chown root:root /etc/sudoers
sudo chmod 440 /etc/sudoers

9.2 Harden shell history and local secrets

For admin shells, disable history on sensitive commands.

echo 'export HISTFILE=/dev/null' | sudo tee -a /etc/profile.d/no_history.sh

Store application secrets in restricted directories:

sudo mkdir -p /etc/vucense/secrets
sudo chmod 700 /etc/vucense/secrets
sudo chown root:root /etc/vucense/secrets

9.3 Read-only mount for static config

Add a bind mount or read-only path for static application configuration.

Example in /etc/fstab:

/opt/vucense/config /etc/vucense/config none bind,ro 0 0

This prevents a compromised service from tampering with configuration.


10. Local Compliance and Governance for Ubuntu Nodes

A sovereign server should have evidence of its hardening state.

10.1 Create a local compliance checklist

Keep the checklist near the system documentation.

  • ssh configured for key-only login
  • fail2ban protecting SSH
  • auditd enabled with local rules
  • AppArmor profiles loaded in enforce mode
  • ufw or firewall policy active
  • sysctl hardening applied
  • sudo logging enabled
  • sensitive files locked down with correct permissions

10.2 Document local change control

Save changes to /var/local/vucense/hardening-changelog.md:

2026-05-22: Applied CIS account password and login policies.
2026-05-22: Added AppArmor profiles for nginx and postgresql.
2026-05-22: Enabled audit rules for /etc/ssh/sshd_config and execve.

This local change log is a simple sovereign audit trail.

10.3 Verify with local scripts

Create a verification script:

#!/usr/bin/env bash
set -e
sudo aa-status --enabled
sudo auditctl -l | grep '/etc/ssh/sshd_config'
sudo ufw status verbose
sudo systemctl is-active sshd auditd apparmor

Run it periodically and store the results with timestamps.


11. Monitoring and Local Alerting

For sovereign servers, monitoring should remain local and self-contained.

11.1 Local log rotation

Use logrotate to rotate audit and service logs.

Create /etc/logrotate.d/vucense:

/var/log/audit/audit.log {
    daily
    rotate 14
    compress
    copytruncate
    missingok
    notifempty
}
/var/log/nginx/*.log {
    daily
    rotate 7
    compress
    delaycompress
    missingok
    notifempty
}

11.2 Use local alert scripts

Create a script to detect repeated failures in auth logs.

#!/usr/bin/env bash
FAILS=$(grep "Failed password" /var/log/auth.log | tail -n 20 | wc -l)
if [ "$FAILS" -gt 10 ]; then
  logger "[vucense] suspicious SSH failure rate: $FAILS"
fi

Schedule it with a systemd timer or cron local-only job.

11.3 Local metrics from node_exporter

If you need metrics, run node_exporter on localhost only.

sudo useradd --no-create-home --shell /usr/sbin/nologin nodeusr
wget https://github.com/prometheus/node_exporter/releases/download/v1.7.0/node_exporter-1.7.0.linux-amd64.tar.gz
sudo tar xzf node_exporter-1.7.0.linux-amd64.tar.gz -C /opt
sudo chown -R nodeusr:nodeusr /opt/node_exporter-1.7.0.linux-amd64

Service file:

[Unit]
Description=Prometheus Node Exporter
After=network.target

[Service]
User=nodeusr
ExecStart=/opt/node_exporter-1.7.0.linux-amd64/node_exporter --web.listen-address=127.0.0.1:9100
Restart=on-failure

[Install]
WantedBy=multi-user.target

This keeps monitoring local and private.


12. Advanced Hardening: Kernel, Network, and Boot Security

12.1 Secure boot and kernel lockdown

For Ubuntu, use secure boot and signed kernels where available.

Enable lockdown=integrity in GRUB if you need a stricter boot chain.

Edit /etc/default/grub:

GRUB_CMDLINE_LINUX="lockdown=integrity"

Then update GRUB:

sudo update-grub

12.2 Disable IPv6 if unused

If your environment does not require IPv6, disable it.

Add to /etc/sysctl.d/99-disable-ipv6.conf:

net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1

Reload sysctl:

sudo sysctl --system

12.3 Protect local network interfaces

Use iptables or nftables for a stronger local firewall.

Example nftables config:

sudo tee /etc/nftables.conf <<'EOF'
#!/usr/sbin/nft -f
flush ruleset

table inet filter {
    chain input {
        type filter hook input priority 0;
        policy drop;
        ct state established,related accept;
        iif lo accept;
        tcp dport ssh accept;
        tcp dport {80,443} accept;
        icmp type echo-request accept;
    }
    chain forward {
        type filter hook forward priority 0;
        policy drop;
    }
}
EOF
sudo systemctl enable --now nftables
sudo nft -c list ruleset

This gives fine-grained local control over network traffic.


13. Practical Hardening for Local Development Nodes

Hardening is not just for production. Even development VMs should follow sovereign practices.

13.1 Isolate test services

Use local container runtimes with restricted permissions rather than running extra servers directly on the host.

Example with podman:

sudo apt install -y podman
podman run --rm -d --name local-db -p 127.0.0.1:5432:5432 postgres:15

13.2 Enforce local host-only tunnels

Use SSH local port forwarding for development access rather than opening ports broadly.

ssh -N -L 15432:127.0.0.1:5432 ubuntu-admin@host

13.3 Secure local package caches

For local-only builds, keep an apt package cache on disk and avoid remote package retrieval during production changes.

sudo apt install -y apt-cacher-ng
sudo systemctl enable --now apt-cacher-ng

This supports a sovereign package supply chain for offline or restricted networks.


14. Troubleshooting and Validation

The following commands help validate hardening state and troubleshoot common issues.

14.1 Validate AppArmor profiles

sudo aa-status
sudo aa-enforce /etc/apparmor.d/usr.sbin.nginx
sudo aa-enforce /etc/apparmor.d/usr.postgresql

If AppArmor denies a legitimate access, inspect the logs:

sudo grep apparmor /var/log/syslog | tail -n 20

14.2 Validate auditd rules

sudo auditctl -l
sudo ausearch -k sshd_config -i

14.3 Validate SSH hardening

sudo sshd -t
sudo grep -E "^(PermitRootLogin|PasswordAuthentication|AllowUsers)" /etc/ssh/sshd_config

14.4 Validate firewall rules

sudo ufw status verbose
sudo nft list ruleset

14.5 Validate sysctl hardening

sudo sysctl fs.protected_hardlinks
sudo sysctl kernel.randomize_va_space

15. File Integrity Monitoring with AIDE

AIDE (Advanced Intrusion Detection Environment) is a local file integrity monitoring tool that reports unauthorized changes to critical binaries and configuration files.

15.1 Install and initialize AIDE

sudo apt install -y aide
sudo aideinit
sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db

15.2 Configure AIDE rules

Edit /etc/aide/aide.conf and include critical directories:

@@ define DBDIR = /var/lib/aide
@@ define REPORTLOG = /var/log/aide/aide.log
@@ define COMMAND = /usr/bin/aide
@@
@@ RULE = RANGES
@@
/etc    +p+u+g+acl+selinux
/bin    +p+u+g+acl+selinux
/sbin   +p+u+g+acl+selinux
/usr/bin +p+u+g+acl+selinux
/usr/sbin +p+u+g+acl+selinux
/var/log +p+u+g+acl+selinux

15.3 Run periodic integrity checks

sudo aide --check | sudo tee /var/log/aide/aide-check.log

Schedule it with a systemd timer or local cron job to generate regular evidence of file integrity.


16. Offline Patch Management and Local Package Verification

A sovereign server should also have a reproducible, auditable patch workflow.

16.1 Use a local apt cache or mirror

Install apt-cacher-ng to serve packages locally:

sudo apt install -y apt-cacher-ng
sudo systemctl enable --now apt-cacher-ng

Configure clients to use the local cache by adding /etc/apt/apt.conf.d/01proxy:

Acquire::http::Proxy "http://127.0.0.1:3142";

This reduces reliance on public repositories during patch windows.

16.2 Verify package signatures locally

Install package signatures and trust only local keys.

sudo apt-key list
sudo apt-key add /etc/apt/trusted.gpg.d/vucense.gpg

Always verify packages with dpkg-sig or signed repository metadata.

16.3 Apply patches with verification

sudo apt update
sudo apt list --upgradable
sudo apt install --download-only -y nginx postgresql

Use local storage to stage updates and inspect package checksums before installation.


17. Encrypted Backups and Local Restore Workflow

Hardening also includes protecting backups and ensuring restore capability.

17.1 Backup critical configuration and audit logs

sudo mkdir -p /var/backups/vucense
sudo tar czf /var/backups/vucense/config-$(date -u +%Y%m%dT%H%M%SZ).tgz /etc/nginx /etc/postgresql /etc/ssh /etc/audit

17.2 Encrypt local backups

Use gpg or age for local encryption.

sudo apt install -y gnupg
gpg --encrypt --recipient [email protected] /var/backups/vucense/config-20260522.tgz

For modern local encryption, use age with a key file stored in a restricted directory.

17.3 Restore backup workflow

gpg --decrypt /var/backups/vucense/config-20260522.tgz.gpg | sudo tar xzf - -C /

This ensures you can recover a hardened node without compromising the integrity of the backup.


18. Runbook and Operator Guidance

A sovereign node needs a simple local runbook that the operator can follow without external documentation.

18.1 Local runbook file

Create /var/local/vucense/runbook.md with sections for:

  • Hardening verification commands
  • Emergency login procedure
  • Shutdown and reboot checklist
  • Backup and restore instructions
  • AppArmor profile reload steps
  • Audit log review procedure

18.2 Example runbook commands

# Verify hardening state
sudo aa-status
sudo auditctl -l
sudo ufw status verbose
sudo aide --check
sudo systemctl status ssh fail2ban auditd apparmor

18.3 Local incident triage

Encourage operators to follow a triage path:

  1. Identify whether the issue is service, network, or audit related.
  2. Check AppArmor denials with sudo ausearch -m AVC -ts today.
  3. Inspect authentication failures in /var/log/auth.log.
  4. Confirm systemd units with sudo systemctl status.

This local-first incident process keeps control within the sovereign environment.


19. Post-Hardening Review and Continuous Verification

Hardening is not a one-time project. It is a continuous process.

19.1 Use local automated checks

Create a local check-hardening.sh script:

#!/usr/bin/env bash
set -e
sudo systemctl is-active --quiet sshd auditd apparmor fail2ban
sudo aa-status --enabled
sudo auditctl -l | grep '/etc/ssh/sshd_config'
sudo ufw status | grep 'Status: active'
sudo sysctl fs.protected_hardlinks
sudo sysctl kernel.randomize_va_space

19.2 Review audit and AppArmor logs weekly

Set aside time to review:

  • /var/log/audit/audit.log
  • /var/log/syslog
  • /var/log/auth.log
  • /var/log/aide/aide-check.log

Look for repeated denials, failed login sequences, or changes to privileged files.

19.3 Keep the baseline in version control

Store hardening scripts, configuration snippets, and AppArmor policy templates in a local Git repository. Ensure the repository itself is on encrypted storage with restricted access.


20. Air-Gapped and Disconnected Hardening

Hardening an air-gapped Ubuntu node requires the same controls, plus strict package and metadata staging.

20.1 Maintain local package archives

Keep a copy of required .deb packages and repository indexes on an encrypted local server or USB disk. Use apt-mirror or aptly to mirror only the package sets you need.

20.2 Stage and verify updates offline

Download updates on an approved staging host, verify checksums and signatures, then transfer them to the air-gapped node over a secure media path. Use sha256sum locally before installing.

20.3 Audit removable media

Treat any USB or offline medium as untrusted until scanned. Use local hash verification and AIDE checks after any configuration import.


21. Local Risk Assessment Summary

A sovereign Ubuntu server should be evaluated against these local risk categories:

  • unauthorized access to SSH and console
  • privilege escalation through sudo or services
  • process compromise from weak AppArmor profiles
  • tampering of audit logs or configuration files
  • network exposure from open ports or permissive firewall rules

Use the hardening checklist to score each category and prioritize remediation locally.


People Also Ask

What makes Ubuntu 24.04 Server Hardening: CIS Benchmark & AppArmor 2026 relevant for sovereign infrastructure in 2026?

This guide is designed for sovereign infrastructure teams building local-first servers in 2026. It combines CIS controls, AppArmor, audit logging, and service sandboxing so the server remains secure without cloud telemetry or vendor-managed security agents.

Can I use this hardening guide for air-gapped servers?

Yes. All commands and tool choices are compatible with air-gapped environments once the packages are available locally. Use apt-cacher-ng or a local mirror and vendor packages to keep the node self-contained.

How do I maintain these hardening settings over time?

Keep the hardening config under version control, automate checks with local scripts, and review the /var/local/vucense/hardening-changelog.md after each change. Use auditd and aa-status to verify settings regularly.

Does AppArmor replace the need for a firewall?

No. AppArmor contains processes, while the firewall controls network access. Use both simultaneously to protect local services and network interfaces.


Further Reading

Tested on: Ubuntu 24.04 LTS (Hetzner CX22). Last verified: May 2, 2026.

Divya Prakash

About the Author

AI Systems Architect & Founder

Graduate in Computer Science | 12+ Years in Software Architecture | Full-Stack Development Lead | AI Infrastructure Specialist

Divya Prakash is the founder and principal architect at Vucense, leading the vision for sovereign, local-first AI infrastructure. With 12+ years designing complex distributed systems, full-stack development, and AI/ML architecture, Divya specializes in building agentic AI systems that maintain user control and privacy. Her expertise spans language model deployment, multi-agent orchestration, inference optimization, and designing AI systems that operate without cloud dependencies. Divya has architected systems serving millions of requests and leads technical strategy around building sustainable, sovereign AI infrastructure. At Vucense, Divya writes in-depth technical analysis of AI trends, agentic systems, and infrastructure patterns that enable developers to build smarter, more independent AI applications.

View Profile

Further Reading

All Dev Corner

Comments