When your Apache server throws an IOError 13 while trying to write to a log file it technically owns, you're likely facing SELinux context mismatch. The classic symptom:
IOError: [Errno 13] Permission denied: '/var/www/webapp/k/site/k.log'
The file's current security context shows:
$ ll -Z k.log
-rw-r--r--. apache apache system_u:object_r:httpd_sys_content_t:s0 k.log
While the audit.log
reveals the actual conflict:
type=AVC msg=audit(1409945481.163:1561): avc: denied { append } for pid=16862 comm="httpd" name="k.log" dev="dm-1" ino=201614333 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:httpd_sys_content_t:s0 tclass=file
Instead of disabling SELinux (setenforce 0
), set the correct context:
# For existing files:
sudo chcon -R -t httpd_sys_rw_content_t /var/www/webapp/k/site/
# For persistent changes:
sudo semanage fcontext -a -t httpd_sys_rw_content_t "/var/www/webapp/k/site(/.*)?"
sudo restorecon -Rv /var/www/webapp/k/site/
For development environments, you might consider:
# Create a custom policy module from audit log:
sudo grep httpd /var/log/audit/audit.log | audit2allow -M mypolicy
sudo semodule -i mypolicy.pp
# OR set permissive mode for specific domain:
sudo semanage permissive -a httpd_t
After applying changes, verify the new context:
$ ls -lZ /var/www/webapp/k/site/k.log
-rw-r--r--. apache apache system_u:object_r:httpd_sys_rw_content_t:s0 k.log
When your Apache server throws an IOError: [Errno 13] Permission denied
error despite correct file ownership, SELinux context is usually the culprit. The audit log clearly shows:
avc: denied { append } for pid=16862 comm="httpd"
scontext=system_u:system_r:httpd_t:s0
tcontext=system_u:object_r:httpd_sys_content_t:s0
This indicates Apache's httpd_t process is being blocked from writing to a file labeled httpd_sys_content_t.
The key mismatch here is between:
- Process context:
httpd_t
(Apache's default SELinux domain) - File context:
httpd_sys_content_t
(typically for read-only web content)
A quick verification shows our file's context:
$ ls -Z /var/www/webapp/k/site/k.log
-rw-r--r--. apache apache system_u:object_r:httpd_sys_content_t:s0 k.log
1. Correct Context Assignment
For log files that Apache needs to write to, use httpd_log_t
:
sudo semanage fcontext -a -t httpd_log_t "/var/www/webapp/k/site(/.*)?"
sudo restorecon -Rv /var/www/webapp/k/site
2. Alternative: Custom Policy Module
If you specifically need httpd_sys_content_t, generate a policy module:
sudo grep httpd /var/log/audit/audit.log | audit2allow -M httpd_append
sudo semodule -i httpd_append.pp
3. Temporary Debugging Approach
To test if SELinux is really the issue:
sudo ausearch -c 'httpd' --raw | audit2allow
After applying changes, verify with:
sudo sealert -l "*"
The proper context should now appear:
$ ls -Z /var/www/webapp/k/site/k.log
-rw-r--r--. apache apache system_u:object_r:httpd_log_t:s0 k.log