Candid photograph of a Linux server terminal with a soft olive-green glow against a dark slate background, conveying a calm technical atmosphere.

Step-by-step guides for system administrators — covering command-line basics, web server setup, and preparation material for technical interviews.

Browse Tutorials

Managing SELinux Contexts for Web Applications

SELinux adds a policy layer that controls what a web server may access, even when ordinary Unix permissions appear correct. On RHEL, CentOS Stream and Fedora, an incorrect security context can make Nginx return a 403 error, fail to read an asset or reject an upload.

The most reliable approach is to treat labels as part of the application configuration. Identify which paths need read-only access, which directories require controlled writes, then assign persistent file contexts rather than applying temporary fixes.

This matters for Australian teams running sites from Sydney or Melbourne data centres, regional offices in Brisbane or Perth, and cloud platforms with workloads spread across local availability zones. A deployment that works in a test VM may still fail after a release, restore or migration if labels were never recorded.

The commands below suit administrators who want repeatable troubleshooting rather than guesswork. Run them with sudo or as root, and test changes in a staging environment before applying them to a production site serving customers across Australian time zones.

SELinux Labels and Web Requests

SELinux assigns a security context to files, directories, processes and ports. For web content, the important field is usually the type, such as httpd_sys_content_t. Nginx runs within a confined domain and policy rules determine whether that domain can read, execute or modify a labelled object.

Check the current label with:

ls -Zd /var/www/html
ls -Z /var/www/html/index.html
ps -eZ | grep nginx

A directory can have suitable Unix ownership and mode bits while still being inaccessible to Nginx. This is why changing chmod 777 is a poor fix: it weakens discretionary permissions without addressing the SELinux policy decision.

Map Paths to Persistent Types

For ordinary static files, label the document root as web-readable content. The -a option adds a file-context rule, while -t selects the SELinux type:

sudo semanage fcontext -a -t httpd_sys_content_t "/srv/www/site(/.*)?"
sudo restorecon -Rv /srv/www/site

The regular expression covers the directory and everything below it. If semanage is missing on a minimal installation, install the package that provides it:

sudo dnf install policycoreutils-python-utils

Use semanage fcontext -l to inspect existing rules. Avoid relying on chcon for permanent configuration; it changes the current label but can be undone by restorecon, package operations or a filesystem relabel.

Apply and Verify Contexts

After applying a rule, confirm both the persistent mapping and the live labels. This small check is useful after a deployment, an archive extraction or a move from /var/www/html to a custom path.

sudo semanage fcontext -l | grep '/srv/www/site'
sudo restorecon -Rv /srv/www/site
ls -lZ /srv/www/site

Keep these checks in deployment notes or a shell script. A practical verification list includes:

Handle Uploads and Runtime Data

Uploaded files, caches and generated reports need more careful treatment. A web process should not receive write access to the entire application tree. Keep code and configuration labelled httpd_sys_content_t, then assign only the required writable directory the httpd_sys_rw_content_t type.

sudo semanage fcontext -a -t httpd_sys_rw_content_t "/srv/www/site/storage(/.*)?"
sudo restorecon -Rv /srv/www/site/storage

The write permission is still subject to Unix ownership and mode bits. SELinux does not replace those controls. For an uploads directory, consider preventing script execution through Nginx configuration and application design, since a writable web path increases the impact of a compromised account.

Read Denials Without Guessing

When SELinux blocks an operation, inspect recent audit records instead of immediately disabling enforcement. The following commands help identify the denied source, target and operation:

sudo ausearch -m AVC -ts recent
sudo journalctl -t setroubleshoot --since "15 minutes ago"

audit2why can explain a denial, but its output is guidance rather than an instruction to enable every suggested rule. A denial may reveal a wrong path, an accidental write attempt or an application that should use a different service design.

If a PHP application needs network access to a database or API, check the relevant boolean before changing policy. For example:

getsebool httpd_can_network_connect_db
sudo setsebool -P httpd_can_network_connect_db on

Enable only the narrowly relevant boolean, and record the reason. This is especially important for Australian organisations working under internal security reviews or Essential Eight-aligned controls.

Keep Nginx and Policy Aligned

SELinux labels cannot correct an Nginx path mismatch. Confirm that the root, alias, proxy settings and service account refer to the same locations you labelled. For a clean RHEL 9 installation and server layout, follow this Nginx configuration guide before troubleshooting application access.

A useful deployment sequence is to create directories, set ownership and modes, add semanage fcontext rules, run restorecon, and then reload Nginx. Validate with a local request before exposing the change through a load balancer or Australian CDN edge.

For routine checks, keep these commands close at hand:

What to Remember

SELinux context management is most predictable when labels describe the intended role of each path. Static content should be read-only, runtime directories should be limited to the specific locations that need writes, and persistent mappings should be restored after every deployment or migration.

For broader command-line and system administration references, the Linux administration guides provide useful supporting material. The key principle is simple: inspect the label, define the correct persistent type, restore it, and verify the application request before changing policy.