When working with multi-user Linux systems, Systemd creates transient user-(UID).slice
units for each logged-in user. These slices form the parent cgroup hierarchy for all user processes. By default, these automatically generated slices inherit basic configurations without strict resource constraints.
While you can override settings per-user with individual user-1000.slice
files, maintaining consistent default limits across all users requires deeper Systemd integration. The transient nature of these slices (generated in /run/systemd/system/
) makes template-based configuration impossible through conventional drop-in files.
Method 1: Global User Slice Configuration
Edit the base user.slice
to affect all descendants:
# /etc/systemd/system/user.slice.d/90-resource-limits.conf
[Slice]
CPUQuota=150%
MemoryHigh=4G
MemoryMax=6G
TasksMax=5000
Method 2: Systemd System-Wide Drop-In
Create a system-wide configuration that applies to all user slices:
# /etc/systemd/system.conf.d/10-user-defaults.conf
DefaultCPUAccounting=yes
DefaultMemoryAccounting=yes
DefaultTasksAccounting=yes
DefaultTasksMax=2000
UID-Based Conditional Application
For more granular control, create a generator that writes slice files dynamically:
#!/bin/bash
# /usr/local/bin/user-slice-generator
UID_MIN=$(grep -E '^UID_MIN' /etc/login.defs | awk '{print $2}')
UID_MAX=$(grep -E '^UID_MAX' /etc/login.defs | awk '{print $2}')
for (( uid=UID_MIN; uid<=UID_MAX; uid++ )); do
mkdir -p "/run/systemd/system/user-${uid}.slice.d"
cat > "/run/systemd/system/user-${uid}.slice.d/90-resource-limits.conf" << EOF
[Slice]
MemoryMax=$(($uid % 100 * 100))M
CPUQuota=$(($uid % 10 * 10 + 100))%
EOF
done
After applying changes, verify with:
systemctl daemon-reload
systemd-cgtop
systemd-cgls
For specific user monitoring:
systemd-cgtop -u user-1000.slice
cat /sys/fs/cgroup/user.slice/user-1000.slice/cpu.max
- Changes to
system.conf
require full system reboot - Memory limits use hierarchical accounting (child cgroups can't exceed parent)
- CPU quotas operate on relative shares (100%=1 core)
- Transient units don't persist across reboots
When attempting to impose per-user resource limits via systemd's cgroup integration, we encounter several architectural constraints. The transient nature of user.slice instances presents particular configuration challenges:
# Typical auto-generated user slice (example for UID 1001)
$ systemctl cat user-1001.slice
# /run/systemd/system/user-1001.slice
[Slice]
MemoryHigh=8G
CPUQuota=200%
While systemd doesn't provide direct templating for user slices, we can implement persistent configurations through several methods:
Method 1: Drop-in Configuration Files
Create directory structure in /etc/systemd/system:
sudo mkdir -p /etc/systemd/system/user-.slice.d
sudo vim /etc/systemd/system/user-.slice.d/90-defaults.conf
Example configuration:
[Slice]
MemoryHigh=4G
CPUQuota=150%
TasksMax=5000
IOWeight=100
Method 2: UID-Specific Overrides
For special cases requiring user-specific limits:
sudo systemctl edit user-1000.slice
Sample override:
[Slice]
MemoryHigh=12G
CPUQuota=300%
AllowedCPUs=0-3
Configure /etc/systemd/logind.conf for system-wide defaults:
[Login]
UserTasksMax=10000
DefaultMemoryHigh=6G
DefaultCPUQuota=180%
Check applied limits with:
systemd-cgls -u user-1000.slice
systemctl show user-1000.slice --property MemoryHigh,CPUQuota
For deeper inspection:
cat /sys/fs/cgroup/user.slice/user-1000.slice/cpu.max
cat /sys/fs/cgroup/user.slice/user-1000.slice/memory.high
Here's a complete deployment script for a multi-user system:
#!/bin/bash
# Set system-wide defaults
echo "Configuring base limits..."
cat > /etc/systemd/system/user-.slice.d/90-base.conf < /etc/systemd/system/user-1001.slice.d/10-developer-override.conf <
When implementing these configurations in production:
- Test limits in staging environments first
- Monitor systemd journal for cgroup-related errors
- Consider combining with pam_limits for session-level constraints
- Document all overrides for maintainability