{"id":587,"date":"2026-07-20T17:58:03","date_gmt":"2026-07-20T17:58:03","guid":{"rendered":"https:\/\/virtualserversvps.com\/blog\/?p=587"},"modified":"2026-07-20T17:58:03","modified_gmt":"2026-07-20T17:58:03","slug":"securing-vps-selinux-apparmor-mandatory-access-control","status":"publish","type":"post","link":"https:\/\/virtualserversvps.com\/blog\/securing-vps-selinux-apparmor-mandatory-access-control\/","title":{"rendered":"Securing Your VPS with SELinux and AppArmor: A Practical Guide to Mandatory Access Control on Linux"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">A standard Linux VPS runs discretionary access control (DAC) \u2014 if a process has root, it can do anything. Mandatory access control (MAC) systems like <strong>SELinux<\/strong> and <strong>AppArmor<\/strong> add a second layer of security: even processes running as root can only access what their policy allows. This guide explains how to configure both systems on your VPS, which one to choose, and how to troubleshoot the inevitable access denials.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Looking for a broader VPS security strategy? Start with our <a href=\"https:\/\/virtualserversvps.com\/#why\">feature overview<\/a> to see what performance and security features different providers offer.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">SELinux vs AppArmor: Which One Should You Use?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Both systems enforce MAC, but they approach it differently. The choice often comes down to your Linux distribution:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Feature<\/th><th>SELinux<\/th><th>AppArmor<\/th><\/tr><\/thead><tbody><tr><td>Default on<\/td><td>RHEL, CentOS, Fedora, AlmaLinux, Rocky Linux<\/td><td>Ubuntu, Debian, OpenSUSE<\/td><\/tr><tr><td>Policy model<\/td><td>Label-based (every file, process, and port has a security context)<\/td><td>Path-based (policies reference file paths and network access)<\/td><\/tr><tr><td>Granularity<\/td><td>Extremely fine-grained. Every system object gets a label.<\/td><td>Coarser but simpler. Policies target specific applications.<\/td><\/tr><tr><td>Learning curve<\/td><td>Steep. Requires understanding security contexts, booleans, and policy modules.<\/td><td>Gentle. Policies are human-readable text files.<\/td><\/tr><tr><td>Audit logs<\/td><td>\/var\/log\/audit\/audit.log (use <code>ausearch<\/code> or <code>sealert<\/code>)<\/td><td>\/var\/log\/syslog or \/var\/log\/kern.log (grep for &#8220;DENIED&#8221; or &#8220;ALLOWED&#8221;)<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">If you are on Ubuntu or Debian, AppArmor is the natural choice. On RHEL-based distributions, SELinux is the default and is deeply integrated into the system packaging (Nginx, MariaDB, and PHP all ship with SELinux policies).<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Installing and Enabling AppArmor on Ubuntu\/Debian<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">AppArmor is pre-installed on Ubuntu (since 8.04) and Debian (since 7). Verify it is running:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo aa-status\n# Should show: \"apparmor module is loaded.\" and a list of profiles<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Installing AppArmor Utilities<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo apt update\nsudo apt install apparmor-utils apparmor-profiles<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Creating a Custom AppArmor Profile for Nginx<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Let us create a profile that restricts Nginx to only the files and network permissions it actually needs.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Generate a profile template based on Nginx's actual behavior\nsudo aa-genprof \/usr\/sbin\/nginx\n\n# Follow the interactive prompts. Run typical Nginx operations\n# (request pages, reload config) then press 'S' to scan,\n# and 'A' to allow each detected permission.<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">After genprof completes, the profile is stored at <code>\/etc\/apparmor.d\/usr.sbin.nginx<\/code>. You can edit it directly:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># \/etc\/apparmor.d\/usr.sbin.nginx\n#include &lt;tunables\/global&gt;\n\n\/usr\/sbin\/nginx {\n  #include &lt;abstractions\/base&gt;\n  #include &lt;abstractions\/nameservice&gt;\n\n  \/etc\/nginx\/** r,\n  \/var\/log\/nginx\/* w,\n  \/var\/www\/** r,\n  \/run\/nginx.pid rw,\n\n  # Allow listening on port 80 and 443\n  network inet tcp,\n  network inet6 tcp,\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Apply the profile:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo aa-enforce \/usr\/sbin\/nginx\n# Or try in complain mode first to log denials without blocking:\n# sudo aa-complain \/usr\/sbin\/nginx<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Configuring SELinux on RHEL\/AlmaLinux\/CentOS<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Check SELinux Status<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>getenforce\n# Output: Enforcing (good) or Permissive or Disabled<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If SELinux is disabled, you can enable it by editing <code>\/etc\/selinux\/config<\/code> and setting <code>SELINUX=enforcing<\/code>, then rebooting. Note that changing from disabled to enforcing on an existing system may uncover previously hidden policy violations \u2014 test in permissive mode first.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Managing SELinux Booleans<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Booleans are SELinux toggles that adjust policy without writing rules. Common ones for a web server VPS:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Allow Nginx to connect to network services (proxying, database)\nsetsebool -P httpd_can_network_connect on\n\n# Allow Nginx to send email\nsetsebool -P httpd_can_sendmail on\n\n# Allow scripts to write to directories (for CMS platforms)\nsetsebool -P httpd_unified on\n\n# List all booleans\ngetsebool -a<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Fixing SELinux Denials<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">When SELinux blocks an operation, it logs to <code>\/var\/log\/audit\/audit.log<\/code>. Use <strong>sealert<\/strong> to get human-readable solutions:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Check for denials in the last hour\nsudo ausearch -m avc -ts recent | audit2allow -a\n\n# Generate a custom policy module to allow a specific denial\nsudo grep \"denied\" \/var\/log\/audit\/audit.log | audit2allow -M myhttpd\nsudo semodule -i myhttpd.pp<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Always prefer setting the correct file context over writing allow rules. If a web application needs write access to a directory, set the httpd_sys_content_t or httpd_sys_rw_content_t context:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Change file context for a writable directory\nsudo semanage fcontext -a -t httpd_sys_rw_content_t \"\/var\/www\/myapp\/uploads(\/.*)?\"\nsudo restorecon -Rv \/var\/www\/myapp\/uploads<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Common Pitfalls and How to Troubleshoot Them<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Problem<\/th><th>Likely Cause<\/th><th>Fix<\/th><\/tr><\/thead><tbody><tr><td>Nginx returns 403 with correct file permissions<\/td><td>SELinux context on document root is wrong<\/td><td><code>chcon -R -t httpd_sys_content_t \/var\/www<\/code><\/td><\/tr><tr><td>PHP cannot connect to MySQL<\/td><td>SELinux blocking httpd network access<\/td><td><code>setsebool -P httpd_can_network_connect on<\/code><\/td><\/tr><tr><td>AppArmor blocking log rotation<\/td><td>logrotate needs write access to var\/log<\/td><td>Add <code>\/var\/log\/nginx\/* rw,<\/code> to AppArmor profile<\/td><\/tr><tr><td>Cannot start Nginx<\/td><td>AppArmor profile blocks port binding<\/td><td>Ensure profile includes <code>network inet tcp,<\/code><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Best Practices for MAC on Your VPS<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Start in <strong>permissive\/complain mode<\/strong> on new installations. Review logs for a week before enforcing policies.<\/li>\n<li>Keep profiles as narrow as possible. Granting blanket permissions defeats the purpose of MAC.<\/li>\n<li>For containerized workloads, use SELinux or AppArmor in combination with container-specific security profiles (seccomp, capabilities drop).<\/li>\n<li>Set up log monitoring for MAC denials. A sudden spike in denials often indicates a compromised application or misconfiguration.<\/li>\n<li>Update policies when you update application configurations. Changing Nginx document root requires updating the corresponding profile or context.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Mandatory access control is one of the most effective security layers you can add to a Linux VPS. AppArmor on Ubuntu\/Debian or SELinux on RHEL-based distributions prevents common attack vectors like file inclusion, privilege escalation, and network pivoting \u2014 even if an attacker gains code execution. Invest the hour to configure it properly, and your VPS will be significantly harder to compromise.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Compare VPS providers that offer security-enhanced hosting environments on our <a href=\"https:\/\/virtualserversvps.com\/#providers\">comparison table<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A standard Linux VPS runs discretionary access control (DAC) \u2014 if a process has root, it can do anything. Mandatory access control (MAC) systems like SELinux and AppArmor add a&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"iawp_total_views":0,"footnotes":""},"categories":[4],"tags":[],"class_list":["post-587","post","type-post","status-publish","format-standard","hentry","category-security-compliance"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v26.1 (Yoast SEO v26.1) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Securing Your VPS with SELinux and AppArmor: A Practical Guide to Mandatory Access Control on Linux - Virtual Servers VPS Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/virtualserversvps.com\/blog\/securing-vps-selinux-apparmor-mandatory-access-control\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Securing Your VPS with SELinux and AppArmor: A Practical Guide to Mandatory Access Control on Linux\" \/>\n<meta property=\"og:description\" content=\"Securing Your VPS with SELinux and AppArmor: A Practical Guide to Mandatory Access Control on Linux\" \/>\n<meta property=\"og:url\" content=\"https:\/\/virtualserversvps.com\/blog\/securing-vps-selinux-apparmor-mandatory-access-control\/\" \/>\n<meta property=\"og:site_name\" content=\"Virtual Servers VPS Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-07-20T17:58:03+00:00\" \/>\n<meta name=\"author\" content=\"Virtual-Servers-Vps-Editor\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Virtual-Servers-Vps-Editor\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"5 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/securing-vps-selinux-apparmor-mandatory-access-control\/\",\"url\":\"https:\/\/virtualserversvps.com\/blog\/securing-vps-selinux-apparmor-mandatory-access-control\/\",\"name\":\"Securing Your VPS with SELinux and AppArmor: A Practical Guide to Mandatory Access Control on Linux - Virtual Servers VPS Blog\",\"isPartOf\":{\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#website\"},\"datePublished\":\"2026-07-20T17:58:03+00:00\",\"author\":{\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/82a299a8284a66ff49f97c74684724a0\"},\"breadcrumb\":{\"@id\":\"https:\/\/virtualserversvps.com\/blog\/securing-vps-selinux-apparmor-mandatory-access-control\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/virtualserversvps.com\/blog\/securing-vps-selinux-apparmor-mandatory-access-control\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/securing-vps-selinux-apparmor-mandatory-access-control\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/virtualserversvps.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Securing Your VPS with SELinux and AppArmor: A Practical Guide to Mandatory Access Control on Linux\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#website\",\"url\":\"https:\/\/virtualserversvps.com\/blog\/\",\"name\":\"Virtual Servers VPS Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/virtualserversvps.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/82a299a8284a66ff49f97c74684724a0\",\"name\":\"Virtual-Servers-Vps-Editor\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/d820b15f1cd028e97610d9adf536df7be5cb6423869967037d468d5355fa003f?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/d820b15f1cd028e97610d9adf536df7be5cb6423869967037d468d5355fa003f?s=96&d=mm&r=g\",\"caption\":\"Virtual-Servers-Vps-Editor\"},\"sameAs\":[\"https:\/\/virtualserversvps.com\/blog\"],\"url\":\"https:\/\/virtualserversvps.com\/blog\/author\/virtualserversvps\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Securing Your VPS with SELinux and AppArmor: A Practical Guide to Mandatory Access Control on Linux - Virtual Servers VPS Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/virtualserversvps.com\/blog\/securing-vps-selinux-apparmor-mandatory-access-control\/","og_locale":"en_US","og_type":"article","og_title":"Securing Your VPS with SELinux and AppArmor: A Practical Guide to Mandatory Access Control on Linux","og_description":"Securing Your VPS with SELinux and AppArmor: A Practical Guide to Mandatory Access Control on Linux","og_url":"https:\/\/virtualserversvps.com\/blog\/securing-vps-selinux-apparmor-mandatory-access-control\/","og_site_name":"Virtual Servers VPS Blog","article_published_time":"2026-07-20T17:58:03+00:00","author":"Virtual-Servers-Vps-Editor","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Virtual-Servers-Vps-Editor","Est. reading time":"5 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/virtualserversvps.com\/blog\/securing-vps-selinux-apparmor-mandatory-access-control\/","url":"https:\/\/virtualserversvps.com\/blog\/securing-vps-selinux-apparmor-mandatory-access-control\/","name":"Securing Your VPS with SELinux and AppArmor: A Practical Guide to Mandatory Access Control on Linux - Virtual Servers VPS Blog","isPartOf":{"@id":"https:\/\/virtualserversvps.com\/blog\/#website"},"datePublished":"2026-07-20T17:58:03+00:00","author":{"@id":"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/82a299a8284a66ff49f97c74684724a0"},"breadcrumb":{"@id":"https:\/\/virtualserversvps.com\/blog\/securing-vps-selinux-apparmor-mandatory-access-control\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/virtualserversvps.com\/blog\/securing-vps-selinux-apparmor-mandatory-access-control\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/virtualserversvps.com\/blog\/securing-vps-selinux-apparmor-mandatory-access-control\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/virtualserversvps.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Securing Your VPS with SELinux and AppArmor: A Practical Guide to Mandatory Access Control on Linux"}]},{"@type":"WebSite","@id":"https:\/\/virtualserversvps.com\/blog\/#website","url":"https:\/\/virtualserversvps.com\/blog\/","name":"Virtual Servers VPS Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/virtualserversvps.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/82a299a8284a66ff49f97c74684724a0","name":"Virtual-Servers-Vps-Editor","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/d820b15f1cd028e97610d9adf536df7be5cb6423869967037d468d5355fa003f?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/d820b15f1cd028e97610d9adf536df7be5cb6423869967037d468d5355fa003f?s=96&d=mm&r=g","caption":"Virtual-Servers-Vps-Editor"},"sameAs":["https:\/\/virtualserversvps.com\/blog"],"url":"https:\/\/virtualserversvps.com\/blog\/author\/virtualserversvps\/"}]}},"_links":{"self":[{"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/posts\/587","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/comments?post=587"}],"version-history":[{"count":1,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/posts\/587\/revisions"}],"predecessor-version":[{"id":684,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/posts\/587\/revisions\/684"}],"wp:attachment":[{"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/media?parent=587"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/categories?post=587"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/tags?post=587"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}