Editor – The blog post titled “NGINX: SELinux Changes when Upgrading to RHEL 6.6 / CentOS 6.6” redirects here. This article provides updated and generalized information.
The default settings for Security-Enhanced Linux (SELinux) on modern Red Hat Enterprise Linux (RHEL) and related distros can be very strict, erring on the side of security rather than convenience. Although the default settings do not limit the functioning of NGINX Open Source and NGINX Plus in their default configurations, other features you might configure can be blocked unless you explicitly allow them in SELinux. This article describes the possible issues and recommended ways to resolve them.
[Editor – This article applies to both NGINX Open Source and NGINX Plus. For ease of reading, the term “NGINX” is used throughout.
CentOS is a related distro originally derived from RHEL and is supported by NGINX and NGINX Plus. In addition, NGINX Plus supports the related Amazon Linux and Oracle Linux distros. Their default SELinux settings might differ from CentOS and RHEL; consult the vendor documentation.]
Overview of SELinux
SELinux is enabled by default on modern RHEL and CentOS servers. Each operating system object (process, file descriptor, file, etc.) is labeled with an SELinux context that defines the permissions and operations the object can perform. In RHEL 6.6/CentOS 6.6 and later, NGINX is labeled with the httpd_t context:
The httpd_t context permits NGINX to listen on common web server ports, to access configuration files in /etc/nginx, and to access content in the standard docroot location (/usr/share/nginx). It does not permit many other operations, such as proxying to upstream locations or communicating with other processes through sockets.
Temporarily Disabling SELinux for NGINX
To temporarily disable SELinux restrictions for the httpd_t context, so that NGINX can perform all the same operations as in non‑SELinux OSs, assign the httpd_t context to the permissive domain. See the next section for details.
Changing SELinux Modes
SELinux can be run in enforcing, permissive, or disabled modes (also referred to as domains). Before you make an NGINX configuration change that might breach the default (strict) permissions, you can change SELinux from enforcing to permissive mode, in your test environment (if available) or production environment. In permissive mode, SELinux permits all operations, but logs operations that would have breached the security policy in enforcing mode.
To add httpd_t to the list of permissive domains, run this command:
To delete httpd_t from the list of permissive domains, run:
To set the mode globally to permissive, run:
To set the mode globally to enforcing, run:
Resolving SELinux Security Exceptions
In permissive mode, security exceptions are logged to the default Linux audit log, /var/log/audit/audit.log. If you encounter a problem that occurs only when NGINX is running in enforcing mode, review the exceptions that are logged in permissive mode and update the security policy to permit them.
Issue 1: Proxy Connection is Forbidden
By default, the SELinux configuration does not allow NGINX to connect to remote HTTP, FastCGI, or other servers, as indicated by an audit log message like the following:
The audit2why command interprets the message code (1415714880.156:29):
The output from audit2why indicates that you can allow NGINX to make proxy connections by enabling one or both of the httpd_can_network_relay and httpd_can_network_connect Boolean options. You can enable them either temporarily or permanently, the latter by adding the ‑P flag as shown in the output.
Understanding Boolean Options
The sesearch command provides more information about the Boolean options, and is available if you install the setools package (yum install setools). Here we show the output for the httpd_can_network_relay and httpd_can_network_connect options.
The httpd_can_network_relay Boolean Option
Here’s the output from the sesearch command about the httpd_can_network_relay option:
This output indicates that httpd_can_network_relay allows processes labeled with the httpd_t context (such as NGINX) to connect to ports of various types, including type http_port_t:
To add more ports (here, 8082) to the set of ports permitted for http_port_t, run:
If the output from this command says that a port is already defined, as in the following example, it means the port is included in another set. Do not reassign it to http_port_t, because other services might be negatively affected.
The httpd_can_network_connect Boolean Option
Here’s the output from the sesearch command about the httpd_can_network_connect option:
This output indicates that httpd_can_network_connect allows processes labeled with the httpd_t context (such as NGINX) to connect to all TCP socket types that have the port_type attribute. To list them, run:
Issue 2: File Access is Forbidden
By default, the SELinux configuration does not allow NGINX to access files outside of well‑known authorized locations, as indicated by an audit log message like the following:
The audit2why command interprets the message code (1415715270.766:31):
When file access is forbidden, you have two options.
Option 1: Modify the File Label
Modify the file label so that NGINX (as a process labeled with the httpd_t context) can access the file:
By default, this modification is deleted when the file system is relabeled. To make the change permanent, run:
To modify file labels for groups of files, run:
Option 2: Extend the httpd_t Domain Permissions
Extend the policy for httpd_t to allow access to additional file locations:
To generate a compiled policy, include the -M option:
To load the policy, run semodule -i, then verify success with semodule -l:
This change persists across reboots.
Issue 3: NGINX Cannot Bind to Additional Ports
By default, the SELinux configuration does not allow NGINX to listen (bind()) to TCP or UDP ports other than the default ones that are allowlisted in the http_port_t type:
If you try to configure NGINX to listen on a non‑allowlisted port (with the listen directive in the http, stream, or mail context in the NGINX configuration), you get an error when you verify (nginx -t) or reload the NGINX configuration, as indicated by this NGINX log entry:
You can use semanage to add the desired port (here, 8001) to the http_port_t type:
Reload NGINX with the new configuration.
Issue 4: Too many files are open Error
When the limit on the number of open files (RLIMIT_NOFILE) is exceeded, the following message appears in the error log:
When the NGINX Worker Process Generates the Error
In most cases, the NGINX worker process reports this error, but you cannot use the NGINX worker_rlimit_nofile directive to increase the limit because SELinux doesn’t allow the setrlimit() system call, as reported in the following messages in error and audit logs.
- In /var/log/nginx/error.log for CentOS/RHEL 7.4+:
- In /var/log/nginx/error.log for CentOS/RHEL 8.0+:
- In /var/log/audit/audit.log for CentOS/RHEL 7.4+ and /var/log/messages for CentOS/RHEL 8.0+:
To increase the limit, instead run this command as the root user:
When the NGINX Master Process Generates the Error
If the NGINX master process reports the error, you need to update the systemd unit file for NGINX. This sets the file descriptor limit for both master and worker processes.
- Create a directory for the
nginx.serviceconfiguration: - Add the following lines to /etc/systemd/system/nginx.service.d/nofile_limit.conf:
- Reload the systemd daemon configuration and restart NGINX:
Additional Resources
SELinux is a complex and powerful facility for managing operating system permissions. Additional information is available in the following documents.
- Security‑Enhanced Linux, RHEL 6 or RHEL 7
- SELinux (CentOS HowTo)
- Security‑Enhanced Linux User Guide (Fedora project)
- SELinux project home page
- Security‑Enhanced Linux (United States National Security Agency)
About the Author

Related Blog Posts
Secure Your API Gateway with NGINX App Protect WAF
As monoliths move to microservices, applications are developed faster than ever. Speed is necessary to stay competitive and APIs sit at the front of these rapid modernization efforts. But the popularity of APIs for application modernization has significant implications for app security.
How Do I Choose? API Gateway vs. Ingress Controller vs. Service Mesh
When you need an API gateway in Kubernetes, how do you choose among API gateway vs. Ingress controller vs. service mesh? We guide you through the decision, with sample scenarios for north-south and east-west API traffic, plus use cases where an API gateway is the right tool.
Deploying NGINX as an API Gateway, Part 2: Protecting Backend Services
In the second post in our API gateway series, Liam shows you how to batten down the hatches on your API services. You can use rate limiting, access restrictions, request size limits, and request body validation to frustrate illegitimate or overly burdensome requests.
New Joomla Exploit CVE-2015-8562
Read about the new zero day exploit in Joomla and see the NGINX configuration for how to apply a fix in NGINX or NGINX Plus.
Why Do I See “Welcome to nginx!” on My Favorite Website?
The ‘Welcome to NGINX!’ page is presented when NGINX web server software is installed on a computer but has not finished configuring
