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.