How to Install SELinux to Harden Nginx Webserver

For Linux users that have exposed themselves to RHEL-based distributions like RHEL, Fedora, AlmaLinux, and Rocky Linux, SELinux is not a new concept to them as it mostly comes pre-installed on their systems.

Why SELinux is Important?

SELinux or Security Enhanced Linux is a Linux security system attributed to role access. If you have worked with RHEL-based distributions, SELinux has probably tried to block most of your user-initiated actions (especially web-based configurations) until you almost (or successfully) opted to disable it.

However, disabling SELinux is strongly discouraged as it translates to weakening your server security footprints. The alternative approach to disabling SELinux is ensuring its configurations are correctly implemented. By understanding SELinux configurations, we can enable it to play nicely with other Linux-installed packages.

[ You might also like: How to Password Protect Directory in Nginx Web Server ]

This article will walk us through basic configurations that we can implement in SELinux for it to not only play nice with the Nginx web server but also harden it.

Installing Nginx Web Server in Linux

This article requires Nginx installed on your Linux operating system distribution. Refer to the following installation guide for different Linux package managers:

$ sudo apt install nginx      [On Debian, Ubuntu and Mint]
$ sudo yum install nginx      [On RHEL/CentOS/Fedora and Rocky Linux/AlmaLinux]
$ sudo apk add nginx          [On Alpine Linux]
$ sudo emerge -a nginx        [On Gentoo Linux]
$ sudo pacman -S nginx        [On Arch Linux]
$ sudo zypper install nginx   [On OpenSUSE]    

After nginx installation, you can enable, start and verify the status using the following commands.

$ sudo systemctl enable nginx
$ sudo systemctl start nginx
$ sudo systemctl nginx status

Installing SELinux in Linux

On Linux distributions like Debian, Ubuntu, Arch Linux, and Manjaro, you might need to remove/uninstall AppArmor before proceeding with the installation of SELinux as they are both Linux Security Module interface implementations of the Linux Kernel, and therefore cannot co-exist simultaneously.

$ sudo systemctl status AppArmor
$ sudo systemctl stop AppArmor
Check AppArmor Status
Check AppArmor Status

After removing it via your Linux distribution package manager, reboot it before proceeding to install SELinux:

$ sudo apt remove --assume-yes --purge apparmor
$ sudo reboot

For RHEL-based distribution systems:

$ sudo dnf makecache
$ sudo dnf install policycoreutils libselinux-utils libselinux libselinux-devel selinux-policy selinux-policy-devel

For Debian-based distribution systems:

$ sudo apt update 
$ sudo apt install policycoreutils selinux-utils selinux-basics libselinux1 libselinux1-dev

For openSUSE Leap and Tumbleweed Systems:

$ sudo zypper refresh
$ sudo zypper install policycoreutils selinux-tools libselinux-devel libselinux1

Activate SELinux:

$ sudo selinux-activate
Active SELinux
Active SELinux

Set SELinux to permissive mode to avoid errors like “failed to load kernel module” during system boot on Debian and Ubuntu systems.

$ sudo nano /etc/selinux/config  

This mode will only print warnings.

Set SELinux Permissive Mode
Set SELinux Permissive Mode

Reboot machine:

$ sudo reboot

System relabeling should take place during bootup.

SELinux Relabeling
SELinux Relabeling

After a successful system reboot, check SELinux Status:

$ sestatus
Check SELinux Status
Check SELinux Status

Hardening Nginx with SELinux

By default, SELinux labels Nginx (plus files and ports) with the httpd_t domain type. We can tell SELinux to let Nginx run in permissive mode (without restrictions). However, all SELinux-related errors will be logged by Linux.

$ semanage permissive -a httpd_t
Run Nginx in SELinux Permissive Mode
Run Nginx in SELinux Permissive Mode

On Debian and Ubuntu, don’t be triggered by “user sddm not in password file” as its a cosmetic (minor) warning.

The above-enforced SELinux policy not only applies to Nginx but also php-fpm.

Checking SELinux Violations

We will run the command:

$ sudo grep nginx /var/log/audit/audit.log | audit2allow -m nginx

The absence of policy violations will lead to the following output:

Checking SELinux Violations
Checking SELinux Violations

Otherwise, an SELinux policy will be built. The generated policy cannot be directly inherited as it only helps in identifying Nginx configuration errors.

SELinux and PHP-FPM

Use the following command to retrieve PHP-FPM-related errors:

$ sudo grep -R php-fpm /var/log/audit/audit.log 

The final step to hardening our Nginx web server is enabling it to run in SELinux enforcing mode:’

$ sudo semanage permissive -d httpd_t
Run Nginx in SELinux Enforcing Mode
Run Nginx in SELinux Enforcing Mode

For extensive documentation on SELinux, refer to its manual page:

$ man selinux

SELinux ensures that Nginx operates on ideal security standards and policies.

Got something to say? Join the discussion.

Have a question or suggestion? Please leave a comment to start the discussion. Please keep in mind that all comments are moderated and your email address will NOT be published.