SELinux (Security-Enhanced Linux) is an additional security layer that operates above the traditional Linux Discretionary Access Control (DAC) system. Most VPS administrators disable SELinux entirely because they don't understand how it works, but when implemented correctly, SELinux is a powerful Linux-level protection mechanism that significantly reduces risk from unauthorized access. This guide teaches you how to properly configure SELinux on CentOS Stream, Rocky Linux, or AlmaLinux, troubleshoot denial errors when they occur, and use audit2allow to create targeted policies instead of disabling SELinux entirely.
In short: SELinux is a security layer that works above standard Linux permissions. It has three modes: Enforcing (actively blocks violations, most secure), Permissive (logs violations only), and Disabled (completely off). To prevent application breakage while maintaining security, examine audit logs and use audit2allow to create policies that grant only necessary permissions. Never just disable SELinux.
What is SELinux and How Does It Differ from Standard Linux Permissions
Traditional Linux uses Discretionary Access Control (DAC), which bases access solely on user and group ownership. For example, if the file /var/www/html/index.php is owned by root, the Apache process running as user www-data cannot read it. However, if Apache is compromised, an attacker gains all permissions that www-data has, including access to any files www-data can reach. This is where the limitation of traditional permission model becomes clear.
SELinux adds a second layer called Mandatory Access Control (MAC), which operates independently from DAC permissions. Instead of restricting access based only on user/group membership, SELinux assigns a "role" and "context" to each process and file. For example, Apache might run with context "httpd_t" and web files might have context "httpd_sys_content_t". The SELinux kernel will only allow httpd_t to read files labeled httpd_sys_content_t, regardless of what other permissions www-data has. Even if Apache contains a vulnerability and is compromised, the attacker cannot access files that SELinux policy forbids.
Tip: Think of SELinux as a "server-level firewall" or additional checkpoint. Standard DAC permissions are like "authentication" (proving who you are), but SELinux is an "authorization layer" (verifying you should actually be allowed to do this according to system policy).
The Three Modes of SELinux
SELinux operates in three distinct modes.
- Enforcing: SELinux actively enforces policy. If a process attempts an action that policy forbids, SELinux denies the action and logs the violation. This is not a warning mode—the operation is actually blocked. Enforcing mode provides maximum security, but may break applications if policy doesn't grant sufficient permissions.
- Permissive: SELinux logs violations but does not enforce them. Any action that violates policy is allowed to proceed, but details are recorded in the audit log. Permissive mode is useful for testing and troubleshooting when you want to see what a process is trying to do without worrying about it being blocked.
- Disabled: SELinux is completely off, no checks or logging occurs. If you set this mode, you must reboot the VPS to re-enable SELinux (changing from disabled to enabled requires relabeling all files, which takes considerable time).
Check Current SELinux Status
Before making any changes, check the current SELinux status on your VPS using getenforce
getenforce
This command returns a single line: Enforcing, Permissive, or Disabled. For more detailed information, use sestatus
sestatus
The output shows the current mode, active policy, file context information, and more. For even greater detail, add the -v flag
sestatus -v
Change SELinux Mode
To temporarily change SELinux mode (until next reboot), use setenforce
setenforce 0
The above sets SELinux to Permissive mode (0 = Permissive, 1 = Enforcing). This change is temporary only. To make the change persistent, edit /etc/selinux/config as root
sudo nano /etc/selinux/config
Find the line starting with SELINUX= and set your desired value
SELINUX=enforcing
Valid values are enforcing, permissive, or disabled. If you change from disabled to either enforcing or permissive, you must reboot because the system needs to relabel all files.
Warning: When changing SELinux from disabled to enforcing or permissive, the system must relabel every file (scanning all files to assign correct contexts). This process can take several hours depending on data volume. During relabeling in enforcing mode, some services may become blocked or crash. Plan this change carefully.
Understanding SELinux Contexts
A SELinux context has the format user:role:type:level. The most important part for normal operations is the type (the classification). A typical context for web files looks like
httpd_sys_content_t
The context for the Apache process itself
httpd_t
To see what context a file has, use ls with the -Z flag
ls -Z /var/www/html/index.php
To see the context of running processes
ps auxZ | grep httpd
The output displays the context assigned to each running process.
Common SELinux Commands
chcon - Change File Context
To change the context of a file or directory, use chcon (change context)
chcon -t httpd_sys_rw_content_t /var/www/html/uploads/
The -t flag means change the type only. The above command changes the type of the uploads directory to httpd_sys_rw_content_t, allowing Apache to read and write files there.
To change context recursively for a directory and all files inside it, add the -R flag
chcon -Rt httpd_sys_rw_content_t /var/www/html/uploads/
restorecon - Restore Default Context
If you change context incorrectly or need to restore files to their policy-defined defaults, use restorecon
restorecon -v /var/www/html/
This command reads what contexts should be according to SELinux policy, then adjusts files to match. The -v flag shows verbose output (which files were changed).
To recursively update contexts for a directory and all contents
restorecon -Rv /var/www/html/
semanage - Manage Policy and Contexts
semanage is the primary tool for managing SELinux policy. A common use case is permanently defining the context for a directory
semanage fcontext -a -t httpd_sys_rw_content_t "/var/www/html/uploads(/.*)?"
This tells SELinux that /var/www/html/uploads and all files and directories inside should have context httpd_sys_rw_content_t permanently. After setting this, run restorecon to apply it to existing files
restorecon -Rv /var/www/html/uploads/
SELinux Booleans
SELinux includes settings called booleans that control specific aspects of policy behavior. An important example is httpd_can_network_connect, which allows Apache to make outbound network connections (necessary for applications that connect to external databases, APIs, or services).
To see all available booleans and their current state
getsebool -a
To enable a specific boolean
setsebool -P httpd_can_network_connect on
The -P flag makes the change persistent across reboots. Without -P, the setting is lost after reboot.
Real-World Scenario: Apache Cannot Connect to Database
Suppose you set up a new Rocky Linux VPS, install Apache, and run a PHP web application that connects to MySQL on a different server. If SELinux is set to Enforcing, you might get "Connection refused" or timeout errors when the application tries to reach the database, even though firewall rules and Linux permissions are correct.
To verify SELinux is the cause, temporarily change to Permissive mode to log violations without blocking them
sudo setenforce 0
Then access the web application again and trigger database operations. If it works now and displays data from the database, SELinux is definitely the cause of the problem.
Using Audit Logs to Find the Issue
When SELinux denies an action, it logs details to /var/log/audit/audit.log. To see recent denial entries
tail -30 /var/log/audit/audit.log | grep denied
A denial line looks something like
type=AVC msg=audit(1625126789.123:456): avc: denied { connect } for pid=1234 comm="apache" saddr=192.168.1.1 sport=12345 daddr=10.0.0.2 dport=3306
This shows Apache (PID 1234) tried to create a network connection to 10.0.0.2:3306 (MySQL) but SELinux blocked it. For easier reading, use ausearch
ausearch -m AVC -ts recent | head -30
The -m AVC flag searches for AVC message types, and -ts recent finds only recent events.
Using audit2allow to Create Policy
Instead of disabling SELinux entirely, use audit2allow to generate policy that grants necessary permissions. First, install required packages
sudo yum install -y audit policycoreutils-python-utils
Then generate a policy module by reading audit log denials
sudo audit2allow -a -M myapp
The -a flag means process all unhandled denials in the audit log, and -M creates a module named myapp. This generates myapp.pp (policy package) and myapp.te (type enforcement file).
Before loading the policy, review the myapp.te file to see what permissions audit2allow generated
cat myapp.te
If the output looks reasonable and not overly broad, load the policy
sudo semodule -i myapp.pp
Once the policy is loaded, switch SELinux back to Enforcing mode
sudo setenforce 1
Test the web application again. It should now work without errors. If additional denials appear, repeat the audit2allow process.
Tip: If audit2allow generates overly permissive policy (allowing everything), don't load it. Delete the generated files, keep SELinux in Permissive a bit longer, then try audit2allow again with narrower conditions or create the policy manually to be more specific.
Secure SELinux Configuration Approach
Proper SELinux configuration means not just disabling it, but following a methodical troubleshooting workflow
- Set SELinux to Permissive mode temporarily to log violations without enforcing
- Run your application and test all functionality thoroughly—test reading, writing, network connections, and any other operations your app performs
- Review the audit log for SELinux denials related to your application
- Use audit2allow to generate policy allowing only necessary actions
- Review the generated .te file to ensure it permits only required operations
- Load the policy module using semodule -i
- Switch SELinux back to Enforcing mode
- Test your application again thoroughly to ensure all features work
By following this workflow, you create SELinux policy tailored to your specific application needs, providing real security benefits while avoiding the pitfall of completely disabling the system.
Summary
SELinux is a powerful Linux-level security mechanism that is often misunderstood. Many administrators completely disable it rather than learning to use it properly. By breaking it down into manageable steps, understanding modes, contexts, audit logs, and the audit2allow workflow, you can confidently configure SELinux on your VPS and add a genuine layer of defense that modern applications require.
Frequently Asked Questions
Does SELinux slow down the server significantly?
SELinux overhead is typically minimal—usually 1-5% performance impact due to additional context checks. If your VPS is suffering severe CPU performance issues, the problem likely lies elsewhere. In most cases, SELinux impact is negligible.
I disabled SELinux to fix problems earlier. Should I re-enable it?
If SELinux is Disabled, you can switch to Permissive immediately without rebooting. To use Enforcing mode requires a reboot because the system must relabel all files, which can take many hours on large systems. If setting up a new VPS, start with Permissive mode from the beginning.
What if audit2allow creates a policy that allows everything—is that secure?
audit2allow generates the minimum permissions needed based on observed denials. If you properly test your application in Permissive mode for several days, audit2allow will generate sufficient policy. Always review the generated .te file before loading to ensure it's appropriately scoped.
Can I remove or undo a SELinux policy I applied incorrectly?
Yes, use semodule -l to list loaded modules, then semodule -r myapp to remove a module. If you need to reset file contexts, use restorecon -R to restore them to policy defaults. Changes take effect immediately without a reboot.
Start Your AsiaGB VPS Today
AsiaGB VPS runs on SSD storage across every plan, with Thailand or Singapore datacenter options and full root access from day one — starting at 500 THB/month (Linux), backed by a Thai support team.
See VPS Plans