runit Linux: Complete Guide to Unix Init Scheme with Service Supervision

runit is a lightweight, cross-platform Unix init scheme with service supervision that provides a reliable alternative to traditional init systems. Developed by Gerrit Pape, runit provides a simple yet powerful approach to process supervision and system initialization, making it an excellent choice for embedded systems, containers, and servers requiring robust service management.

What is runit?

runit is a Unix init scheme that replaces the traditional SysV init system with a more reliable and simpler approach. It consists of three main phases and provides automatic service supervision, which means it constantly monitors running services and automatically restarts them if they fail. This makes Runit especially valuable for mission-critical applications where uptime is essential.

The system is specifically designed based on the philosophy of “do one thing and do it well”, focusing on process supervision and service management. Unlike systemd or other complex init systems, runit maintains simplicity while providing robust functionality.

Key Features of Runit

  • Automated Service Supervision: Continuously monitors services and restarts failed processes
  • Simple configuration: Uses plain shell scripts for service definitions
  • Fast boot time: Parallel service startup reduces boot time
  • Reliable Logging: Built-in logging mechanism with svlogd
  • Cross-platform: Works on Linux, BSD and other Unix-like systems
  • Small Footprint: Minimal resource usage and dependencies

runit architecture

Runit operates through three distinct phases:

Step 1: System Initialization

This phase handles one-time system initialization tasks such as mounting the file system, configuring network interfaces, and setting up the basic system environment. This is equivalent to the traditional /etc/rc.sysinit script.

Step 2: Service Supervision

The core of runit, this step starts the runswiddir program that monitors all services. It continuously monitors service directories and automatically starts, stops, and restarts services as needed.

Stage 3: System Shutdown

Handles graceful system shutdowns, including stopping all supervised services, unmounting file systems, and performing cleanup tasks.

install runit

Runit installation varies depending on your Linux distribution:

Ubuntu/Debian:

sudo apt-get update
sudo apt-get install runit

CentOS/RHEL:

sudo yum install runit
# or for newer versions
sudo dnf install runit

Arch Linux:

sudo pacman -S runit

From Source:

wget http://smarden.org/runit/runit-2.1.2.tar.gz
tar xzf runit-2.1.2.tar.gz
cd runit-2.1.2
package/install

Basic runit commands

Runit provides several essential commands for service management:

SV – Service Control

sv The primary tool for controlling command services is:

# Start a service
sv start service_name

# Stop a service
sv stop service_name

# Restart a service
sv restart service_name

# Check service status
sv status service_name

# Get service uptime
sv up service_name

Example output:

$ sv status nginx
run: nginx: (pid 1234) 3600s
$ sv status down_service
down: down_service: 0s, normally up

runvdir – service directory monitor

Monitors service directories and starts runv for each service:

runsvdir /etc/service

Runv – Single Service Supervisor

Supervises personal services:

runsv /etc/service/nginx

Creating Runit Services

Creating services in runit involves setting up a services directory with an executable run script:

basic service structure

/etc/sv/myservice/
├── run          # Main service script (required)
├── finish       # Cleanup script (optional)
├── down         # Prevents auto-start (optional)
└── log/         # Logging service (optional)
    └── run      # Log service script

Creating a Simple Web Server Service

Let’s create a service for a simple Python HTTP server:

# Create service directory
sudo mkdir -p /etc/sv/webserver

# Create the run script
sudo tee /etc/sv/webserver/run << 'EOF'
#!/bin/sh
exec 2>&1
cd /var/www/html
exec python3 -m http.server 8080
EOF

# Make it executable
sudo chmod +x /etc/sv/webserver/run

# Enable the service
sudo ln -s /etc/sv/webserver /etc/service/

service with logging

# Create log directory
sudo mkdir -p /etc/sv/webserver/log

# Create log run script
sudo tee /etc/sv/webserver/log/run << 'EOF'
#!/bin/sh
exec svlogd -tt /var/log/webserver
EOF

# Make it executable
sudo chmod +x /etc/sv/webserver/log/run

# Create log directory
sudo mkdir -p /var/log/webserver

Advanced Service Configuration

service with environment variables

# Create environment directory
sudo mkdir -p /etc/sv/myapp/env

# Set environment variables
echo "production" | sudo tee /etc/sv/myapp/env/NODE_ENV
echo "3000" | sudo tee /etc/sv/myapp/env/PORT

# Updated run script
sudo tee /etc/sv/myapp/run << 'EOF'
#!/bin/sh
exec 2>&1
exec chpst -e ./env -u appuser node /opt/myapp/server.js
EOF

Service with user privileges

sudo tee /etc/sv/database/run << 'EOF'
#!/bin/sh
exec 2>&1
exec chpst -u postgres:postgres /usr/bin/postgres -D /var/lib/postgresql/data
EOF

service management example

Service status monitoring

# Check all services
sudo sv status /etc/service/*

# Example output:
run: apache2: (pid 1456) 7200s
run: nginx: (pid 1234) 3600s
down: mysql: 120s, normally up
run: ssh: (pid 892) 86400s

interactive service control

# Start multiple services
for service in nginx mysql redis; do
    sv start $service
    echo "Started $service"
done

# Monitor service startup
watch 'sv status /etc/service/*'

Logging with Svlogd

Runit includes svlogd, a powerful logging daemon that provides automatic log rotation and filtering:

Basic logging configuration

# Log configuration file
sudo tee /var/log/myservice/config << 'EOF'
s1000000  # Maximum log file size (1MB)
n10       # Keep 10 log files
t         # Add timestamps
EOF

log filtering

# Filter logs by pattern
sudo tee /var/log/myservice/config << 'EOF'
+*error*     # Include lines containing 'error'
-*debug*     # Exclude lines containing 'debug'
s10000000    # 10MB log files
n5           # Keep 5 files
EOF

Troubleshooting Runit Services

Common Issues and Solutions

service will not start

# Check if run script is executable
ls -la /etc/sv/myservice/run

# Check for syntax errors
sh -n /etc/sv/myservice/run

# Check service logs
sudo tail -f /var/log/myservice/current

Service keeps restarting

# Check service status with details
sv status /etc/service/myservice

# Monitor service restarts
while true; do
    sv status /etc/service/myservice
    sleep 1
done

debugging service script

# Add debug output to run script
#!/bin/sh
exec 2>&1
echo "Starting service at $(date)"
echo "Environment: $(env)"
echo "User: $(whoami)"
exec /path/to/program

Performance and Resource Management

resource limitations

# Limit memory usage
sudo tee /etc/sv/myapp/run << 'EOF'
#!/bin/sh
exec 2>&1
exec chpst -m 100000000 -u appuser /opt/myapp/bin/myapp
EOF

cpu limits

# Nice priority adjustment
exec chpst -n 10 -u appuser /opt/myapp/bin/myapp

Migration from other init systems

from systemd

Converting systemd service to runit:

# systemd service file
[Unit]
Description=My Web App
After=network.target

[Service]
Type=simple
User=webuser
WorkingDirectory=/opt/webapp
ExecStart=/opt/webapp/bin/server
Restart=always

[Install]
WantedBy=multi-user.target

Equivalent Runit Service:

# /etc/sv/webapp/run
#!/bin/sh
exec 2>&1
cd /opt/webapp
exec chpst -u webuser /opt/webapp/bin/server

best practices

service design principles

  • Keep the run script simple: Avoid complex logic in run script
  • Use execution: Replace shell process with your program
  • redirect stderr: Use exec 2>&1 To combine output streams
  • Avoid condemnation: Run the program in foreground mode
  • Set working directory: Use cd before executing the program

security considerations

# Run service as non-root user
exec chpst -u serviceuser:servicegroup /path/to/program

# Set environment cleanly
exec chpst -e ./env -u serviceuser /path/to/program

# Limit resources
exec chpst -m 100000000 -o 1000 -u serviceuser /path/to/program

monitoring and warning

service health checkup

#!/bin/bash
# health_check.sh
for service in $(ls /etc/service/); do
    status=$(sv status "/etc/service/$service" 2>/dev/null)
    if [[ $status == down* ]]; then
        echo "ALERT: $service is down"
        # Send notification
    fi
done

automatic service recovery

# /etc/sv/myservice/finish
#!/bin/sh
# Cleanup script that runs when service exits
echo "Service $1 exited with code $2 at $(date)" >> /var/log/myservice/finish.log

# Conditional restart logic
if [ "$2" -eq "100" ]; then
    # Exit code 100 means don't restart
    touch ./down
fi

conclusion

Runit provides a robust, lightweight alternative to complex init systems while maintaining simplicity and reliability. Its service supervision capabilities, coupled with straightforward configuration and excellent performance characteristics, make it an excellent choice for a variety of deployment scenarios.

The system’s philosophy of simplicity does not compromise functionality – from basic service management to advanced logging and resource control, Runit provides all the tools needed for effective system administration. Whether you’re managing a single server or a complex distributed system, Runit’s reliable service supervision ensures that your applications remain available and functional.

By following the practices and examples outlined in this guide, you will be well-equipped to implement Runit into your infrastructure and take advantage of its powerful service supervision capabilities. Its lightweight nature and cross-platform compatibility make it particularly valuable for modern containerized environments and embedded systems where resource efficiency is important.



Leave a Comment