AVC denial in audit.log

SELinux Denying Web App Access: Fix 'Permission Denied' on /var/www/html

Apache can't read files in /var/www/html even with 755 permissions. The fix is adding a file context label, not disabling SELinux.

You set up Apache on CentOS 7 or RHEL 8. You copied your website files to /var/www/html with chmod 755. But when you browse to the site, you get a 403 Forbidden or a Permission Denied error in the Apache error log. The trigger is usually after you rsync or cp files from another directory, like cp -r /home/user/my-site/* /var/www/html/. The files have the right permissions, but SELinux is blocking Apache from reading them.

Root Cause

SELinux labels every file and process with a context. Apache runs under the httpd_t domain. It can only read files labeled httpd_sys_content_t or httpd_sys_rw_content_t. When you copy files from a user home directory, they keep the user_home_t label. Apache can't touch those. You can check the current label with ls -Z /var/www/html/index.html. You'll see something like system_u:object_r:user_home_t instead of httpd_sys_content_t.

The Fix

Do not run setenforce 0. That disables SELinux and breaks the security model. The real fix is to restore or change the file context.

Step 1: Check the current SELinux context

ls -Z /var/www/html/index.html

You should see a context like unconfined_u:object_r:user_home_t. This confirms the label is wrong.

Step 2: Restore the default context for the whole directory

sudo restorecon -Rv /var/www/html

The -R flag goes into subdirectories. The -v shows what it changes. After this, run ls -Z /var/www/html/index.html again. You should see system_u:object_r:httpd_sys_content_t. This usually fixes the problem.

Step 3: If you need a custom path (like /opt/myweb)

sudo semanage fcontext -a -t httpd_sys_content_t '/opt/myweb(/.*)?'
sudo restorecon -Rv /opt/myweb

The first command tells SELinux to label anything under /opt/myweb as httpd_sys_content_t. The restorecon applies the change immediately. You only do this once per path.

Step 4: If Apache needs to write files (uploads, logs)

Use a different context: httpd_sys_rw_content_t for read-write. But be careful — this lets Apache modify files. Only do this for specific directories, like an upload folder.

sudo semanage fcontext -a -t httpd_sys_rw_content_t '/var/www/html/uploads(/.*)?'
sudo restorecon -Rv /var/www/html/uploads

Step 5: Check SELinux booleans

Sometimes Apache needs extra permissions to access home directories or use CGI scripts. Use getsebool -a | grep httpd to see all Apache-related booleans. Common ones:

  • httpd_read_user_content — lets Apache read files in user home dirs. Set it with sudo setsebool -P httpd_read_user_content on.
  • httpd_enable_homedirs — enables UserDir support.
  • httpd_can_network_connect — allows Apache to make outbound connections (like to a database).

The -P flag makes the change permanent across reboots.

What to Check If It Still Fails

First, look at the SELinux audit log. Run sudo ausearch -m avc -ts recent. This shows the exact denial. The output tells you the process name (httpd_t), the target file, and the missing permission. You might see something like denied { read } for pid=1234 comm="httpd" name="index.html". That confirms you fixed the wrong file or missed a subdirectory.

Second, check if the file is a symlink. SELinux can follow symlinks, but the target file must also have the right context. Run ls -Z -l /var/www/html/index.html. If it points to /home/user/site/index.html, label that file too with restorecon.

Third, if you're running a web app like WordPress or Drupal, it might need write access to /var/www/html/wp-content. Set that directory to httpd_sys_rw_content_t as shown in Step 4. Also check SELinux booleans for database connections or sending emails.

Last resort — check the Apache error log: tail -f /var/log/httpd/error_log. It often says Permission denied: /var/www/html/index.html. If SELinux is still blocking, you'll also see an AVC denial in /var/log/audit/audit.log. If you don't see any AVC messages, the problem is not SELinux — check file permissions or Apache config.

Related Errors in Linux & Unix
bond0: link status down Network Bonding Fails After Reboot on Ubuntu 22.04 Fix Kernel Panic: VFS Unable to Mount Root Filesystem Invalid class name error in JavaScript on Linux: quick fix Invalid module format or Exec format error Fixing kernel module version mismatch in Linux

Was this solution helpful?

EP
Erropedia Team
Tech Support Editors
The Erropedia editorial team researches and documents real-world tech errors from across Windows, Linux, macOS, networking, databases, cloud platforms, and more. Every solution is reviewed for accuracy and updated as software and systems evolve.