When integrating Nginx with Gunicorn via Unix sockets (/run/gunicorn/socket
), SELinux typically blocks access attempts with two distinct denials:
# First denial: Socket file write permission
type=AVC msg=audit(1454360194.623:7324): avc: denied { write } for pid=9128 comm="nginx"
# Second denial: Stream socket connection
type=AVC msg=audit(1454361591.701:13343): avc: denied { connectto } for pid=9128 comm="nginx"
First verify current context labeling:
ls -Z /run/gunicorn/socket
# Output shows incorrect httpd_sys_content_t context
system_u:object_r:httpd_sys_content_t:s0 /run/gunicorn/socket
Apply the correct context permanently:
semanage fcontext -a -t httpd_var_run_t "/run/gunicorn/socket(/.*)?"
restorecon -Rv /run/gunicorn/socket
For immediate testing, enable the HTTPD connection boolean:
setsebool -P httpd_connect_unixsocket 1
Create a persistent policy without relying on denials:
# Create .te policy file
cat << EOF > nginx_gunicorn.te
module nginx_gunicorn 1.0;
require {
type httpd_t;
type initrc_t;
class unix_stream_socket connectto;
class sock_file write;
}
# Allow socket connection
allow httpd_t initrc_t:unix_stream_socket connectto;
# Allow socket file write
allow httpd_t httpd_var_run_t:sock_file write;
EOF
# Compile and install
checkmodule -M -m -o nginx_gunicorn.mod nginx_gunicorn.te
semodule_package -o nginx_gunicorn.pp -m nginx_gunicorn.mod
semodule -i nginx_gunicorn.pp
Confirm the changes took effect:
# Check socket context
ls -Z /run/gunicorn/socket
# Should show: system_u:object_r:httpd_var_run_t:s0
# Verify boolean
getsebool httpd_connect_unixsocket
# Should return "on"
# Check custom module
semodule -l | grep nginx_gunicorn
If using systemd socket activation, add SELinux context directives:
[Unit]
Description=Gunicorn Socket
[Socket]
ListenStream=/run/gunicorn/socket
SocketUser=nginx
SocketGroup=nginx
SocketMode=0660
# SELinux context
SELinuxContext=system_u:object_r:httpd_var_run_t:s0
[Install]
WantedBy=sockets.target
When setting up Nginx to communicate with Gunicorn via Unix sockets (/run/gunicorn/socket
), SELinux typically blocks the connection attempts. The audit logs reveal two critical denials:
avc: denied { write } for comm="nginx" name="socket" dev="tmpfs" ino=76151
avc: denied { connectto } for comm="nginx" path="/run/gunicorn/socket"
Instead of relying on audit2allow
, we can manually configure the security contexts:
# First, verify current context of the socket
ls -Z /run/gunicorn/socket
# Set proper context for the socket directory
sudo semanage fcontext -a -t httpd_var_run_t "/run/gunicorn(/.*)?"
sudo restorecon -Rv /run/gunicorn
# Alternatively for temporary testing (not recommended for production)
sudo chcon -t httpd_var_run_t /run/gunicorn/socket
For production systems, create a custom policy module:
# Create a .te file with the necessary rules
cat > nginx_gunicorn.te <
After applying these changes, test the connection:
# Check if Nginx can now access the socket
sudo -u nginx curl --unix-socket /run/gunicorn/socket http://localhost
# Verify SELinux is no longer blocking
sudo ausearch -m avc -c nginx | grep denied
Some systems may benefit from using SELinux booleans:
# Check relevant booleans
getsebool -a | grep httpd
# Enable httpd_can_network_connect if needed
sudo setsebool -P httpd_can_network_connect on
For automated deployments, include these commands in your provisioning scripts:
#!/bin/bash
# Ensure directory exists
mkdir -p /run/gunicorn
chown nginx:nginx /run/gunicorn
# Set SELinux context
semanage fcontext -a -t httpd_var_run_t "/run/gunicorn(/.*)?"
restorecon -Rv /run/gunicorn
# Load custom policy if created earlier
semodule -i /path/to/nginx_gunicorn.pp