Running Apache with AppArmor on Debian 12 doesn’t have to be messy. Forget about mod_apparmor, forget about β€œhats”, and ignore the dynamic module rabbit hole. We’ll use a simple, maintainable static AppArmor profile to secure our web server β€” and we’ll do it nerd-style.


πŸ›‘οΈ What is AppArmor and why should you care?

AppArmor is a Linux security module that restricts what individual applications can access β€” files, sockets, system resources. It uses per-program profiles to define access rules. If a process tries to do something it’s not supposed to, AppArmor can log or block it. This reduces the impact of exploits and mistakes. For example, even if Apache is compromised, it won’t be able to read or write beyond its defined directories. It’s lightweight, easier to manage than SELinux, and perfectly suited for locked-down Linux servers.


🎯 Goal

  • βœ… No mod_apparmor
  • βœ… No virtualhost β€œhats”
  • βœ… Just a plain, static AppArmor profile
  • βœ… Apache with Nextcloud at /var/www/html/nextcloud
  • βœ… Data storage at /data
  • βœ… PHP-FPM via /run/php/php8.2-fpm.sock

🧩 The AppArmor Profile

Place this file as:

/etc/apparmor.d/usr.sbin.apache2

# AppArmor profile for Apache
#include <tunables/global>

profile /usr/sbin/apache2 {

  # Apache binary and required libraries
  /usr/sbin/apache2 mr,
  /lib/** mr,
  /lib64/** mr,
  /usr/lib/** mr,

  # Apache configuration
  /etc/apache2/** r,

  # Web root (Nextcloud)
  /var/www/html/nextcloud/** r,

  # Nextcloud data directory
  /data/** rw,

  # PHP-FPM socket communication
  /run/php/php8.2-fpm.sock rw,

  # Logging
  /var/log/apache2/ rw,
  /var/log/apache2/** rwk,

  # Required capabilities
  capability net_bind_service,
  capability setuid,
  capability setgid,

  # OpenSSL configuration
  /etc/ssl/openssl.cnf r,

  # Stream socket access
  network inet stream,
  network inet6 stream,
  network unix stream,

  # System configuration files
  /etc/ld.so.cache r,
  /etc/gai.conf r,
  /etc/nsswitch.conf r,
  /etc/passwd r,
  /etc/group r,

  # Datagram and raw network sockets
  network inet dgram,
  network inet6 dgram,
  network netlink raw,
  network unix dgram,

  # DNS and hostname resolution
  /etc/host.conf r,
  /etc/hosts r,
  /run/systemd/resolve/resolv.conf r,

  # Timezone data
  /usr/share/zoneinfo/Etc/UTC r,
  /usr/share/zoneinfo/Europe/Berlin r,

  # IPv6 configuration
  /proc/sys/net/ipv6/conf/all/disable_ipv6 r,

  # Random and zero devices
  /dev/urandom r,
  /dev/zero rw,
  /dev/null rw,

  # Shared memory
  /dev/shm/** rwk,

  # SSL certificates (Let's Encrypt)
  /etc/letsencrypt/archive/nextcloud.cvjm-gn.de/fullchain1.pem r,
  /etc/letsencrypt/archive/nextcloud.cvjm-gn.de/privkey1.pem r,
  /etc/letsencrypt/live/nextcloud.cvjm-gn.de/fullchain.pem r,
  /etc/letsencrypt/live/nextcloud.cvjm-gn.de/privkey.pem r,
  /etc/letsencrypt/** r,

  # Diffie-Hellman parameters
  /etc/ssl/certs/dhparam.pem r,

  # MIME type detection
  /etc/mime.types r,

  # Kernel configuration access
  /proc/sys/kernel/ngroups_max r,

  # Apache runtime PID directory
  /run/apache2/** rwk,

  # Allow signaling systemd (for notify/reload etc.)
  signal peer=unconfined,
  signal (receive) peer=/lib/systemd/systemd,
}

πŸ”Ž Tip: The profile is in complain mode to log violations instead of enforcing them. Switch to enforce once you’re confident it works.

sudo aa-enforce /etc/apparmor.d/usr.sbin.apache2

πŸ”§ Deploying via Ansible

If you’re using Ansible, here’s how you can deploy the profile (assuming you store the file in files/usr.sbin.apache2):

- name: Upload AppArmor profile for Apache
  copy:
    src: files/usr.sbin.apache2
    dest: /etc/apparmor.d/usr.sbin.apache2
    owner: root
    group: root
    mode: '0644'

- name: Reload AppArmor profile
  command: apparmor_parser -r /etc/apparmor.d/usr.sbin.apache2
  notify: Restart Apache

And don’t forget the handler:

- name: Restart Apache
  service:
    name: apache2
    state: restarted

πŸ“‹ AppArmor Cheat Sheet

Want a quick reference for AppArmor management? Here’s a handy list of common commands for inspecting, managing, and debugging AppArmor on Debian-based systems.

πŸ” STATUS & INFO
sudo aa-status
# Show loaded profiles and their mode (enforce/complain)

sudo apparmor_status
# Same as above (older syntax, still valid)

πŸͺ΅ VIEW LOGS
sudo journalctl -k | grep -i apparmor
# Kernel-level logs for AppArmor denials

sudo dmesg | grep -i apparmor
# Alternative way to see recent denials

πŸ“¦ INSTALL APPARMOR TOOLS
sudo apt install apparmor-utils
# Installs tools like aa-enforce, aa-complain, etc.

βš™οΈ PROFILE MANAGEMENT
sudo aa-enforce /etc/apparmor.d/PROFILE
# Enforce mode: block everything not explicitly allowed

sudo aa-complain /etc/apparmor.d/PROFILE
# Complain mode: only log violations, don’t block

sudo aa-disable /etc/apparmor.d/PROFILE
# Disable a profile completely

sudo apparmor_parser -r /etc/apparmor.d/PROFILE
# Reload a profile after editing

πŸ” TEMPORARILY DISABLE APPARMOR (until reboot)
sudo systemctl stop apparmor
# Stops AppArmor service β€” disables all active profiles

πŸ”’ ENABLE APPARMOR
sudo systemctl start apparmor
# Starts AppArmor and loads profiles

sudo systemctl restart apparmor
# Reloads all profiles

🚫 PERMANENTLY DISABLE APPARMOR (via GRUB)
sudo nano /etc/default/grub
# Add: GRUB_CMDLINE_LINUX_DEFAULT="quiet splash apparmor=0"

sudo update-grub
sudo reboot
# AppArmor will be disabled after reboot

πŸ“Œ Summary

This setup gives you a static AppArmor profile for Apache, no dynamic modules or extra dependencies. Just a simple rule-based file to lock down your web server. It’s nerdy. It’s clean. And it’s one more layer of defense in your stack.

By raphael

Leave a Reply