{"id":1167,"date":"2026-09-18T22:33:52","date_gmt":"2026-09-18T22:33:52","guid":{"rendered":"https:\/\/virtualserversvps.com\/blog\/?p=1167"},"modified":"2026-09-18T22:33:52","modified_gmt":"2026-09-18T22:33:52","slug":"systemd-resource-control-slices-cap-runaway-vps-processes","status":"publish","type":"post","link":"https:\/\/virtualserversvps.com\/blog\/systemd-resource-control-slices-cap-runaway-vps-processes\/","title":{"rendered":"Using systemd Slices to Cap Runaway Processes on a VPS"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">You&#8217;ve seen it: a runaway process eats all available CPU on your VPS, the load average spikes to 40, SSH becomes unresponsive, and the only fix is a hard reboot from the provider panel. The usual advice is to install a userspace daemon to watch for high load. That&#8217;s the wrong layer. systemd already has a complete resource-control framework built in, and on any modern VPS with cgroup v2 you can cap CPU, memory, I\/O, and process counts so that a runaway service degrades <em>itself<\/em> instead of the whole machine. This guide walks through the units, the directives, and how to verify the limits are actually enforced. If your provider&#8217;s images don&#8217;t support cgroup v2, <a href=\"https:\/\/virtualserversvps.com\/\">see our full VPS comparison<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Confirm cgroup v2 is active<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Everything below assumes the unified cgroup v2 hierarchy. Check it first \u2014 many older VPS images still boot with the legacy v1 layout, where the specific directives differ.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>stat -fc %T \/sys\/fs\/cgroup\/\n# 'cgroup2fs' = v2 (good).  'tmpfs' = v1 (legacy).\n\nsystemctl --version | head -1   # systemd 243+ for most directives below\n\n# See live per-slice resource usage\nsystemd-cgtop -m<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If you&#8217;re on cgroup v1, add <code>systemd.unified_cgroup_hierarchy=1<\/code> to the kernel command line and reboot. On a VPS with GRUB, edit <code>\/etc\/default\/grub<\/code> and run <code>update-grub<\/code>. Some providers use a custom bootloader, so confirm your changes persist across a reboot before relying on them.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The four slices you should have<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">systemd ships with <code>system.slice<\/code>, <code>user.slice<\/code>, and <code>machine.slice<\/code>. The trick is to put backup jobs, web services, and anything untrusted into their own slices so their resource consumption is bounded independently.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Slice<\/th><th>Purpose<\/th><th>Typical cap on a 2 vCPU \/ 4 GB VPS<\/th><\/tr><\/thead><tbody><tr><td><code>system.slice<\/code><\/td><td>Critical daemons: sshd, networking, journald<\/td><td>Never capped \u2014 protect it<\/td><\/tr><tr><td><code>web.slice<\/code><\/td><td>nginx, PHP-FPM, app servers<\/td><td>CPUQuota=150%, MemoryMax=2G<\/td><\/tr><tr><td><code>batch.slice<\/code><\/td><td>Backups, log rotation, cron jobs<\/td><td>CPUQuota=50%, IOWeight=50<\/td><\/tr><tr><td><code>user.slice<\/code><\/td><td>Interactive SSH sessions<\/td><td>Untouched<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Protecting <code>system.slice<\/code> is the key insight. When a runaway process belongs to <code>web.slice<\/code>, the kernel will throttle it there, and sshd \u2014 living in <code>system.slice<\/code> \u2014 keeps responding. You can still log in and investigate instead of reaching for the provider&#8217;s reboot button.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Defining the slices<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Slices are just unit files with a <code>.slice<\/code> suffix. Create them under <code>\/etc\/systemd\/system\/<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo tee \/etc\/systemd\/system\/web.slice &gt;\/dev\/null &lt;&lt;'EOF'\n[Unit]\nDescription=Web services slice\n\n[Slice]\nCPUAccounting=yes\nCPUQuota=150%\nMemoryAccounting=yes\nMemoryHigh=1600M\nMemoryMax=2G\nMemorySwapMax=512M\nTasksMax=512\nIOAccounting=yes\nIOWeight=200\nEOF\n\nsudo tee \/etc\/systemd\/system\/batch.slice &gt;\/dev\/null &lt;&lt;'EOF'\n[Unit]\nDescription=Background batch jobs slice\n\n[Slice]\nCPUAccounting=yes\nCPUQuota=50%\nMemoryAccounting=yes\nMemoryMax=768M\nTasksMax=256\nIOWeight=50\nEOF\n\nsudo systemctl daemon-reload<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">A few semantics worth internalising:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><code>MemoryHigh<\/code> vs <code>MemoryMax<\/code>.<\/strong> <code>MemoryHigh<\/code> is a soft limit \u2014 the kernel reclaims aggressively and throttles the cgroup rather than killing it. <code>MemoryMax<\/code> is a hard limit; exceeding it triggers the OOM killer <em>within that cgroup only<\/em>, not globally. Set High below Max to get graceful degradation before a kill.<\/li>\n<li><strong><code>CPUQuota<\/code> is a ceiling, not a reservation.<\/strong> <code>CPUQuota=150%<\/code> means the slice can consume at most one and a half cores&#8217; worth of time. It can be idle; the machine just won&#8217;t let it exceed the cap.<\/li>\n<li><strong><code>IOWeight<\/code><\/strong> is a relative share (1\u201310000, default 100). Under contention, a process with weight 200 gets roughly twice the bandwidth of one at weight 100. It only matters when the device is saturated.<\/li>\n<li><strong><code>TasksMax<\/code><\/strong> caps the number of processes\/threads, which prevents fork bombs from filling the PID table.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Assigning services to slices<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Use a drop-in override rather than editing the shipped unit file \u2014 package updates won&#8217;t overwrite it.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Put nginx into web.slice\nsudo systemctl edit nginx\n# In the editor, add:\n#   [Service]\n#   Slice=web.slice\n\n# Per-service hard stop on top of the slice cap\nsudo mkdir -p \/etc\/systemd\/system\/nginx.service.d\nsudo tee \/etc\/systemd\/system\/nginx.service.d\/limits.conf &gt;\/dev\/null &lt;&lt;'EOF'\n[Service]\nSlice=web.slice\nMemoryMax=1G\nTasksMax=256\nEOF\n\n# Batch jobs: a backup unit\nsudo mkdir -p \/etc\/systemd\/system\/backup.service.d\nsudo tee \/etc\/systemd\/system\/backup.service.d\/limits.conf &gt;\/dev\/null &lt;&lt;'EOF'\n[Service]\nSlice=batch.slice\nNice=10\nIOSchedulingClass=best-effort\nIOSchedulingPriority=7\nEOF\n\nsudo systemctl daemon-reload\nsudo systemctl restart nginx<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">For cron-driven work, the cleanest pattern is to stop using cron entirely for heavy jobs and define transient units instead, so every job inherits slice limits. A timer plus a service gives you the same schedule with accounting, logging, and resource control for free.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Verifying the caps are enforced<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Directives that aren&#8217;t enforced are worse than none, because they give false confidence. Test each one deliberately.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Inspect the effective cgroup limits for a running service\nsystemctl show nginx -p Slice -p MemoryMax -p CPUQuotaPerSecUSec -p TasksMax\ncat \/sys\/fs\/cgroup\/web.slice\/memory.max\ncat \/sys\/fs\/cgroup\/web.slice\/cpu.max       # format: \"quota period\"\n\n# Prove the memory cap works: allocate past MemoryMax inside the slice\nsystemd-run --slice=batch.slice --unit=memtest -p MemoryMax=64M \\\n  \/bin\/sh -c 'python3 -c \"a=bytearray(200*1024*1024); print(len(a))\"'\nsystemctl status memtest   # expect a SIGKILL \/ OOM message, not a system-wide stall\n\n# Prove the CPU cap works: burn cycles and watch the usage\nsystemd-run --slice=batch.slice --unit=cputest -p CPUQuota=25% \\\n  \/bin\/sh -c 'while :; do :; done' &amp;\nsleep 10\nsystemd-cgtop -m --iterations=1   # batch.slice should sit near 25%\nsystemctl stop cputest<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">When <code>cputest<\/code> shows roughly a quarter of one core and <code>memtest<\/code> gets killed while the rest of the system stays responsive, you&#8217;ve confirmed the framework is doing its job.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Common mistakes<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Setting <code>MemoryMax<\/code> without <code>MemoryHigh<\/code>.<\/strong> The service gets OOM-killed abruptly instead of being throttled first.<\/li>\n<li><strong>Capping <code>system.slice<\/code>.<\/strong> Never do this. If sshd and networking compete for a capped budget you&#8217;ve created a lockout scenario.<\/li>\n<li><strong>Forgetting <code>daemon-reload<\/code>.<\/strong> Changes to slice files do nothing until systemd rereads them, and existing cgroups are only re-parented on service restart.<\/li>\n<li><strong>Ignoring swap.<\/strong> Without <code>MemorySwapMax<\/code>, a memory-hungry service can push the whole VPS into swap thrash before hitting <code>MemoryMax<\/code>.<\/li>\n<li><strong>Setting <code>TasksMax<\/code> too low on a threaded app.<\/strong> A web server with a thread-per-connection model will hit a low cap and start refusing work. Watch <code>systemd-cgtop<\/code> task counts under load first.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Complementing this with kernel-level tuning<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Slices control <em>who<\/em> gets what. You still want the kernel&#8217;s own reclaim behaviour tuned so that memory pressure is handled gracefully \u2014 lower <code>vm.swappiness<\/code> for database hosts, sane <code>dirty_ratio<\/code> values for slow virtual disks. Slices and sysctls solve different halves of the same problem, and together they turn a fragile instance into one that survives its own mistakes.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Resource control is one of the strongest arguments for picking a provider that gives you a current systemd and a cgroup v2 kernel. Providers running 4.15 kernels with cgroup v1 can&#8217;t offer any of this. <a href=\"https:\/\/virtualserversvps.com\/\">See our full VPS comparison<\/a> for hosts that ship modern images with full root access.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Want to stop rebooting your VPS to fix runaway processes? <a href=\"https:\/\/virtualserversvps.com\/\" rel=\"noreferrer noopener sponsored\">Compare VPS plans with full systemd and cgroup v2 support<\/a> and get an instance where resource limits actually protect you.<\/p>\n\n","protected":false},"excerpt":{"rendered":"<p>You&#8217;ve seen it: a runaway process eats all available CPU on your VPS, the load average spikes to 40, SSH becomes unresponsive, and the only fix is a hard reboot&#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":1,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-1167","post","type-post","status-publish","format-standard","hentry","category-vps-guides-tutorials"],"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>Using systemd Slices to Cap Runaway Processes on a VPS - 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-resource-control-slices-cap-runaway-vps-processes\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Using systemd Slices to Cap Runaway Processes on a VPS\" \/>\n<meta property=\"og:description\" content=\"Using systemd Slices to Cap Runaway Processes on a VPS\" \/>\n<meta property=\"og:url\" content=\"https:\/\/virtualserversvps.com\/blog\/systemd-resource-control-slices-cap-runaway-vps-processes\/\" \/>\n<meta property=\"og:site_name\" content=\"Virtual Servers VPS Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-09-18T22:33: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=\"6 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/systemd-resource-control-slices-cap-runaway-vps-processes\/\",\"url\":\"https:\/\/virtualserversvps.com\/blog\/systemd-resource-control-slices-cap-runaway-vps-processes\/\",\"name\":\"Using systemd Slices to Cap Runaway Processes on a VPS - Virtual Servers VPS Blog\",\"isPartOf\":{\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#website\"},\"datePublished\":\"2026-09-18T22:33:52+00:00\",\"author\":{\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/82a299a8284a66ff49f97c74684724a0\"},\"breadcrumb\":{\"@id\":\"https:\/\/virtualserversvps.com\/blog\/systemd-resource-control-slices-cap-runaway-vps-processes\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/virtualserversvps.com\/blog\/systemd-resource-control-slices-cap-runaway-vps-processes\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/systemd-resource-control-slices-cap-runaway-vps-processes\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/virtualserversvps.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Using systemd Slices to Cap Runaway Processes on a VPS\"}]},{\"@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":"Using systemd Slices to Cap Runaway Processes on a VPS - 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-resource-control-slices-cap-runaway-vps-processes\/","og_locale":"en_US","og_type":"article","og_title":"Using systemd Slices to Cap Runaway Processes on a VPS","og_description":"Using systemd Slices to Cap Runaway Processes on a VPS","og_url":"https:\/\/virtualserversvps.com\/blog\/systemd-resource-control-slices-cap-runaway-vps-processes\/","og_site_name":"Virtual Servers VPS Blog","article_published_time":"2026-09-18T22:33:52+00:00","author":"Virtual-Servers-Vps-Editor","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Virtual-Servers-Vps-Editor","Est. reading time":"6 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/virtualserversvps.com\/blog\/systemd-resource-control-slices-cap-runaway-vps-processes\/","url":"https:\/\/virtualserversvps.com\/blog\/systemd-resource-control-slices-cap-runaway-vps-processes\/","name":"Using systemd Slices to Cap Runaway Processes on a VPS - Virtual Servers VPS Blog","isPartOf":{"@id":"https:\/\/virtualserversvps.com\/blog\/#website"},"datePublished":"2026-09-18T22:33:52+00:00","author":{"@id":"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/82a299a8284a66ff49f97c74684724a0"},"breadcrumb":{"@id":"https:\/\/virtualserversvps.com\/blog\/systemd-resource-control-slices-cap-runaway-vps-processes\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/virtualserversvps.com\/blog\/systemd-resource-control-slices-cap-runaway-vps-processes\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/virtualserversvps.com\/blog\/systemd-resource-control-slices-cap-runaway-vps-processes\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/virtualserversvps.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Using systemd Slices to Cap Runaway Processes on a VPS"}]},{"@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\/1167","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=1167"}],"version-history":[{"count":1,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/posts\/1167\/revisions"}],"predecessor-version":[{"id":1176,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/posts\/1167\/revisions\/1176"}],"wp:attachment":[{"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/media?parent=1167"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/categories?post=1167"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/tags?post=1167"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}