LearnRHCSA (EX200)Security

restorecon and semanage fcontext

restorecon - a hands-on Linux lab on a real virtual machine.

Fix the SELinux label that blocks a service even when permissions look fine. restorecon resets a file to the type the policy expects and is a silent no-op when the file is already correct, which is why a plain cp into a directory inherits the right type for free. semanage fcontext -a -t TYPE PATH-REGEX changes what that expected default IS and makes it permanent. The exam pattern is always semanage fcontext -a then restorecon -Rv PATH. mv preserves the old context and is the classic wrong-context case. Serves EX200 security: restore default file contexts.

You built a website the sensible way. You made a fresh directory /web, dropped index.html into it, pointed Apache at it, and opened the browser. Apache answers with 403 Forbidden. The file permissions are correct, rwxr-xr-x, owned by the right user. The firewall is open. The daemon is running. Everything a normal permissions check would tell you looks fine, and the page still will not load.

The block is SELinux, and it is invisible to ls -l. Every file carries a second label beyond owner and mode, the SELinux type, and Apache is only allowed to read files whose type is httpd_sys_content_t. Your brand-new /web tree got labeled default_t instead, so the policy denies the read. This lesson teaches the two commands that fix exactly this: restorecon, which resets a file to the label the policy expects, and semanage fcontext, which changes what that expected label IS. Together they are the single most common SELinux repair on the exam.

The black boxes below are a practice terminal: a safe sandbox that checks the one command each step teaches. The outputs come from a real RHEL 10 machine (AlmaLinux 10.2) running SELinux in Enforcing mode. Some values, like the exact path in a relabel message, depend on your files, so treat those as illustrative. What is stable everywhere is the SHAPE. restorecon resets a file to its policy default and stays silent when nothing needs changing. semanage fcontext -a records a new default rule that survives reboots and full relabels.

restorecon means restore context. Its whole job is to take a file and reset its SELinux type back to whatever the policy says that path is supposed to have. It never invents a label. It reads the rule for that path out of the policy, then stamps the file with the matching type.

Think of it like a coat check. The policy holds a book that says which hook every coat belongs on. restorecon does not decide where your coat goes; it looks up the assigned hook and moves the coat there. If the coat is already on the right hook, it does nothing and says nothing. If the coat is on the wrong hook, it moves it and, with -v, tells you which hook it changed from and to.

You reach for restorecon whenever a file has drifted from its correct SELinux type and a service is being denied access. The most common causes of that drift are moving a file with mv, restoring from a backup, or creating a directory tree in a location the policy did not expect. In every case the fix is the same: point restorecon at the path and let it stamp the correct type back on.

This is the RHCSA objective worded as "restore default file contexts," and it is nearly always paired with a service that will not start until the labels are right. Learn to reach for it the moment a service is denied and the permissions look fine.

This is the trap that catches people, so learn it before you touch the commands. How a file gets its SELinux type depends entirely on how the file arrived.

When you cp a file INTO a directory, the new copy inherits the type of the directory it lands in. Copy something into /var/www/html and it is born with httpd_sys_content_t, the web type, because that is what the directory carries. It is already correct.

When you mv a file, it keeps the type it had at its old location. Move a file from your home directory into /var/www/html and it drags its old user_home_t type along with it. The file now sits in the web directory wearing the wrong label, and Apache is denied. cp is safe, mv is the classic wrong-context case. This is why the honest demonstration below, a cp, needs no repair.

Watch what a plain cp produces. Copy a file into /var/www/html and check its label. Because the copy inherited the directory's type, it is already httpd_sys_content_t, the correct web type. Copy the file in:

cp /root/index.html /var/www/html/moved.html

prompt: [root@servera ~]# answer: cp /root/index.html /var/www/html/moved.html output: hint: The copy command is cp, then the source, then the destination: cp /root/index.html /var/www/html/moved.html

Now read the label the copy was born with:

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

prompt: [root@servera ~]# answer: ls -Z /var/www/html/moved.html output: unconfined_u:object_r:httpd_sys_content_t:s0 /var/www/html/moved.html hint: ls -Z shows the SELinux context; point it at the file you just copied.

The context is unconfined_u:object_r:httpd_sys_content_t:s0. The field that matters is the third one, the TYPE, ending in _t: httpd_sys_content_t. That is the web content type, exactly what Apache is allowed to read. The copy inherited it from the /var/www/html directory automatically. No repair is needed, because cp did the right thing for free.

Now run restorecon on that same file with -v for verbose. Because the file already carries the type the policy expects, restorecon has nothing to change. It stays completely silent. Silence here is the honest, correct result, not a failure. Run the reset:

restorecon -v /var/www/html/moved.html

prompt: [root@servera ~]# answer: restorecon -v /var/www/html/moved.html output: hint: restorecon resets a file to its policy default; -v prints only when it actually changes something.

No output. restorecon -v prints a relabel line ONLY when it changes a file's type. Here the file already matched the policy default, httpd_sys_content_t, so there was nothing to change and nothing to report. This is the honest lesson: a plain cp into /var/www/html inherits the correct type, so restorecon is a no-op. You would see actual output only when the file was wrong, which is exactly what mv or a brand-new directory tree produces.

The username field in the context (unconfined_u above) depends on who created the file and can read system_u or unconfined_u on your machine. It does not affect access. SELinux enforces on the TYPE, the third field ending in _t. When you read a context, jump straight to the type and ignore the rest unless a task asks otherwise.

restorecon can only stamp on the type the policy already expects for a path. So what do you do for a brand-new location like /web, where the policy expects the generic default_t and Apache is denied? You change what the default IS. That is the job of semanage fcontext.

semanage fcontext -a -t <type> '<path-regex>' ADDS a rule to the policy. The rule says "files matching this path pattern should have this type." The -a means add, and -t names the target type. The path is a regular expression: '/web(/.*)?' means the directory /web itself and everything under it. This rule is permanent. It is written into the local policy and survives a reboot and even a full filesystem relabel. Record the new default:

semanage fcontext -a -t httpd_sys_content_t '/web(/.*)?'

prompt: [root@servera ~]# answer: semanage fcontext -a -t httpd_sys_content_t '/web(/.*)?' output: hint: semanage fcontext -a -t TYPE 'PATH-REGEX' adds a permanent default rule; the regex '/web(/.*)?' covers /web and everything under it.

No output means the rule was accepted and written to the local policy. Read it aloud: files whose path matches /web(/.*)? should carry the type httpd_sys_content_t. That regex is the standard "this directory and all of its contents" pattern. But notice what has NOT happened yet: the files already sitting in /web still wear their old labels. semanage fcontext only edited the rulebook. It did not touch a single file on disk. That is the second half of the pattern, and it is why these two commands always travel together.

semanage fcontext alone fixes nothing on disk. It records the new default, but existing files keep their old, wrong labels until you run restorecon to apply the rule. The number-one exam mistake is running semanage fcontext -a and stopping there, then wondering why the service is still denied. Always follow it with restorecon -Rv <path>. The rule and the relabel are two commands, never one.

The rule is in the policy; now push it onto the files. restorecon -Rv /web walks the whole /web tree and stamps every file with the type the policy now expects. The -R means recursive, so it descends into subdirectories, and -v prints a line for every file it actually relabels. This time you WILL see output, because the files start out wrong and restorecon corrects them. Apply the rule:

restorecon -Rv /web

prompt: [root@servera ~]# answer: restorecon -Rv /web output: Relabeled /web from unconfined_u:object_r:default_t:s0 to unconfined_u:object_r:httpd_sys_content_t:s0 hint: restorecon -Rv PATH applies the recorded default to a whole tree; -R recurses, -v prints each relabel.

Now there is output, and it tells the full story of the fix. The Relabeled /web line shows the file changing from the wrong type default_t to the correct httpd_sys_content_t. That transition is the whole point: semanage fcontext set the target, and restorecon moved the file to it. Apache can now read /web and the 403 Forbidden clears. This exact two-step, semanage fcontext -a then restorecon -Rv, is the pattern the exam tests over and over.

The exact path and old type in your Relabeled line depend on the files you created and where they lived. On the practice machine /web started as default_t; a tree moved out of a home directory might start as user_home_t instead. What is stable is the shape of the line: Relabeled <path> from <old context> to <new context>, and the new context always carries the type you set with semanage fcontext.

Scaffolding off. No command is printed this time. You have every piece you need.

You created a directory tree at /web for a website. Apache returns 403 Forbidden even though permissions and the firewall are fine, because the tree is labeled default_t and Apache needs httpd_sys_content_t. You have already recorded the correct default with semanage fcontext -a. One command remains: apply that recorded default to every file in the tree, recursively, and print each file it relabels. Which single command, given the path /web, does that?

prompt: [root@servera ~]# answer: restorecon -Rv /web output: Relabeled /web from unconfined_u:object_r:default_t:s0 to unconfined_u:object_r:httpd_sys_content_t:s0 hint: It is the relabel step, not semanage. The tool is restorecon, -R to recurse, -v to print, then the path /web.

restorecon -Rv /web is the answer. -R walks the whole tree, -v prints the Relabeled line for each file it corrects, and the path names what to fix. semanage fcontext had already set the target type; this command is what actually moves the files to it. That is the closing move of every "restore default file contexts" task: record the rule with semanage fcontext -a, then apply it with restorecon -Rv.

You earned this cheat sheet. Every row is a form you just ran or built:

The one thing to burn in for the exam: semanage fcontext -a changes the RULE, restorecon changes the FILES, and you almost always need both, in that order. cp into a directory inherits the right type for free; mv drags the old type along and is the classic wrong-context case.

The regex '/web(/.*)?' is the standard "this directory and everything under it" pattern, and it is worth memorizing exactly. The (/.*)? part means "optionally, a slash followed by anything," so it matches both /web itself and every path beneath it. Reuse it for any tree: '/srv/data(/.*)?', '/app/uploads(/.*)?'. Forget it and restorecon will relabel only the top directory, leaving the files inside still wrong.

The practice terminal walked you through the whole repair. ls -Z to read a context, restorecon -v to reset one file, semanage fcontext -a -t to record a new permanent default, and restorecon -Rv to push that default onto a whole tree. You saw the honest no-op that a plain cp produces, and you saw the real Relabeled output that a wrong-context tree produces. Every one of those you typed yourself.

The security module capstone is Operation Lockdown, run against a real RHEL 10 VM. A full machine boots for you with SELinux Enforcing, a misbehaving service, and files wearing the wrong labels. Operation Lockdown hands you objectives that use exactly what you practiced here. Find the file that is denied, set the correct default with semanage fcontext -a, apply it with restorecon -Rv, and confirm the service comes back. One difference from this lesson: the capstone shows no commands. You read the objective, recall the semanage fcontext and restorecon forms, and type them. That recall is what makes it stick on exam day.

Finish the other security lessons, then go lock down a real machine in Operation Lockdown.

Practice restorecon and semanage fcontext in a real Linux terminal at The Linux Camp. Progress is verified automatically as you type commands on the machine.