Every file, process, port, and user on an SELinux system carries a security context — a label that SELinux uses to make access control decisions. When a process tries to access a file, SELinux compares their contexts against the loaded policy. If the policy does not explicitly allow the access, it is denied — regardless of Unix permissions.
Understanding contexts is the key to understanding SELinux. Most SELinux problems come down to a mismatch between a process's context and a file's context. Fixing the context fixes the problem.
A context is four fields separated by colons:
Maps to a set of allowed roles. Not the same as a Linux user.
Groups types a user or process is allowed to enter.
The primary enforcement label. Policy rules are written in terms of types.
Sensitivity level. Always s0 in targeted policy.
httpd_t that means "the Apache web server process."
When you see httpd_sys_content_t that means "content Apache
is allowed to serve." The policy says: httpd_t may read httpd_sys_content_t.
The -Z flag added to ls shows SELinux context:
# Show context for files in current directory ls -Z # Show context for a specific file ls -Z /var/www/html/index.html # Long listing with context ls -lZ /var/www/html/ # Show context for a directory ls -dZ /var/www/html/ # Combine with other options ls -laZ /etc/httpd/conf/ls -lZ /var/www/html/ output:
upload.php has context
admin_home_t — it was likely copied from a home directory.
Apache (httpd_t) cannot read admin_home_t files.
It needs to be httpd_sys_content_t. Fix with
restorecon or chcon.
The -Z flag also works with ps to show process contexts:
# Show context for all processes ps -eZ # Show context for a specific process ps -eZ | grep httpd ps -eZ | grep sshd # Full listing with context ps -eZf | grep nginx # Show your current shell context ps -Z $$ps -eZ | grep httpd output:
id -Z:
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023Logged-in users typically run as
unconfined_t — they are
not confined by SELinux policy in the targeted model.
restorecon resets file contexts back to what the policy says
they should be. This is the correct fix for most context problems:
# Restore context on a single file sudo restorecon /var/www/html/upload.php # Restore recursively on a directory sudo restorecon -R /var/www/html/ # Verbose — show what changed sudo restorecon -Rv /var/www/html/ # Dry run — show what WOULD change without changing it sudo restorecon -Rvn /var/www/html/ # Restore after moving files from home directory to web root sudo cp ~/myapp/* /var/www/html/myapp/ sudo restorecon -Rv /var/www/html/myapp/restorecon -Rv output:
chcon — use
restorecon. It sets the context to what the policy defines
as correct for that path, and the fix survives a relabel. chcon
changes are temporary and will be wiped by a relabel.
chcon changes a file's context directly. Use it for testing
and troubleshooting — not as a permanent fix:
# Change the type of a file sudo chcon -t httpd_sys_content_t /var/www/html/upload.php # Change type recursively sudo chcon -R -t httpd_sys_content_t /var/www/html/myapp/ # Copy context from a reference file sudo chcon --reference=/var/www/html/index.html /var/www/html/upload.php # Change user field sudo chcon -u system_u /var/www/html/upload.php # Change full context at once sudo chcon -u system_u -r object_r -t httpd_sys_content_t /var/www/html/upload.php
touch /.autorelabel + reboot, or restorecon -R /)
will reset any chcon changes back to the policy defaults.
Use chcon to test — use semanage fcontext +
restorecon to make it permanent.
When your files live in a non-standard path, add a persistent context rule
with semanage fcontext then apply it with restorecon:
# Add a context rule for a custom web root sudo semanage fcontext -a -t httpd_sys_content_t "/srv/myapp(/.*)?" # Apply the rule sudo restorecon -Rv /srv/myapp/ # Add rule for writable web content (uploads) sudo semanage fcontext -a -t httpd_sys_rw_content_t "/srv/myapp/uploads(/.*)?" sudo restorecon -Rv /srv/myapp/uploads/ # List all custom fcontext rules sudo semanage fcontext -l | grep myapp # Delete a custom rule sudo semanage fcontext -d "/srv/myapp(/.*)?" # List ALL fcontext rules (very long) sudo semanage fcontext -l | lesssemanage fcontext -l | grep myapp:
semanage fcontext -a -t TYPE "/path(/.*)?" — add the rulerestorecon -Rv /path/ — apply the rule to existing files/path/ will inherit the correct context automaticallyKnowing the most common type labels saves enormous troubleshooting time:
# Query what type a path should have
sudo semanage fcontext -l | grep "^/var/www"
sudo semanage fcontext -l | grep "^/etc/httpd"
sudo semanage fcontext -l | grep "^/var/log/httpd"
| Type Label | Meaning | Typical Path |
|---|---|---|
| httpd_sys_content_t | Web content Apache can read and serve | /var/www/html/ |
| httpd_sys_rw_content_t | Web content Apache can read AND write | Upload directories |
| httpd_config_t | Apache configuration files | /etc/httpd/conf/ |
| httpd_log_t | Apache log files | /var/log/httpd/ |
| sshd_key_t | SSH host key files | /etc/ssh/ssh_host_* |
| ssh_home_t | User SSH keys and config | ~/.ssh/ |
| var_log_t | Generic log files | /var/log/ |
| etc_t | Generic config files in /etc | /etc/ |
| admin_home_t | Files in root or admin home dirs | /root/, ~/ |
| user_home_t | Regular user home directory files | /home/user/ |
| tmp_t | Temporary files | /tmp/ |
| bin_t | System binaries | /usr/bin/, /bin/ |
| mysqld_db_t | MySQL/MariaDB data files | /var/lib/mysql/ |
| postgresql_db_t | PostgreSQL data files | /var/lib/pgsql/ |
Processes can only bind to ports that match their type. If you run a service on a non-standard port, you must add it to the SELinux port context:
# List all port contexts sudo semanage port -l # Find what type is assigned to port 80 and 443 sudo semanage port -l | grep http # Add a non-standard port for Apache (e.g., 8080) sudo semanage port -a -t http_port_t -p tcp 8080 # Add a non-standard SSH port sudo semanage port -a -t ssh_port_t -p tcp 2222 # Modify an existing port entry sudo semanage port -m -t http_port_t -p tcp 8443 # Delete a custom port rule sudo semanage port -d -t http_port_t -p tcp 8080 # List only http-related ports sudo semanage port -l | grep http_port_tsemanage port -l | grep http_port_t:
http_port_t does not include 8080 by default.
Fix: sudo semanage port -a -t http_port_t -p tcp 8080
A complete context workflow for deploying a new application:
#!/bin/bash # Deploy myapp to /srv/myapp — set correct SELinux contexts APP_DIR="/srv/myapp" APP_UPLOAD="$APP_DIR/uploads" APP_PORT=8080 # 1. Create directories sudo mkdir -p "$APP_DIR" "$APP_UPLOAD" # 2. Deploy application files sudo cp -r /home/deploy/myapp/* "$APP_DIR/" # 3. Add persistent SELinux context rules sudo semanage fcontext -a -t httpd_sys_content_t "${APP_DIR}(/.*)?" sudo semanage fcontext -a -t httpd_sys_rw_content_t "${APP_UPLOAD}(/.*)?" # 4. Apply the rules sudo restorecon -Rv "$APP_DIR" # 5. Add the custom port sudo semanage port -a -t http_port_t -p tcp $APP_PORT # 6. Verify contexts look correct ls -lZ "$APP_DIR" ls -lZ "$APP_UPLOAD" sudo semanage port -l | grep $APP_PORT echo "SELinux context setup complete."Verification output:
| Command | What it does |
|---|---|
| ls -Z FILE | Show SELinux context of file(s) |
| ls -lZ DIR/ | Long listing with contexts |
| ls -dZ DIR/ | Show context of directory itself |
| ps -eZ | grep svc | Show process context |
| id -Z | Show current user's SELinux context |
| restorecon FILE | Restore file to policy-defined context |
| restorecon -Rv DIR/ | Restore recursively, verbose |
| restorecon -Rvn DIR/ | Dry run — show what would change |
| chcon -t TYPE FILE | Temporarily change file type (testing only) |
| chcon --reference=REF FILE | Copy context from reference file |
| semanage fcontext -l | List all file context rules |
| semanage fcontext -a -t TYPE "/path(/.*)?" | Add persistent context rule |
| semanage fcontext -d "/path(/.*)?" | Delete a context rule |
| semanage port -l | List all port context rules |
| semanage port -a -t TYPE -p tcp PORT | Add a port to a type |
| Tool | Persistent? | When to use |
|---|---|---|
| chcon | ❌ No — lost on relabel | Quick testing only |
| restorecon | ✅ Yes — applies policy rules | Fix wrong context on existing files |
| semanage fcontext + restorecon | ✅ Yes — adds new policy rule | Non-standard paths not covered by default policy |