Skip to main content
skill CX Codex

systemd-services — Claude Code skill: what it does, how to install

Creates and manages systemd service units, timers, and socket activation. Use it to run background apps and configure resource limits under Linux.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add BagelHole/DevOps-Security-Agent-Skills --skill systemd-services -a claude-code
Open on GitHub

What systemd-services does

The skill guides the agent in authoring systemd unit files and handling Linux background services. It includes unit templates with restart policies and security flags like ProtectSystem=strict and NoNewPrivileges. The guide also details ordering rules such as After, Requires, and Wants alongside dependency tree inspection.

It provides patterns for replacing cron jobs with systemd timers using OnCalendar and Persistent=true. You also get instructions for socket activation and cgroups v2 quotas like MemoryMax and CPUQuota inside drop-in configuration directories.

Root or sudo access is mandatory here because system-level units live in /etc/systemd/system/. For timer debugging, the skill suggests validating expressions via systemd-analyze calendar.

What it helps with

  • deploy a background application as a managed systemd unit
  • replace cron jobs with systemd timers and persistent scheduling
  • set memory and CPU quotas using cgroups v2 drop-in files
  • configure socket activation for on-demand service startup
  • harden service processes with filesystem and privilege restrictions

Example prompts for the agent

  • Create a systemd unit file for my backend with on-failure restart and a 1G memory limit
  • Set up a daily systemd backup timer running at 2:30 AM with persistent execution
  • Show me how to configure socket activation on port 8080 for my server binary

How to install systemd-services

1Skills CLI (Vercel)

npx skills add BagelHole/DevOps-Security-Agent-Skills --skill systemd-services -a claude-code

2Manually: put the files in place

~/.claude/skills/systemd-services/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/systemd-services/

Step by step, with commands for each platform: How to install skills in Claude Code: five ways

Questions about systemd-services

How to install systemd-services in Claude Code?

Run npx skills add BagelHole/DevOps-Security-Agent-Skills --skill systemd-services -a claude-code. This installs the skill files into your Claude Code environment.

What does systemd-services do?

It gives the AI assistant unit templates, security hardening directives, timer configs, and systemctl commands to manage Linux background processes.

What are the prerequisites for this skill?

You need a Linux distribution running systemd and root or sudo privileges. Elevated access is required to write service files into /etc/systemd/system/.

Source text

SKILL.md · MIT
---
name: systemd-services
description: Create and manage systemd services and timers. Configure service dependencies and resource limits. Use when managing system services.
license: MIT
metadata:
  author: devops-skills
  version: "1.0"
---

# Systemd Services

Create, manage, and monitor systemd services and timers. Covers unit file authoring, dependency management, socket activation, resource limits, journalctl log analysis, and production hardening.

## When to Use

- Deploying an application as a managed background service
- Replacing cron jobs with systemd timers for better logging and dependency control
- Setting up socket activation for on-demand service startup
- Configuring resource limits (CPU, memory, I/O) for services
- Debugging service startup failures and runtime crashes
- Managing service dependencies and ordering

## Prerequisites

- Linux system running systemd (most modern distributions)
- Root or sudo access for creating system-level unit files
- Application binary or script to run as a service
- Understanding of the application's start/stop lifecycle

## Service Unit File -- Complete Example

```ini
# /etc/systemd/system/myapp.service
[Unit]
Description=MyApp Production Server
Documentation=https://docs.example.com/myapp
After=network-online.target postgresql.service
Wants=network-online.target
Requires=postgresql.service

[Service]
Type=notify
User=myapp
Group=myapp
WorkingDirectory=/opt/myapp

# Environment configuration
EnvironmentFile=/etc/myapp/env
Environment=NODE_ENV=production
Environment=PORT=8080

# Execution
ExecStartPre=/opt/myapp/bin/migrate --check
ExecStart=/opt/myapp/bin/server --config /etc/myapp/config.yaml
ExecStartPost=/opt/myapp/bin/healthcheck.sh
ExecReload=/bin/kill -HUP $MAINPID
ExecStop=/opt/myapp/bin/graceful-stop.sh

# Restart behavior
Restart=on-failure
RestartSec=5
StartLimitIntervalSec=300
StartLimitBurst=5

# Timeouts
TimeoutStartSec=30
TimeoutStopSec=30
WatchdogSec=60

# Security hardening
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
ReadWritePaths=/var/lib/myapp /var/log/myapp
CapabilityBoundingSet=
AmbientCapabilities=

# Logging
StandardOutput=journal
StandardError=journal
SyslogIdentifier=myapp

[Install]
WantedBy=multi-user.target
```

## Service Management Commands

```bash
# Reload systemd after creating or modifying unit files
systemctl daemon-reload

# Start, stop, restart a service
systemctl start myapp
systemctl stop myapp
systemctl restart myapp

# Reload service configuration without restart (if supported)
systemctl reload myapp

# Enable service to start on boot
systemctl enable myapp

# Enable and start in one command
systemctl enable --now myapp

# Disable and stop
systemctl disable --now myapp

# Check service status
systemctl status myapp

# Check if a service is active, enabled, or failed
systemctl is-active myapp
systemctl is-enabled myapp
systemctl is-failed myapp

# List all running services
systemctl list-units --type=service --state=running

# List all failed services
systemctl list-units --type=service --state=failed

# Show all properties of a service
systemctl show myapp

# Show specific property values
systemctl show myapp -p MainPID,MemoryCurrent,CPUUsageNSec

# Mask a service (prevent it from being started at all)
systemctl mask myapp

# Unmask
systemctl unmask myapp

# Reset a failed service state
systemctl reset-failed myapp
```

## Timer Units (Cron Replacement)

### Timer File

```ini
# /etc/systemd/system/backup.timer
[Unit]
Description=Daily backup timer

[Timer]
# Run daily at 2:30 AM
OnCalendar=*-*-* 02:30:00
# If the system was off at the scheduled time, run when it boots
Persistent=true
# Add random delay up to 15 minutes to avoid thundering herd
RandomizedDelaySec=900
# Associate with a specific service (defaults to same name .service)
Unit=backup.service

[Install]
WantedBy=timers.target
```

### Corresponding Service File

```ini
# /etc/systemd/system/backup.service
[Unit]
Description=Daily backup job
After=network-online.target
Wants=network-online.target

[Service]
Type=oneshot
User=backup
ExecStart=/usr/local/bin/run-backup.sh
StandardOutput=journal
StandardError=journal
```

### Timer Management

```bash
# Common OnCalendar expressions:
# minutely, hourly, daily, weekly, monthly
# *-*-* 06:00:00       Daily at 6 AM
# Mon..Fri *-*-* 09:00 Weekdays at 9 AM
# *:0/15               Every 15 minutes

# Validate calendar expressions
systemd-analyze calendar "Mon..Fri *-*-* 09:00"

# List all active timers
systemctl list-timers --all

# Enable and start a timer
systemctl enable --now backup.timer

# Run the associated service immediately (for testing)
systemctl start backup.service
```

## Socket Activation

```ini
# /etc/systemd/system/myapp.socket
[Unit]
Description=MyApp Socket

[Socket]
ListenStream=8080
Accept=no
# Optionally bind to a specific IP
# ListenStream=10.0.1.10:8080

[Install]
WantedBy=sockets.target
```

```ini
# /etc/systemd/system/myapp.service
[Unit]
Description=MyApp Server
Requires=myapp.socket

[Service]
Type=notify
User=myapp
ExecStart=/opt/myapp/bin/server
# Service receives the socket file descriptor from systemd

[Install]
WantedBy=multi-user.target
```

```bash
# Enable the socket (service starts on first connection)
systemctl enable --now myapp.socket

# Check socket status
systemctl status myapp.socket

# List all listening sockets
systemctl list-sockets
```

## Dependency Management

```bash
# Key [Unit] directives for ordering and dependencies:
# After=            Start after these units (ordering only)
# Requires=         Hard dependency -- fail if this unit cannot start
# Wants=            Soft dependency -- try to start, don't fail if unavailable
# PartOf=           Stop this unit when the parent stops
# Conflicts=        Cannot run alongside this unit

# Visualize the dependency tree for a service
systemctl list-dependencies myapp

# Show reverse dependencies (who depends on this unit)
systemctl list-dependencies myapp --reverse

# Analyze boot order for a service
systemd-analyze critical-chain myapp.service
```

## Resource Limits (cgroups v2)

```ini
# /etc/systemd/system/myapp.service.d/limits.conf
# (drop-in override file)
[Service]
# Memory limits
MemoryMax=1G
MemoryHigh=768M

# CPU limits
CPUQuota=200%          # Up to 2 full CPU cores
CPUWeight=100          # Relative weight (default=100)

# I/O limits
IOWeight=50
IOReadBandwidthMax=/dev/sda 100M
IOWriteBandwidthMax=/dev/sda 50M

# Process limits
LimitNOFILE=65535
LimitNPROC=4096
TasksMax=512

# Disable OOM killer (let the app handle it)
OOMPolicy=continue
```

```bash
# Apply drop-in overrides without editing the main unit file
mkdir -p /etc/systemd/system/myapp.service.d/

cat <<'EOF' > /etc/systemd/system/myapp.service.d/limits.conf
[Service]
MemoryMax=1G
CPUQuota=200%
EOF

systemctl daemon-reload
systemctl restart myapp

# View current resource usage for a service
systemctl status myapp                  # Shows Memory and CPU
systemd-cgtop                          # Real-time cgroup resource usage

# Edit a service's overrides interactively
systemctl edit myapp
# This creates a drop-in file automatically
```

## Journalctl Log Analysis

```bash
# Follow logs for a service in real time
journalctl -u myapp -f

# Show logs since last boot
journalctl -u myapp -b

# Show logs for a specific time range
journalctl -u myapp --since "2025-01-15 08:00" --until "2025-01-15 12:00"

# Show only error and above
journalctl -u myapp -p err

# Show the last 100 lines with full messages (no truncation)
journalctl -u myapp -n 100 --no-pager -l

# Show logs in JSON format (for parsing)
journalctl -u myapp -o json-pretty --no-pager | head -50

# Check journal disk usage and vacuum old entries
journalctl --disk-usage
journalctl --rotate
journalctl --vacuum-time=7d
journalctl --vacuum-size=500M
```

## Troubleshooting

| Symptom | Diagnostic Command | Common Fix |
|---|---|---|
| Service fails to start | `systemctl status myapp`, `journalctl -u myapp -n 50` | Check ExecStart path, permissions, config syntax |
| Service keeps restarting | `journalctl -u myapp --since "5 min ago"` | Check StartLimitBurst; look for crash in logs |
| "Main process exited, code=exited, status=217" | `journalctl -u myapp` | User or group in unit file does not exist |
| "Failed to set up mount namespacing" | Check ProtectSystem/PrivateTmp | Kernel too old or SELinux blocking; relax directives |
| Timer not firing | `systemctl list-timers`, `systemctl status backup.timer` | Ensure timer is enabled; validate OnCalendar expression |
| Service starts before dependency | Check After= and Requires= | Add `After=dependency.service` for ordering |
| OOM killed | `journalctl -k \| grep oom`, `dmesg` | Increase MemoryMax or optimize application memory |
| Cannot bind to port 80 | Check AmbientCapabilities | Add `CAP_NET_BIND_SERVICE` or use a higher port |

## Related Skills

- `linux-administration` -- General system administration context
- `performance-tuning` -- Kernel tuning and resource optimization
- `user-management` -- Service accounts and permissions
- `backup-recovery` -- Scheduling backups with systemd timers

© devops-skills · MIT · BagelHole/DevOps-Security-Agent-Skills

Similar skills

Everything for DevOps and infrastructure →

From the same set127

linux-administration A skill for Linux server work: packages, services, disks, processes, cron and logs. Useful when the agent needs to run commands on a server, not just write code. CX Codex +1 770installs linux-hardening A skill that walks your agent through CIS benchmarks: SSH config, user policy, firewall rules and kernel parameters. Useful when a server heads to production or an audit. CX Codex +1 769installs docker-management Instructions for building multi-stage Dockerfiles, managing container networks, and troubleshooting failed processes. Useful for container deployment and debugging. CX Codex +1 508installs reverse-proxy Configures nginx and Traefik as reverse proxies for TLS termination, path routing, and rate limiting. CX Codex +1 473installs firewall-config A skill that writes and reviews firewall rules: iptables, nftables, UFW and AWS security groups. Useful when you lock down a server perimeter or split a network into zones. CX Codex +1 458installs ssh-configuration Configures OpenSSH clients and servers, handles Ed25519 keys, port forwarding, and bastion jumps for secure Linux server access. CX Codex +1 451installs prometheus-grafana This skill gives your agent templates for Prometheus scraping, PromQL queries and Grafana panels. Handy when a project needs monitoring added. CX Codex +1 449installs windows-server A skill for Windows Server administration: roles and features, IIS sites, Active Directory users, updates. Useful when the agent touches Windows infrastructure. CX Codex +1 449installs

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor