A socket activation proxy written in Rust that starts and stops systemd services on demand.
I have a bunch of home-grown tools and web apps that I vibe-coded for personal use. Most of them sit idle 99% of the time, but still consume RAM if left running. This tool is part of my vibe-slop management system - it keeps services dormant until actually needed, then spins them up on first request and shuts them down after a period of inactivity.
- Socket Activation: Compatible with systemd socket activation (receives file descriptors)
- Automatic Service Management: Starts/stops systemd units on demand via D-Bus
- Health Checking: HTTP health checks with configurable retries and timeouts
- Metrics Collection: Prometheus-compatible metrics endpoint
- Multiple Protocols: TCP, UDP, and Unix socket support
- Inactivity Timeout: Automatically stops services after period of inactivity
- Graceful Shutdown: Handles SIGTERM/SIGINT with proper cleanup
- Configuration: YAML-based configuration with CLI overrides
cargo install sockretaryOr from source:
git clone https://github.com/volh/sockretary
cd sockretary
cargo install --path .-
Generate an example configuration:
sockretary --generate-config > myapp.yaml -
Edit the configuration for your service:
proxy: mode: tcp backend_address: "127.0.0.1:8080" max_connections: 100 service: unit: "myapp.service" startup_timeout: 30s timeouts: inactivity: 5m
-
Create systemd units:
# /etc/systemd/system/myapp-proxy.socket [Unit] Description=MyApp Proxy Socket [Socket] ListenStream=127.0.0.1:3000 Accept=no [Install] WantedBy=sockets.target
# /etc/systemd/system/myapp-proxy.service [Unit] Description=MyApp Proxy Requires=myapp-proxy.socket [Service] Type=simple ExecStart=/usr/local/bin/sockretary -c /etc/sockretary/myapp.yaml User=myuser Group=myuser [Install] WantedBy=multi-user.target
-
Enable and start:
sudo systemctl enable myapp-proxy.socket sudo systemctl start myapp-proxy.socket
proxy:
mode: tcp # tcp, udp, unix
backend_address: "127.0.0.1:8080"
max_connections: 100
buffer_size: 8192
service:
unit: "myapp.service"
startup_timeout: 30s
graceful_shutdown: true
timeouts:
inactivity: 5m # Stop service after inactivity
connection: 30s # Connection timeout
read: 30s # Read timeout
write: 30s # Write timeout
health_check:
path: "/health" # Health check endpoint
timeout: 5s # Per-request timeout
interval: 10s # Check interval
retries: 3 # Retries before marking unhealthy
expected_status: 200 # Expected HTTP status
metrics:
port: 9090 # Prometheus metrics port
bind: "127.0.0.1" # Bind address
logging:
level: "info" # trace, debug, info, warn, error
format: "pretty" # pretty, jsonsockretary [OPTIONS]
OPTIONS:
-c, --config <FILE> Configuration file path
-u, --unit <UNIT> systemd unit to manage (overrides config)
-b, --backend <ADDRESS> Backend address (overrides config)
-t, --timeout <DURATION> Inactivity timeout (overrides config)
-v, --log-level <LEVEL> Log level [default: info]
--generate-config Generate example configuration and exit
-h, --help Print help
-V, --version Print versionInternet/Network
↓
systemd socket
↓
sockretary ←--→ systemd (start/stop service via D-Bus)
↓
Backend Service
- Socket Inheritance: Receives pre-bound socket from systemd via file descriptor (fd 3)
- Service Management: Communicates with systemd via D-Bus to start/stop units
- Proxy Traffic: Forwards connections between clients and backend service
- Activity Monitoring: Tracks connection activity and data transfer
- Health Monitoring: Performs periodic HTTP health checks on backend (if configured)
- Automatic Shutdown: Stops service after configured inactivity period
When metrics are enabled, the following metrics are available at /metrics:
sockretary_connections_total- Total connections handledsockretary_connections_active- Currently active connectionssockretary_connection_duration_seconds- Connection duration histogramsockretary_bytes_total- Total bytes transferredsockretary_service_starts_total- Service start countsockretary_service_stops_total- Service stop countsockretary_service_uptime_seconds- Service uptimesockretary_health_checks_total- Health check count by statussockretary_backend_healthy- Backend health status (1=healthy, 0=unhealthy)sockretary_errors_total- Error count by type
Basic health check available at /health on the metrics port.
-
"LISTEN_PID not set": Not running under systemd socket activation
- Test with:
systemd-socket-activate -l 127.0.0.1:3000 sockretary
- Test with:
-
D-Bus connection failed: Missing systemd or wrong permissions
- Ensure running on systemd-based system
- Check user has access to system D-Bus
-
Backend connection failed: Service not ready or wrong address
- Check backend service is running
- Verify backend_address in configuration
- Enable health checking to wait for readiness
-
Permission denied on socket: SELinux or file permissions
- Check SELinux context:
ls -Z /path/to/socket - Ensure proper user/group in systemd service unit
- Check SELinux context:
Test socket activation manually:
# Terminal 1: Start proxy with systemd-socket-activate
systemd-socket-activate -l 127.0.0.1:3000 sockretary \
--unit test.service \
--backend 127.0.0.1:8080 \
--timeout 30s
# Terminal 2: Test connection
curl http://127.0.0.1:3000/- Run as non-root user with minimal permissions
- Use systemd security features:
[Service] DynamicUser=yes ProtectSystem=strict ProtectHome=yes PrivateTmp=yes NoNewPrivileges=yes
- Bind metrics to localhost only unless needed externally
- Use firewall rules to restrict access to proxy ports
MIT - see LICENSE file.
- cherti/socket-activate - Go implementation that inspired this
- systemd socket activation docs