SELinux Configuration and Management: A Practical Linux Security Guide
Security-Enhanced Linux (SELinux) adds a policy-controlled security boundary to Linux systems. This guide explains the model behind SELinux and shows how to configure labels, booleans, ports, and policy troubleshooting without treating permissive mode or audit2allow as permanent fixes.
What Is SELinux?
SELinux is a Linux security module that implements mandatory access control (MAC). The kernel checks an SELinux policy in addition to normal UNIX permissions, access control lists, and capabilities. A process can be owned by a user with read permission and still be denied if its SELinux domain is not allowed to access the target object’s type.
This separation is useful when a service is compromised. For example, a web server may be allowed to read files labeled httpd_sys_content_t, but not to read a user’s SSH keys or write arbitrary files under /etc. The policy limits what the service can do even when the service’s UNIX account would otherwise have access.
SELinux is maintained as an upstream project and is integrated into distributions such as Red Hat Enterprise Linux, Fedora, and other Linux platforms. The Fedora SELinux project page provides background on the project and its distribution integration.
Why SELinux Exists
Traditional Linux access checks are primarily discretionary: the file owner and administrator decide which users and groups can access an object. That model is essential, but a vulnerable daemon, stolen service credential, or mistaken ownership change can make the daemon’s effective permissions too broad.
SELinux addresses this risk by separating:
- Identity and ownership: UNIX users, groups, file modes, and ACLs.
- Process confinement: The SELinux domain assigned to a running process.
- Object classification: The SELinux type assigned to a file, directory, socket, or port.
- Policy decisions: Rules that permit or deny operations between domains and types.
SELinux does not replace patching, least-privilege UNIX accounts, firewalls, or backups. It is one layer in a defense-in-depth design.
How SELinux Works
An SELinux access decision follows a path similar to this:
Application process -> kernel security hook -> process domain and object type -> loaded policy rule -> allow or deny -> AVC audit record
The process and object are represented by security contexts. A context commonly looks like:
system_u:system_r:httpd_t:s0
The fields are:
- SELinux user:
system_uin this example; this is separate from a UNIX login name. - Role:
system_r, which participates in role-based transitions. - Type:
httpd_t, the domain for an Apache process. Type enforcement is the part most administrators work with. - Level:
s0, used by the MLS/MCS portions of the policy.
Inspect the context of a process and a path with:
ps -eZ | grep '[h]ttpd'
ls -Zd /var/www/html
id -Z
The policy usually allows a domain to interact with particular types and classes, such as reading a file, binding to a port, or connecting to a database. A denial does not mean that the target is globally inaccessible; it means that this specific subject-to-object operation was not allowed by the active policy.
Policy, Domains, Types, and Labels
The default targeted policy confines selected services rather than every process. A service runs in a domain such as sshd_t or httpd_t, while files receive types such as ssh_home_t or httpd_sys_content_t. Labels are stored as extended attributes on filesystems that support them.
The policy also defines transitions. Starting a service can move a process into its service domain, and executing a correctly labeled binary can transition a process into a more restricted domain. This is why copying a file into a directory is not always enough: the file may retain an incorrect label and the service may deny access.
Modes and Policy Types
Check the current mode and loaded policy before changing anything:
sestatus
getenforce
SELinux has three modes:
| Mode | Behavior | Appropriate use |
|---|---|---|
| Enforcing | Logs denials and blocks operations not permitted by policy. | Normal production operation. |
| Permissive | Logs denials but allows the operation. | Short diagnostic or migration windows. |
| Disabled | Does not load SELinux policy. | Avoid as a troubleshooting shortcut; re-enabling can require relabeling and a reboot. |
The targeted policy is the common default. MLS policy adds sensitivity and clearance labels for environments that require multi-level separation. The policy type is not the same thing as the runtime mode.
Installing and Enabling SELinux Safely
Package names differ across distributions, so use the vendor’s package manager and documentation. On a RHEL-compatible system, the core policy and administration tools can be installed with:
sudo dnf install policycoreutils policycoreutils-python-utils selinux-policy selinux-policy-targeted setroubleshoot-server
Use the Red Hat SELinux documentation for distribution-specific package names, policy setup, and recovery guidance. Ubuntu and other distributions may ship AppArmor as the default MAC system instead; do not copy RHEL package commands onto them without checking their documentation.
Review the configuration before a reboot:
grep -E '^(SELINUX|SELINUXTYPE)=' /etc/selinux/config
For a temporary mode change during a controlled test:
sudo setenforce 0 # permissive until the next reboot
sudo setenforce 1 # enforcing
Do not use setenforce 0 as a permanent resolution. If a host has been running without labels, plan a maintenance window, confirm console or rescue access, and follow the distribution’s relabeling procedure before enforcing a policy.
Managing Labels, Booleans, and Ports
Most SELinux administration is the process of making the intended service-to-resource relationship visible to the policy.
File Contexts
Use semanage fcontext to define a persistent mapping, then use restorecon to apply the expected label:
sudo semanage fcontext -a -t httpd_sys_content_t '/srv/www(/.*)?'
sudo restorecon -Rv /srv/www
ls -Zd /srv/www /srv/www/index.html
The regular expression covers the directory and everything beneath it. A manual chcon changes the current label but is not a durable configuration: a relabel operation can remove it. Prefer semanage fcontext plus restorecon. The restorecon manual documents how the command restores default file contexts.
If a mapping already exists, inspect it before modifying it:
sudo semanage fcontext -l | grep '/srv/www'
Booleans
Booleans expose policy choices without requiring a custom policy module. List and inspect them before enabling one:
getsebool -a | grep httpd
sudo semanage boolean -l | grep httpd
Enable a narrowly scoped option persistently only when the service requirement is understood:
sudo setsebool -P httpd_can_network_connect on
The -P option writes the persistent policy store and may take time. A temporary setsebool change is useful for testing, but it will not survive a reboot. Enabling a broad boolean can grant more access than a dedicated service configuration, so document the reason and review it during hardening.
Network Ports
SELinux labels ports by service type. If a web service must listen on TCP port 8080, inspect the current assignments first:
sudo semanage port -l | grep http_port_t
sudo semanage port -a -t http_port_t -p tcp 8080
Use -m instead of -a if that port already has an SELinux port record that needs editing. This label does not open a firewall port; configure the host firewall separately.
Troubleshooting AVC Denials
A denial is a diagnostic record, not an instruction to allow every requested permission. Use a repeatable workflow:
- Reproduce the failure once, if it is safe to do so.
- Check the process domain, target context, path, port, and recent configuration changes.
- Read the AVC record and determine whether the action is expected.
- Correct a label, boolean, port mapping, UNIX permission, or service configuration when that is the root cause.
- Retest in enforcing mode and record the change.
Useful commands include:
sudo ausearch -m AVC,USER_AVC -ts recent
sudo ausearch -m AVC -ts recent | audit2why
sudo sealert -a /var/log/audit/audit.log
On systems without sealert, inspect the audit log and use audit2why where available. audit2allow can help a policy author understand a denial, but blindly installing its output can weaken confinement. Generate a module only after confirming that the access is required and that labeling or an existing boolean cannot solve the problem:
sudo ausearch -m AVC -ts recent | audit2allow -M local-service
less local-service.te
sudo semodule -i local-service.pp
Treat locally generated modules as code: review them, keep their source under version control, test them after policy updates, and remove them when the underlying application is fixed.
SELinux in Services and Containers
SELinux is most useful when the resource layout and process boundaries are deliberate.
Web and Database Services
For a web root outside the distribution default, label content as read-only web content and restore the label:
sudo semanage fcontext -a -t httpd_sys_content_t '/srv/site(/.*)?'
sudo restorecon -Rv /srv/site
Writable application directories need a type intended for the specific write operation, not a blanket permissive rule. Consult the service policy and label only the directories that actually need writes.
For a database moved to a different path, use the database policy’s documented type, then restore it. Do not assume that a type for web content is suitable for a database or upload directory.
Containers
Container isolation depends on the runtime, host policy, image, user namespace, and mounted paths. On SELinux-enabled hosts, container runtimes commonly use process and file labels to prevent one container from reading another container’s private content.
For Podman bind mounts, :Z requests a private relabel for one container, while :z requests a shared label for content used by multiple containers:
podman run --rm \
-v "$PWD/site:/usr/share/nginx/html:Z" \
-p 8080:80 \
docker.io/library/nginx:stable
Read the Podman run documentation before using relabel options on shared directories or data that another service must access. A relabel can change the security context of every file below the mount path, so never apply it to a directory containing unrelated host data.
SELinux Compared with Other Controls
SELinux is not a replacement for every Linux security mechanism. The following distinctions help choose the right control:
| Control | Primary boundary | Typical question it answers | Relationship to SELinux |
|---|---|---|---|
| UNIX permissions and ACLs | Users, groups, and object ownership | Which identities may access this path? | Checked alongside SELinux, not replaced by it. |
| SELinux | Domains, types, and policy rules | May this confined process perform this operation? | MAC layer enforced by the kernel. |
| AppArmor | Per-program path and capability profiles | Which paths and capabilities may this executable use? | Another MAC approach; distributions commonly choose one default. |
| Capabilities | Privileged kernel operations | May this process mount, change ownership, or load modules? | Often restricted by both runtime and SELinux policy. |
| Firewall | Network flows and ports | Which traffic may reach this host or service? | Separate from SELinux port labeling. |
Use the control that matches the failure or threat. A correctly labeled service can still be exposed through an open firewall, and an SELinux policy cannot repair an unpatched application.
Practical Operating Checklist
Use this checklist when introducing or reviewing SELinux:
- Confirm the current mode, policy type, and label support with
sestatus. - Keep a tested console or rescue path before changing policy or modes.
- Start in enforcing mode whenever possible; use permissive mode only for a bounded diagnostic window.
- Keep custom file-context mappings and policy modules in configuration management.
- Prefer vendor types, booleans, and port mappings over custom allow rules.
- Review AVC records in context; verify that a denial is an expected operation before allowing it.
- Test service startup, reload, upgrades, log rotation, backups, and restores after a policy change.
- Treat container bind mounts as security-sensitive host paths and choose
:Zor:zdeliberately. - Monitor policy changes and remove temporary exceptions after the application or deployment is corrected.
Common SELinux Misconceptions
“Permissive mode fixed the problem.”
Permissive mode only stops SELinux from blocking the operation. The service may still have a bad label, an incorrect UNIX permission, or a broken configuration. Use the resulting audit record to fix the cause, then return to enforcing mode.
“Every AVC denial should become an allow rule.”
Some denials identify probing, a compromised process, or a typo in a path. Others are fixed by restorecon, a boolean, or a port mapping. Investigate the subject, object, operation, and expected data flow before creating a module.
“chcon is a permanent configuration.”
chcon changes a label immediately, but the change is not the policy’s persistent file-context mapping. Use semanage fcontext and restorecon for managed systems.
“SELinux and UNIX permissions are interchangeable.”
Both layers must allow the operation. Granting a UNIX user read permission does not override a denied SELinux domain, and an SELinux allow rule does not grant a user access that UNIX permissions deny.
“Containers automatically remove the need for host MAC policy.”
Containers share a host kernel and often mount host paths. Runtime labels, image configuration, capabilities, and host policy work together; none is a substitute for the others.
Related Articles
- Linux server hardening techniques covers how SELinux fits with patching, permissions, firewalls, and centralized logging.
- Linux security with AppArmor compares a path-oriented MAC workflow with SELinux’s label and type model.
- Linux container security for beginners explains image, runtime, network, and container isolation controls.
- LDAP integration with Linux systems covers centralized identity, which complements local service confinement.
- DNS configuration on Linux covers resolver and service naming dependencies that frequently appear in Linux service deployments.

