Many times you install nginx on your Linux server like Red Hat or Rocky Linux and then you start it but it say error and no working. You look at status and it is red color, so you feel very sad and want to cry because you do not know why. This is usually because SELinux is active and it block your nginx from doing things like using port or reading files. SELinux has a system called AVC that write logs when it block something, but these logs are very hard to read because they look like alien language with many strange words. I also got very confused when I first look at this log, but then I learn how to read it from my brother and now I want to show you how you can read it easily so you can fix your server without getting headache.
Below is one example of the AVC denial log that we always see when nginx try to use a port that SELinux does not like:
type=AVC msg=audit(05/23/2026 17:06:14.179:446) : avc: denied { name_bind } for pid=8458 comm=nginx src=8888 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:unreserved_port_t:s0 tclass=tcp_socket permissive=0
This text look very long and scary, but do not worry because we can break it down into small pieces and read it one by one. I will make a tutorial step by step to explain what every single word in this log mean so you can become smart and fix it.
Step 1: Find where is the log and open it
First you need to find this log inside your server. Usually SELinux write all these blocks inside a file called audit dot log. You must opening your terminal and login as root user because normal user cannot see this file. You can run this command to see the logs:
cat /var/log/audit/audit.log | grep nginx
Or if you do not have audit log file, you can also use another tool that is called journalctl by running this command:
journalctl -t setroubleshoot
When you run this, you will see many lines of logs and one of them will look exactly like the example log I showed you above. Now we must read it.
Step 2: Understand the type and the time of log
At the very start of the log, you see “type=AVC”. This is telling you that this log is coming from the Access Vector Cache, which is the security brain of SELinux that makes quick decisions to allow or block things. If you do not see “type=AVC”, then it is not a SELinux block log, maybe it is just normal system log.
Next to it, you see “msg=audit(05/23/2026 17:06:14.179:446)”. This is the time when the block happened. The numbers inside the bracket are very important because it show the date, the hour, the minute, the second, and milliseconds. The last number “446” is like a unique ID for this specific event so you can find it easily if there are many logs at the same second.
Step 3: See what action was blocked by SELinux
After the time, you see “avc: denied { name_bind }”. The word “denied” is very clear, it means SELinux said “No!” and stopped the action. If it says “allowed”, then it did not block it, but here it is “denied”.
The words inside the curly brackets “{ name_bind }” is called the access vector. This is the exact action that the program tried to do. In this example, “name_bind” means the program wanted to bind itself to a network port, which means it wanted to listen to a port so people can connect to it.
Step 4: Find who is the culprit process
Now we look at “for pid=8458 comm=nginx”. This part tells you what program tried to do the bad thing.
- “pid=8458” is the Process ID number of the program that was running at that time.
- “comm=nginx” is the command name. This is super helpful because it tells you directly that nginx is the one trying to do the action. If it says “comm=apache” or “comm=mysql”, then you know those programs are the ones having trouble.
Step 5: Find what target the process wanted to touch
In this log, we see “src=8888”. This tells us the source port number. Nginx is trying to use port 8888 on the server. Because port 8888 is not a standard port for web servers, SELinux gets very suspicious and blocks it.
Step 6: Read the Security Context of the source
Next, we have “scontext=system_u:system_r:httpd_t:s0”. This is the source context, which is the security label of the process that tried to run. SELinux does not look at usernames like “root”, instead it looks at these labels. Let us break this label down:
- “system_u” is the SELinux user.
- “system_r” is the role.
- “httpd_t” is the domain or type. This is the most important part! It tells us that nginx is running inside the “httpd_t” domain, which is the security box for web servers.
- “s0” is the sensitivity level, which is used for multi-level security.
Step 7: Read the Security Context of the target
Then we see “tcontext=system_u:object_r:unreserved_port_t:s0”. This is the target context, which is the security label of the thing that the process tried to touch. In this case, the target is the port 8888.
- “system_u” is the user.
- “object_r” is the role for objects like ports or files.
- “unreserved_port_t” is the type of the port. Because port 8888 is not registered for any specific service in SELinux, it gets the label “unreserved_port_t”, which means it is a generic port that is not specifically allowed for web servers.
Step 8: Check the class of the target and permissive mode
At the end of the log, we see “tclass=tcp_socket permissive=0”.
- “tclass=tcp_socket” is the target class. It tells us what kind of object the target is. Here it is a TCP socket, which makes sense because nginx is trying to use a network port. If it was a file, it would say “tclass=file”.
- “permissive=0” is very important. It tells us if SELinux is actively blocking or just watching. The number “0” means enforcing mode is active, so SELinux actually blocked the action and nginx failed to start. If it was “permissive=1”, it means SELinux is in permissive mode, so it only wrote this log but did not actually block nginx, and nginx would run fine.
How to fix this issue step by step
Now that we understand the log, we know that nginx (running as httpd_t) tried to bind to port 8888 (which has label unreserved_port_t) but was blocked because httpd_t is not allowed to bind to unreserved_port_t. Here is how you can fix it.
Step 1: See what ports are allowed for web servers. You can run this command:
semanage port -l | grep http_port_t
This will show you a list of ports like 80, 443, 8080, etc. You will see that port 8888 is not in that list.
Step 2: Add port 8888 to the allowed list for web servers by running this command:
semanage port -a -t http_port_t -p tcp 8888
This command tells SELinux to add port 8888 to the “http_port_t” label so that nginx is allowed to use it.
Step 3: Try to start your nginx again:
systemctl restart nginx
Now nginx should start without any red error because SELinux is happy now and will not block it anymore.
Conclusion
Reading SELinux logs is not very hard once you know what each word means. You just need to look at who is trying to do the action (scontext), what action they want to do (the brackets like name_bind), and what target they want to touch (tcontext). If you map these things in your head, you can easily find the right command to fix the permission problem. I hope this simple guide helps you understand your Linux server better and saves you from crying next time your nginx does not want to start.
