- Trading skills (OKX, dividend, lottery, quantitative) - Creative skills (ASCII art, diagrams, video) - Development skills (GitHub, debugging, TDD) - Research skills (arXiv, blog monitoring) - Productivity skills (email, documents, notes) - MCP integration skills - Custom user skills
7.6 KiB
name, description, tags
| name | description | tags | |||||
|---|---|---|---|---|---|---|---|
| startup-service-manager | Generic Linux service manager script — start/stop/restart/status any service via simple .sh definitions. No systemd required. |
|
Startup - Generic Service Manager
A lightweight bash-based service manager at ~/startup/. Manages any process (mihomo, yacd, custom apps) via simple .sh definition files. No systemd, no Docker dependency.
When to Use
- User wants to manage multiple background services from one place
- Services don't have their own systemd units
- Quick prototyping before committing to systemd
- User explicitly asks for a startup/service management script
Architecture
~/startup/
├── startup.sh # Main script
├── startup # Symlink/wrapper for convenience
├── services/ # One .sh per service (the registry)
│ ├── mihomo.sh
│ └── yacd.sh
├── pids/ # Auto-managed PID files
└── logs/ # Per-service stdout/stderr logs
Commands
bash ~/startup/startup.sh status # Show all services (running/stopped + PID)
bash ~/startup/startup.sh list # List all registered services (name + port + desc)
bash ~/startup/startup.sh start # Start all
bash ~/startup/startup.sh stop # Stop all
bash ~/startup/startup.sh restart mihomo # Restart one
bash ~/startup/startup.sh log mihomo # View logs
bash ~/startup/startup.sh register nginx # Create template
bash ~/startup/startup.sh remove nginx # Delete service
bash ~/startup/startup.sh help # Show help
status vs list: status shows runtime state (PID, running/stopped), list shows a clean registry view (name, port, description).
If alias is set (alias startup="bash ~/startup/startup.sh"), just type startup status.
Service Definition Format
Each service is a .sh file in ~/startup/services/. Example (mihomo.sh):
SVC_DESC="Clash/Mihomo 代理引擎"
SVC_PORT="7890 (代理) / 9090 (API)"
SVC_PID_PATTERN="mihomo -d"
SVC_START="cd ~/clash && exec ./mihomo -d config"
SVC_HEALTH="curl -s http://127.0.0.1:9090/version"
Required: SVC_START — the command to launch the service (must background itself or use exec with the script's &).
Optional:
| Variable | Purpose |
|---|---|
SVC_DESC |
Human-readable description (shown in status) |
SVC_PORT |
Port info string (display only) |
SVC_PID_PATTERN |
pkill -f pattern for cleanup of stale processes |
SVC_HEALTH |
Command that exits 0 when service is ready (used for startup wait) |
SVC_STOP |
Custom stop command (before SIGTERM) |
Registering a New Service
# Method 1: Use register command (creates template)
bash ~/startup/startup.sh register myapp
# Then edit ~/startup/services/myapp.sh
# Method 2: Write directly
cat > ~/startup/services/myapp.sh << 'EOF'
SVC_DESC="My Application"
SVC_PORT="8080"
SVC_PID_PATTERN="myapp"
SVC_START="cd ~/myapp && exec node server.js"
SVC_HEALTH="curl -s http://127.0.0.1:8080/health"
EOF
Quick-Start Service Definitions
Ready-to-use definitions for common services: skill_view(name="startup-service-manager", file_path="references/common-services.md")
Auto-Start with systemd
To make startup services auto-start on boot, create a systemd unit:
cat > /tmp/startup-services.service << 'EOF'
[Unit]
Description=Startup Services (mihomo, yacd, hermes-dashboard)
After=network.target
[Service]
Type=oneshot
RemainAfterExit=yes
User=openclaw
ExecStart=/home/openclaw/startup/startup.sh start all
ExecStop=/home/openclaw/startup/startup.sh stop all
[Install]
WantedBy=multi-user.target
EOF
sudo cp /tmp/startup-services.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable startup-services.service
Important: startup.sh must have execute permission: chmod +x ~/startup/startup.sh
Pitfalls
- PID file stale after crash: If a service crashes without cleanup, the PID file remains. The script checks
kill -0so it detects dead PIDs, butstartwill refuse. Fix:rm ~/startup/pids/<name>.pidthen start again, or juststartup restart <name>which stops (cleans up) then starts. - systemd permission denied: If systemd fails with "Permission denied" when executing startup.sh, run
chmod +x ~/startup/startup.sh. The script needs execute permission for systemd to run it. - Multiple processes on same pattern:
SVC_PID_PATTERNis used withpkill -f, which kills ALL matching processes. If the pattern is too broad (e.g., justpython), it will kill unrelated processes. Use specific patterns likehttp.server 9091. - Health check timeout: Default wait is 10 seconds. If your service takes longer to start, the script still succeeds (PID is alive) but logs "启动成功" before health check passes. For slow-starting services, increase the loop or accept the delay.
- Log rotation: Logs append (
>>), never rotate. For long-running production, either add logrotate or periodically truncate:> ~/startup/logs/mihomo.log. - startup.sh vs systemd: Don't use both for the same service — they'll fight over PIDs. Pick one management system per service.
- ⚠️ CRITICAL: systemd cgroup kills child processes on exit: If
startup.sh restart <service>is called from inside a systemd oneshot service (e.g., a watchdog timer), the spawned process inherits the service's cgroup. When the oneshot service exits, systemd kills all processes in the cgroup — including the just-started service. This creates a death loop: watchdog starts service → watchdog exits → systemd kills service → next watchdog cycle finds service dead → repeat. Fix: Services managed by a systemd-timer watchdog MUST run as their own dedicated systemd service. The watchdog should callsystemctl --user restart <service>instead ofstartup.sh restart <service>. Seeskill_view(name="clash-docker-workflow", file_path="references/mihomo-watchdog.md")for the full diagnosis and fix. - Alias not available in new terminals: After adding
alias startup=...to.bashrc, existing terminals needsource ~/.bashrc. New terminals get it automatically. - Tracking existing processes: When a service was started outside startup.sh (manually, or by another system), the PID file won't exist. The script will show "已停止" even though the process is running. Fix:
echo $(pgrep -f "pattern") > ~/startup/pids/<name>.pid. Or restart through startup.sh to take over management. - Duplicate instances: If you manually start a service that's already running via startup.sh, you get two processes competing for the same port. Always check
startup statusbefore starting. Thestopcommand uses both PID file ANDpkill -f SVC_PID_PATTERNto catch stragglers. - SVC_HEALTH with curl -w format: In
evalcontext,curl -w '%{http_code}'can misbehave because%and{}are interpreted by the shell. Use double quotes inside:curl -s ... -o /dev/null -w '"'"'%{http_code}'"'"'or test with a simpler check likess -tlnp | grep -q PORT. - Alias in .bashrc: When adding
alias startup=...to.bashrc, the linegrep -q || echo >> ~/.bashrcpattern needs the user's approval for writing to .bashrc. Usewrite_fileor ask user consent. - Health watchdog vs service manager: startup.sh manages start/stop lifecycle but doesn't monitor ongoing health. For services that need continuous health monitoring (e.g., mihomo proxy whose crash cascades to Telegram adapter), use a watchdog pattern — see
skill_view(name="clash-docker-workflow", file_path="references/mihomo-watchdog.md").