{"id":807,"date":"2026-08-05T23:09:52","date_gmt":"2026-08-05T23:09:52","guid":{"rendered":"https:\/\/virtualserversvps.com\/blog\/?p=807"},"modified":"2026-08-05T23:09:52","modified_gmt":"2026-08-05T23:09:52","slug":"systemd-service-hardening-sandboxing-capabilities","status":"publish","type":"post","link":"https:\/\/virtualserversvps.com\/blog\/systemd-service-hardening-sandboxing-capabilities\/","title":{"rendered":"systemd Service Hardening: Sandboxing, Capabilities, and Resource Limits"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">A freshly installed service on Ubuntu 24.04 typically scores 8\u20139 on <code>systemd-analyze security<\/code> \u2014 marked <code>EXPOSED<\/code> \u2014 because the default unit grants full filesystem, network, and capability access. The same service can usually be locked down to a score of 2\u20133 with a dozen declarative directives: <code>ProtectSystem<\/code>, <code>PrivateTmp<\/code>, <code>CapabilityBoundingSet<\/code>, <code>NoNewPrivileges<\/code>, and <code>MemoryMax<\/code>. These are restart-safe, survive upgrades, and cost almost no performance.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Hardening matters most on shared or underpowered nodes, where one compromised service can chew through the entire VPS. If you are about to provision one, <a href=\"https:\/\/virtualserversvps.com\/#providers\">see the full specs on our VPS comparison table<\/a> and plan the resource limits before you deploy.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Auditing a Unit with systemd-analyze<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>systemd-analyze security nginx\n# \u2192 Overall exposure level for nginx.service: 8.4 EXPOSED\nsystemd-analyze security --offline=yes nginx.service<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Run the audit first so you have a baseline score to compare against. The per-item list shows exactly which directives are missing \u2014 treat it as a checklist rather than a verdict.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The score is a heuristic, not a guarantee: it counts how many hardening features are enabled, not whether the service is actually exploitable. A score of 9 on a service that only listens on localhost is less alarming than a 5 on an internet-facing daemon with a history of CVEs. Use the number to track improvement over time and catch regressions when a package upgrade rewrites your unit files.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Filesystem Sandboxing<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>[Service]\nProtectSystem=strict\nProtectHome=true\nPrivateTmp=true\nReadWritePaths=\/var\/lib\/nginx \/var\/log\/nginx<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\"><li><code>ProtectSystem=strict<\/code> remounts the whole filesystem read-only except the paths you list in <code>ReadWritePaths<\/code>.<\/li><li><code>ProtectHome=true<\/code> makes <code>\/home<\/code>, <code>\/root<\/code>, and <code>\/run\/user<\/code> inaccessible to the service.<\/li><li><code>PrivateTmp=true<\/code> gives the service its own <code>\/tmp<\/code>, so it can neither read nor write other processes&#8217; temp files.<\/li><\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Dropping Capabilities<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>[Service]\nCapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_NET_RAW\nAmbientCapabilities=CAP_NET_BIND_SERVICE\nNoNewPrivileges=true<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">A web server typically only needs to bind low ports (<code>CAP_NET_BIND_SERVICE<\/code>) and, for ping or ICMP checks, <code>CAP_NET_RAW<\/code>. Everything else gets dropped from the bounding set \u2014 even a root-level exploit inside the service cannot regain capabilities that were never granted.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Capabilities are the Linux answer to &#8220;run as root but not really&#8221;: instead of granting the service full root, you grant it the specific privileges it needs. The bounding set is the ceiling for the process and all its children, and <code>AmbientCapabilities<\/code> (with <code>NoNewPrivileges=true<\/code>) actually hands the permitted capability to the running process. If a service breaks after tightening the set, run <code>journalctl -u example.service<\/code> and look for &#8220;Operation not permitted&#8221; \u2014 that tells you exactly which capability it still needs.<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Start from the defaults with <code>CapabilityBoundingSet=<\/code> (empty) and add back only what the service reports missing.<\/li><li>Keep <code>NoNewPrivileges=true<\/code> whenever possible \u2014 it blocks setuid binaries from escalating.<\/li><li>Re-check with <code>systemd-analyze security<\/code> after each change; the score drops as the set shrinks.<\/li><\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Resource Limits for Runaway Processes<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>[Service]\nMemoryMax=512M\nMemoryHigh=384M\nCPUQuota=75%\nTasksMax=256\nRestart=on-failure<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\"><li><code>MemoryMax<\/code> is a hard cap \u2014 the kernel OOM-kills the service rather than letting it exhaust the VPS.<\/li><li><code>MemoryHigh<\/code> applies memory pressure before the hard limit, throttling a slow leak before it becomes fatal.<\/li><li><code>CPUQuota=75%<\/code> caps CPU at 75% of one core, and <code>TasksMax<\/code> limits threads and forked children.<\/li><li><code>Restart=on-failure<\/code> brings the service back automatically without masking the underlying issue.<\/li><\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Network and Device Isolation<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>[Service]\nPrivateNetwork=true\nRestrictAddressFamilies=AF_INET AF_INET6\nDevicePolicy=closed\nDeviceAllow=\/dev\/null rw \/dev\/random r \/dev\/urandom r<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><code>PrivateNetwork=true<\/code> gives the service a network namespace with only a loopback interface \u2014 ideal for workers that only talk to local sockets. <code>DevicePolicy=closed<\/code> denies access to all device nodes except the ones you explicitly allow.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">A Hardened Unit End to End<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>[Unit]\nDescription=Hardened example service\nAfter=network.target\n\n[Service]\nExecStart=\/usr\/local\/bin\/example --config \/etc\/example.conf\nUser=example\nGroup=example\nProtectSystem=strict\nProtectHome=true\nPrivateTmp=true\nPrivateDevices=true\nNoNewPrivileges=true\nCapabilityBoundingSet=CAP_NET_BIND_SERVICE\nMemoryMax=512M\nTasksMax=256\nRestart=on-failure\n\n[Install]\nWantedBy=multi-user.target<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Run the service as an unprivileged user, combine the sandbox directives, and keep the resource limits explicit. Every line here is optional \u2014 add what your service tolerates and drop what breaks it.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Two details matter when you deploy this unit. First, <code>PrivateDevices=true<\/code> (used above) implies <code>DevicePolicy=closed<\/code> plus allowlists for <code>\/dev\/null<\/code>, <code>\/dev\/random<\/code>, and <code>\/dev\/urandom<\/code>, so you usually do not need both \u2014 pick one style and stay consistent. Second, keep the <code>[Install]<\/code> section intact: dropping it silently disables <code>systemctl enable<\/code>, and the service will not survive a reboot.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Also note that hardening directives are inheritable: any service the unit spawns (workers, subprocesses, CGI handlers) runs under the same restrictions. That is what you want for security, but it means the sandbox must fit the whole process tree, not just the parent \u2014 test with a real workload.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Verifying the Hardening<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>systemctl daemon-reload &amp;&amp; systemctl restart example\nsystemd-analyze security example\n# \u2192 Overall exposure level: 2.1 SAFE\nsystemctl status example   # confirm it is running under the new limits<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Apply directives one at a time and re-run the audit after each change; breakage shows up immediately in <code>systemctl status<\/code> with a clear error line, and you can roll back by deleting the directive and reloading.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Put the hardening in a drop-in instead of editing the vendor unit: create <code>\/etc\/systemd\/system\/example.service.d\/hardening.conf<\/code> with the <code>[Service]<\/code> overrides. Package upgrades then merge your settings instead of overwriting them, and you can see at a glance which directives are site-specific. Run <code>systemctl cat example.service<\/code> to confirm the merged unit looks the way you expect.<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Test the hardened unit under real traffic for at least one release cycle before rolling it out everywhere.<\/li><li>Document the directives in your runbook \u2014 the next person who debugs a &#8220;permission denied&#8221; will thank you.<\/li><li>Re-run <code>systemd-analyze security<\/code> after every package upgrade; some packages reset unit files on install.<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">A hardened unit costs nothing in throughput but removes entire classes of privilege-escalation and resource-exhaustion attacks. When you are choosing the node to run it on, <a href=\"https:\/\/virtualserversvps.com\/#providers\">compare plans side by side on our comparison table<\/a> to get predictable per-core CPU and enough RAM for your limits.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">InterServer VPS plans give you full root access and dedicated vCPU allocation, so hardened services get stable, predictable resources. Check <a href=\"https:\/\/interserver.net\/vps?id=1067805&amp;sid=virtualserversvps\" rel=\"noreferrer noopener sponsored\" target=\"_blank\">InterServer VPS plans and pricing<\/a> to spin up a locked-down node today.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A freshly installed service on Ubuntu 24.04 typically scores 8\u20139 on systemd-analyze security \u2014 marked EXPOSED \u2014 because the default unit grants full filesystem, network, and capability access. The same&#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-807","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>systemd Service Hardening: Sandboxing, Capabilities, and Resource Limits - 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\/systemd-service-hardening-sandboxing-capabilities\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"systemd Service Hardening: Sandboxing, Capabilities, and Resource Limits\" \/>\n<meta property=\"og:description\" content=\"systemd Service Hardening: Sandboxing, Capabilities, and Resource Limits\" \/>\n<meta property=\"og:url\" content=\"https:\/\/virtualserversvps.com\/blog\/systemd-service-hardening-sandboxing-capabilities\/\" \/>\n<meta property=\"og:site_name\" content=\"Virtual Servers VPS Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-08-05T23:09:52+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\/systemd-service-hardening-sandboxing-capabilities\/\",\"url\":\"https:\/\/virtualserversvps.com\/blog\/systemd-service-hardening-sandboxing-capabilities\/\",\"name\":\"systemd Service Hardening: Sandboxing, Capabilities, and Resource Limits - Virtual Servers VPS Blog\",\"isPartOf\":{\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#website\"},\"datePublished\":\"2026-08-05T23:09:52+00:00\",\"author\":{\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/82a299a8284a66ff49f97c74684724a0\"},\"breadcrumb\":{\"@id\":\"https:\/\/virtualserversvps.com\/blog\/systemd-service-hardening-sandboxing-capabilities\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/virtualserversvps.com\/blog\/systemd-service-hardening-sandboxing-capabilities\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/systemd-service-hardening-sandboxing-capabilities\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/virtualserversvps.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"systemd Service Hardening: Sandboxing, Capabilities, and Resource Limits\"}]},{\"@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":"systemd Service Hardening: Sandboxing, Capabilities, and Resource Limits - 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\/systemd-service-hardening-sandboxing-capabilities\/","og_locale":"en_US","og_type":"article","og_title":"systemd Service Hardening: Sandboxing, Capabilities, and Resource Limits","og_description":"systemd Service Hardening: Sandboxing, Capabilities, and Resource Limits","og_url":"https:\/\/virtualserversvps.com\/blog\/systemd-service-hardening-sandboxing-capabilities\/","og_site_name":"Virtual Servers VPS Blog","article_published_time":"2026-08-05T23:09:52+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\/systemd-service-hardening-sandboxing-capabilities\/","url":"https:\/\/virtualserversvps.com\/blog\/systemd-service-hardening-sandboxing-capabilities\/","name":"systemd Service Hardening: Sandboxing, Capabilities, and Resource Limits - Virtual Servers VPS Blog","isPartOf":{"@id":"https:\/\/virtualserversvps.com\/blog\/#website"},"datePublished":"2026-08-05T23:09:52+00:00","author":{"@id":"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/82a299a8284a66ff49f97c74684724a0"},"breadcrumb":{"@id":"https:\/\/virtualserversvps.com\/blog\/systemd-service-hardening-sandboxing-capabilities\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/virtualserversvps.com\/blog\/systemd-service-hardening-sandboxing-capabilities\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/virtualserversvps.com\/blog\/systemd-service-hardening-sandboxing-capabilities\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/virtualserversvps.com\/blog\/"},{"@type":"ListItem","position":2,"name":"systemd Service Hardening: Sandboxing, Capabilities, and Resource Limits"}]},{"@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\/807","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=807"}],"version-history":[{"count":1,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/posts\/807\/revisions"}],"predecessor-version":[{"id":809,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/posts\/807\/revisions\/809"}],"wp:attachment":[{"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/media?parent=807"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/categories?post=807"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/tags?post=807"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}