How to Install SELinux on Debian Linux

Installing SELinux on Debian replaces AppArmor with mandatory access controls (MAC) that restrict how processes, users, and applications interact with files, devices, and network ports. Unlike discretionary access controls where users manage their own permissions, SELinux enforces system-wide policies that even root cannot bypass without proper authorization.

Common use cases for SELinux on Debian include hardening web servers to contain compromised services, meeting compliance requirements for PCI-DSS or HIPAA environments, and isolating multi-tenant applications. By the end of this guide, you will have SELinux installed and configured on Debian with the default policy active. Additionally, you will understand how to switch between enforcement modes and know how to troubleshoot common policy violations using audit logs and custom modules.

Disable AppArmor Before Installing SELinux

Debian ships with AppArmor as the default Linux Security Module (LSM). However, the kernel can only load one LSM at a time, so you must disable AppArmor before enabling SELinux.

Disabling AppArmor removes its protection from confined applications. If you decide to revert to AppArmor later, you will need to re-enable and reboot. Consider backing up any custom AppArmor profiles before proceeding.

Check if AppArmor is currently active:

sudo systemctl status apparmor

When AppArmor is active, you should see the following output:

● apparmor.service - Load AppArmor profiles
     Loaded: loaded (/lib/systemd/system/apparmor.service; enabled; preset: enabled)
     Active: active (exited) since ...
   Main PID: ... (code=exited, status=0/SUCCESS)

If AppArmor is running, you must deactivate it before installing SELinux. Therefore, use the following command to disable AppArmor:

sudo systemctl disable apparmor --now

Install SELinux Packages

First, update your package index to ensure you install the latest available versions:

sudo apt update

Then, install the core SELinux packages along with the default reference policy:

sudo apt install policycoreutils selinux-utils selinux-basics selinux-policy-default auditd policycoreutils-python-utils

This command installs the SELinux utilities, activation scripts, the default policy (which functions like a targeted policy, confining specific daemons rather than all processes), the audit daemon for logging policy violations, and the Python utilities needed for audit2allow and semanage commands.

Activate SELinux

Run the activation script to configure GRUB and prepare SELinux for the next boot:

sudo selinux-activate

The activation script produces the following output:

Activating SE Linux
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-6.x.x-amd64
Found initrd image: /boot/initrd.img-6.x.x-amd64
done
SE Linux is activated. You may need to reboot now.

Next, reboot to complete the activation:

sudo reboot

The first boot after enabling SELinux takes significantly longer than normal. The system must relabel every file on your filesystem with the correct security context. On a typical installation this can take 5-15 minutes; do not interrupt the process.

Verify SELinux Status

Once the system reboots, verify that SELinux is active:

sestatus

A properly configured system displays the following output:

SELinux status:                 enabled
SELinuxfs mount:                /sys/fs/selinux
SELinux root directory:         /etc/selinux
Loaded policy name:             default
Current mode:                   permissive
Mode from config file:          permissive
Policy MLS status:              enabled
Policy deny_unknown status:     allowed
Memory protection checking:     actual (secure)
Max kernel policy version:      33

SELinux starts in permissive mode by default, which logs policy violations without blocking them. As a result, this allows you to identify potential issues before switching to enforcing mode.

Configure SELinux Mode

Understanding SELinux modes is essential because SELinux operates in three modes that determine how it handles policy violations:

  • Enforcing: Actively blocks and logs policy violations. Use this for production systems after testing.
  • Permissive: Logs violations without blocking them. Debian defaults to this mode, allowing you to identify issues before enforcing.
  • Disabled: SELinux is completely off. Not recommended as re-enabling requires a full filesystem relabel.

Edit the Configuration File

First, open the SELinux configuration file:

sudo nano /etc/selinux/config

Then, set the SELINUX directive to your preferred mode:

To enable enforcing mode (recommended for production after testing):

SELINUX=enforcing

Alternatively, to keep permissive mode (default, logs only):

SELINUX=permissive

If you need to disable SELinux completely (not recommended):

SELINUX=disabled

Apply Configuration Changes

Finally, reboot for the mode change to take effect:

sudo reboot

Verify Mode Change After Reboot

After the system reboots, confirm the mode change took effect:

getenforce

When enforcing mode is active, you will see:

Enforcing

Conversely, permissive mode displays:

Permissive

Configure Policy Settings

The /etc/selinux/config file also contains additional policy settings:

SETLOCALDEFS: Controls whether SELinux uses locally defined file contexts. The default value of 0 uses only the policy-provided contexts, which is appropriate for most systems:

SETLOCALDEFS=0

SELINUXTYPE: Additionally, this directive defines which policy to load. On Debian, the available options are:

  • default — The standard policy that confines specific daemons and services (recommended)
  • mls — Multi-Level Security for environments requiring classified data handling

The installation process already configures the default policy:

SELINUXTYPE=default

Debian uses default as its policy name, which functions like the “targeted” policy found on Red Hat-based distributions—it confines specific services rather than all processes. Do not change this to “targeted” as that policy type does not exist on Debian.

Configure SELinux for a Web Server

If you run a web server such as Apache or Nginx on Debian, you may need to configure SELinux to allow custom ports. You already have the semanage utility from the initial package installation.

First, check which ports are already allowed for HTTP traffic:

sudo semanage port -l | grep http_port_t

This command shows the default HTTP ports allowed by SELinux:

http_port_t                    tcp      80, 443, 488, 8008, 8009, 8443, 8448

To add a custom port such as 8080, use the -a flag. If the port is already defined under another type, use -m to modify it instead:

sudo semanage port -a -t http_port_t -p tcp 8080

SELinux assigns port 8080 to http_cache_port_t by default. On Debian 11 and 12, you will see an error: “Port tcp/8080 already defined.” In this case, use -m (modify) instead of -a (add): sudo semanage port -m -t http_port_t -p tcp 8080. Debian 13 automatically converts add to modify when a port exists.

Confirm that SELinux now allows the port:

sudo semanage port -l | grep http_port_t

After adding the port, the output now includes 8080:

http_port_t                    tcp      8080, 80, 443, 488, 8008, 8009, 8443, 8448

Similarly, to set a custom file context for a directory (for example, allowing a web server to access content outside the default document root):

sudo semanage fcontext -a -t httpd_sys_content_t "/srv/www(/.*)?"

Afterward, apply the context to existing files:

sudo restorecon -Rv /srv/www

The command confirms the context change with the following output:

Relabeled /srv/www from unconfined_u:object_r:var_t:s0 to unconfined_u:object_r:httpd_sys_content_t:s0

Troubleshoot Common SELinux Issues

SELinux denials are the most common issue administrators encounter. Consequently, the following techniques help identify and resolve policy violations. For comprehensive firewall configuration alongside SELinux, see our guides on installing UFW on Debian and configuring Fail2Ban on Debian.

Restore Default File Contexts

Incorrect file contexts are a common cause of SELinux denials. If you moved or copied files without preserving contexts, you can restore them with restorecon. For instance, to fix contexts in the default web root:

sudo restorecon -Rv /var/www/html

When restorecon relabels files, it displays output similar to:

Relabeled /var/www/html from unconfined_u:object_r:var_t:s0 to unconfined_u:object_r:httpd_sys_content_t:s0

If no files needed relabeling, the command completes silently with no output.

Test with Permissive Mode

To determine whether SELinux is blocking an application, temporarily switch to permissive mode:

sudo setenforce 0

Then, verify the mode change:

getenforce

The output should confirm permissive mode:

Permissive

Test your application. If it works now, SELinux policies caused the issue—check the audit logs to identify the specific denial. Remember to switch back to enforcing mode once you have completed testing:

sudo setenforce 1

Confirm that enforcing mode is now active:

getenforce

The output should display:

Enforcing

Review SELinux Audit Logs

The audit daemon (auditd) logs all SELinux policy violations to /var/log/audit/audit.log. First, verify the audit service is running:

sudo systemctl status auditd

An active audit service displays the following:

● auditd.service - Security Auditing Service
     Loaded: loaded (/lib/systemd/system/auditd.service; enabled; preset: enabled)
     Active: active (running) since ...

Once confirmed, view recent denials:

sudo ausearch -m AVC,USER_AVC -ts recent

Alternatively, search the raw log for denied actions:

sudo grep 'denied' /var/log/audit/audit.log | tail -20

Example AVC denial output:

type=AVC msg=audit(1234567890.123:456): avc:  denied  { read } for  pid=1234 comm="httpd" name="index.html" dev="sda1" ino=123456 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:var_t:s0 tclass=file permissive=0

Each AVC denial entry shows the process (comm="httpd"), the action attempted ({ read }), and the target resource (name="index.html"). The security contexts (scontext and tcontext) reveal why SELinux denied the access. Subsequently, you can use this information to create targeted policy exceptions.

Create Custom Policy Modules with audit2allow

When standard troubleshooting does not resolve a denial, you can use audit2allow to generate a custom policy module from the audit logs.

For example, to create a custom policy for a specific issue, execute:

sudo grep 'denied' /var/log/audit/audit.log | audit2allow -M mycustommodule
sudo semodule -i mycustommodule.pp

Next, confirm that SELinux loaded the module:

sudo semodule -l | grep mycustommodule

If the module installed successfully, the output displays:

mycustommodule

Manage SELinux Booleans

In addition to custom modules, SELinux booleans provide on/off switches for specific policy features. To list all available booleans and their current state:

sudo getsebool -a | grep httpd

Example output showing HTTP-related booleans:

httpd_can_network_connect --> off
httpd_can_network_connect_db --> off
httpd_can_sendmail --> off
httpd_enable_cgi --> on

Based on the output above, you can enable a specific boolean. For example, to allow Apache to make network connections:

sudo setsebool -P httpd_can_network_connect 1

The -P flag makes the change persist through reboots. To verify the boolean is now enabled:

getsebool httpd_can_network_connect

The output confirms the boolean is active:

httpd_can_network_connect --> on

Remove SELinux from Debian

If you need to revert to AppArmor or remove SELinux entirely, follow the steps below carefully. Improper removal can cause boot issues.

Disable SELinux Before Removal

First, set SELinux to permissive mode temporarily:

sudo setenforce 0

Next, edit the SELinux configuration to disable it permanently:

sudo nano /etc/selinux/config

Change the SELINUX line to:

SELINUX=disabled

Save the file and exit.

Remove SELinux Kernel Parameters

Use the built-in deactivation script to remove SELinux kernel parameters from GRUB:

sudo selinux-activate disable

The deactivation script produces the following output:

Deactivating SE Linux
Generating grub configuration file ...
done
SE Linux is deactivated.  You may need to reboot now.

The selinux-activate disable command removes both selinux=1 and security=selinux kernel parameters from GRUB. This is more reliable than manually editing /etc/default/grub.

Remove SELinux Packages

With the kernel parameters removed, proceed to remove the SELinux packages:

sudo apt remove --purge selinux-basics selinux-policy-default policycoreutils policycoreutils-python-utils selinux-utils auditd

Afterward, remove orphaned dependencies:

sudo apt autoremove

Reboot and Verify Removal

Optionally re-enable AppArmor before rebooting:

sudo systemctl enable apparmor

Reboot to apply changes:

sudo reboot

After reboot, verify SELinux is removed:

sestatus

After you successfully remove SELinux, the output shows:

SELinux status:                 disabled

Alternatively, if the command is not found, SELinux has been completely removed. Finally, verify AppArmor is active if you re-enabled it:

sudo systemctl status apparmor

Conclusion

You now have SELinux configured on Debian with the default policy providing mandatory access controls. The key techniques covered include switching between enforcing and permissive modes, using semanage to configure port and file contexts, analyzing denials with ausearch, and creating custom policy modules with audit2allow. For production systems, start in permissive mode to identify violations, then switch to enforcing mode once your policies are tuned. Furthermore, consider combining SELinux with automatic security updates to maintain a hardened Debian server.

2 thoughts on “How to Install SELinux on Debian Linux”

    • Thanks for the suggestion, hmidani. You were right that auditd is essential for troubleshooting. The article didn’t include it when you commented in April. The guide has been updated to include auditd along with policycoreutils-python-utils.

      The updated command is:

      sudo apt install policycoreutils selinux-utils selinux-basics selinux-policy-default auditd policycoreutils-python-utils

      Thanks for helping improve the guide.

      Reply

Leave a Comment