Skill: jgm2025/linux-patcher (version 3.0.2)

--- name: linux-patcher description: Automated Linux server patching and Docker container updates. Use when the user asks to update, patch, or upgrade Linux servers, apply security updates, update Docker containers, check for system updates, or manage server maintenance across multiple hosts. Supports Ubuntu, Debian, RHEL, AlmaLinux, Rocky Linux, CentOS, Amazon Linux, and SUSE. Includes PatchMon integration for automatic host detection and intelligent Docker handling. --- # Linux Patcher Automate Linux server patching and Docker container updates across multiple hosts via SSH. ## ⚠️ Important Disclaimers ### Distribution Support Status **Fully Tested:** - ✅ **Ubuntu** - Tested end-to-end with real infrastructure **Supported but Untested:** - ⚠️ **Debian GNU/Linux** - Commands based on official documentation - ⚠️ **Amazon Linux** - Supports both AL2 (yum) and AL2023 (dnf) - ⚠️ **RHEL (Red Hat Enterprise Linux)** - Supports RHEL 7 (yum) and 8+ (dnf) - ⚠️ **AlmaLinux** - RHEL-compatible, uses dnf - ⚠️ **Rocky Linux** - RHEL-compatible, uses dnf - ⚠️ **CentOS** - Supports CentOS 7 (yum) and 8+ (dnf) - ⚠️ **SUSE/OpenSUSE** - Uses zypper package manager **Testing Recommendation:** Always test untested distributions in a non-production environment first. The script will warn you when running on untested distributions. ### Security Notice This skill requires: - **Passwordless sudo access** - Configured with restricted permissions - **SSH key authentication** - No passwords stored or transmitted - **PatchMon credentials** - Stored securely in user's home directory **Read `SETUP.md` for complete security configuration guide.** ## Quick Start ### Automated (Recommended) **Patch all hosts from PatchMon** (automatic detection): ```bash scripts/patch-auto.sh ``` **Skip Docker updates** (packages only): ```bash scripts/patch-auto.sh --skip-docker ``` **Preview changes** (dry-run): ```bash scripts/patch-auto.sh --dry-run ``` ### Manual (Alternative) **Single host - packages only**: ```bash scripts/patch-host-only.sh user@hostname ``` **Single host - full update**: ```bash scripts/patch-host-full.sh user@hostname /path/to/docker/compose ``` **Multiple hosts from config**: ```bash scripts/patch-multiple.sh config-file.conf ``` ## Features - **PatchMon integration** - Automatically detects hosts needing updates - **Smart Docker detection** - Auto-detects Docker and Compose paths - **Selective updates** - Skip Docker updates with `--skip-docker` flag - **Passwordless sudo required** - Configure with `visudo` or `/etc/sudoers.d/` files - **SSH key authentication** - No password prompts - **Parallel execution** - Update multiple hosts simultaneously - **Dry-run mode** - Preview changes without applying - **Manual override** - Run updates on specific hosts without PatchMon ## Configuration ### Option 1: Automatic via PatchMon (Recommended) Configure PatchMon credentials for automatic host detection: ```bash cp scripts/patchmon-credentials.example.conf ~/.patchmon-credentials.conf nano ~/.patchmon-credentials.conf ``` Set your credentials: ```bash PATCHMON_URL=https://patchmon.example.com PATCHMON_USERNAME=your-username PATCHMON_PASSWORD=your-password ``` Then simply run: ```bash scripts/patch-auto.sh ``` The script will: 1. Query PatchMon for hosts needing updates 2. Auto-detect Docker on each host 3. Apply appropriate updates (host-only or full) ### Option 2: Single Host (Quick Manual) Run scripts directly with command-line arguments (no config file needed). ### Option 3: Multiple Hosts (Manual Config) Create a config file based on `scripts/patch-hosts-config.example.sh`: ```bash cp scripts/patch-hosts-config.example.sh my-servers.conf nano my-servers.conf ``` Example config: ```bash # Host definitions: hostname,ssh_user,docker_path HOSTS=( "webserver.example.com,ubuntu,/opt/docker" "database.example.com,root,/home/admin/compose" "monitor.example.com,docker,/srv/monitoring" ) # Update mode: "host-only" or "full" UPDATE_MODE="full" # Dry run mode (set to "false" to apply changes) DRY_RUN="true" ``` Then run: ```bash scripts/patch-multiple.sh my-servers.conf ``` ## Prerequisites ### Required on Control Machine (where OpenClaw runs) - [ ] **OpenClaw** installed and running - [ ] **SSH client** installed (`ssh` command available) - [ ] **Bash** 4.0 or higher - [ ] **curl** installed (for PatchMon API) - [ ] **jq** installed (for JSON parsing) - [ ] **PatchMon** installed (required to check which hosts need updating) - Does NOT need to be on the OpenClaw host - Can be installed on any server accessible via HTTPS - Download: https://github.com/PatchMon/PatchMon **Install missing tools:** ```bash # Ubuntu/Debian sudo apt install curl jq # RHEL/CentOS/Rocky/Alma sudo dnf install curl jq # macOS brew install curl jq ``` ### Required on Target Hosts - [ ] **SSH server** running and accessible - [ ] **SSH key authentication** configured (passwordless login) - [ ] **Passwordless sudo** configured for patching commands (see SETUP.md) - [ ] **Docker** installed (optional, only for full updates) - [ ] **Docker Compose** installed (optional, only for full updates) - [ ] **PatchMon agent** installed and reporting (optional but recommended) ### PatchMon Setup (Required for Automatic Mode) **PatchMon is required to automatically detect which hosts need patching.** **Important:** PatchMon does NOT need to be installed on the same server as OpenClaw. Install PatchMon on a separate server (can be any server on your network), and OpenClaw will query it via API. **Download PatchMon:** - **GitHub:** https://github.com/PatchMon/PatchMon - **Documentation:** https://docs.patchmon.net **What you need:** - [ ] PatchMon server installed on ANY accessible server (not necessarily the OpenClaw host) - [ ] PatchMon agents installed on all target hosts you want to patch - [ ] PatchMon API credentials (username/password) - [ ] Network connectivity from OpenClaw host to PatchMon server (HTTPS) **Architecture:** ``` ┌─────────────────┐ HTTPS API ┌─────────────────┐ │ OpenClaw Host │ ──────────────────> │ PatchMon Server │ │ (this machine) │ Query updates │ (separate host) │ └─────────────────┘ └─────────────────┘ │ │ Reports ▼ ┌─────────────────┐ │ Target Hosts │ │ (with agents) │ └─────────────────┘ ``` **Quick Start:** 1. Install PatchMon server on a separate server (see GitHub repo) 2. Install PatchMon agents on all hosts you want to patch 3. Configure OpenClaw to access PatchMon API: ```bash cp scripts/patchmon-credentials.example.conf ~/.patchmon-credentials.conf nano ~/.patchmon-credentials.conf # Set PatchMon server URL chmod 600 ~/.patchmon-credentials.conf ``` **Detailed setup:** See `references/patchmon-setup.md` for complete installation guide. **Can I use this skill without PatchMon?** Yes! You can use manual mode to target specific hosts without PatchMon. However, automatic detection of hosts needing updates requires PatchMon. ### On Target Hosts **Required:** - SSH server running - Passwordless sudo for the SSH user (for `apt` and `docker` commands) - PatchMon agent installed and reporting (for automatic mode) **For full updates:** - Docker and Docker Compose installed - Docker Compose files exist at specified paths ### Configure Passwordless Sudo On each target host, create `/etc/sudoers.d/patches`: ```bash # For Ubuntu/Debian systems username ALL=(ALL) NOPASSWD: /usr/bin/apt, /usr/bin/docker # For RHEL/CentOS systems username ALL=(ALL) NOPASSWD: /usr/bin/yum, /usr/bin/docker, /usr/bin/dnf ``` Replace `username` with your SSH user. Test with `sudo -l` to verify. ## Update Modes ### Host-Only Updates Updates system packages only: - Run `apt update && apt upgrade` (or `yum update` on RHEL) - Remove unused packages (`apt autoremove`) - **Does NOT** touch Docker containers **When to use:** - Hosts without Docker - Security patches only - Minimal downtime required ### Full Updates Complete update cycle: - Update system packages - Clean Docker cache (`docker system prune`) - Pull latest Docker images - Recreate containers with new images - **Causes brief service interruption** **When to use:** - Docker-based infrastructure - Regular maintenance windows - Application updates available ## Workflow ### Automatic Workflow (patch-auto.sh) 1. **Query PatchMon** - Fetch hosts needing updates via API 2. **For each host:** - SSH into host - Check if Docker is installed - Auto-detect Docker Compose path (if not specified) - Apply host-only OR full update based on Docker detection 3. **Report results** - Summary of successful/failed updates ### Host-Only Update Process 1. SSH into target host 2. Run `sudo apt update` 3. Run `sudo apt -y upgrade` 4. Run `sudo apt -y autoremove` 5. Report results ### Full Update Process 1. SSH into target host 2. Run `sudo apt update && upgrade && autoremove` 3. Navigate to Docker Compose directory 4. Run `sudo docker system prune -af` (cleanup) 5. Pull all Docker images listed in compose file 6. Run `sudo docker compose pull` 7. Run `sudo docker compose up -d` (recreate containers) 8. Report results ### Docker Detection Logic When using automatic mode: - **Docker installed + compose file found** → Full update - **Docker installed + no compose file** → Host-only update - **Docker not installed** → Host-only update - **--skip-docker flag set** → Host-only update (ignores Docker) ## Docker Path Auto-Detection When Docker path is not specified, the script checks these locations: 1. `/home/$USER/Docker/docker-compose.yml` 2. `/opt/docker/docker-compose.yml` 3. `/srv/docker/docker-compose.yml` 4. `$HOME/Docker/docker-compose.yml` 5. Current directory **Override auto-detection:** ```bash scripts/patch-host-full.sh user@host /custom/path ``` ## Examples ### Example 1: Automatic update via PatchMon (recommended) ```bash # First time: configure credentials cp scripts/patchmon-credentials.example.conf ~/.patchmon-credentials.conf nano ~/.patchmon-credentials.conf # Run automatic updates scripts/patch-auto.sh ``` ### Example 2: Automatic with dry-run ```bash # Preview what would be updated scripts/patch-auto.sh --dry-run # Review output, then apply scripts/patch-auto.sh ``` ### Example 3: Skip Docker updates ```bash # Update packages only, even if Docker is detected scripts/patch-auto.sh --skip-docker ``` ### Example 4: Manual single host, packages only ```bash scripts/patch-host-only.sh [REDACTED_SECRET] ``` ### Example 5: Manual single host, full update with custom Docker path ```bash scripts/patch-host-full.sh [REDACTED_SECRET] /home/docker/production ``` ### Example 6: Manual multiple hosts from config ```bash scripts/patch-multiple.sh production-servers.conf ``` ### Example 7: Via OpenClaw chat Simply ask OpenClaw: - "Update my servers" - "Patch all hosts that need updates" - "Update packages only, skip Docker" OpenClaw will use the automatic mode and report results. ## Troubleshooting ### PatchMon Integration Issues #### "PatchMon credentials not found" - Create credentials file: `cp scripts/patchmon-credentials.example.conf ~/.patchmon-credentials.conf` - Edit with your PatchMon URL and credentials - Or set `PATCHMON_CONFIG` environment variable to custom location #### "Failed to authenticate with PatchMon" - Verify PatchMon URL is correct (without trailing slash) - Check username and password - Ensure PatchMon server is accessible: `curl -k https://patchmon.example.com/api/health` - Check firewall rules #### "No hosts need updates" but PatchMon shows updates available - Verify PatchMon agents are running on target hosts: `systemctl status patchmon-agent` - Check agent reporting intervals: `/etc/patchmon/config.yml` - Force agent update: `patchmon-agent report` ### System Update Issues #### "Permission denied" on apt/docker commands - Configure passwordless sudo (see Prerequisites section) - Test with: `ssh user@host sudo apt update` #### "Connection refused" - Verify SSH access: `ssh user@host echo OK` - Check SSH keys are configured - Verify hostname resolution #### Docker Compose not found - Specify full path: `scripts/patch-host-full.sh user@host /full/path` - Or install Docker Compose on target host - Auto-detection searches: `/home/user/Docker`, `/opt/docker`, `/srv/docker` #### Containers fail to start after update - Check logs: `ssh user@host "docker logs container-name"` - Manually inspect: `ssh user@host "cd /docker/path && docker compose logs"` - Rollback if needed: `ssh user@host "cd /docker/path && docker compose down && docker compose up -d"` ## PatchMon Integration (Optional) For dashboard monitoring and scheduled patching, see `references/patchmon-setup.md`. PatchMon provides: - Web dashboard for update status - Per-host package tracking - Security update highlighting - Update history ## Security Considerations - **Passwordless sudo** is required for automation - Limit to specific commands (`apt`, `docker` only) - Use `/etc/sudoers.d/` files (easier to manage) - **SSH keys** should be protected - Use passphrase-protected keys when possible - Restrict key permissions: `chmod 600 ~/.ssh/id_rsa` - **Review updates** before applying in production - Use dry-run mode first - Test on staging environment - **Schedule updates** during maintenance windows - Use OpenClaw cron jobs for automation - Coordinate with team for Docker updates (brief downtime) ## Best Practices 1. **Test first** - Run dry-run mode before applying changes 2. **Stagger updates** - Don't update all hosts simultaneously (avoid full outage) 3. **Monitor logs** - Check output for errors after updates 4. **Backup configs** - Keep Docker Compose files in version control 5. **Schedule wisely** - Update during low-traffic windows 6. **Document paths** - Maintain config files for infrastructure 7. **Reboot when needed** - Kernel updates require reboots (not automated) ## Reboot Management The scripts do NOT automatically reboot hosts. After updates: 1. Check if reboot required: `ssh user@host "[ -f /var/run/reboot-required ] && echo YES || echo NO"` 2. Schedule manual reboots during maintenance windows 3. Use PatchMon dashboard to track reboot requirements ## Integration with OpenClaw ### Run Updates on Schedule Create a cron job for automatic nightly patching: ```bash cron add --name "Nightly Server Patching" \ --schedule "0 2 * * *" \ --task "cd ~/.openclaw/workspace/skills/linux-patcher && scripts/patch-auto.sh" ``` Or packages-only mode: ```bash cron add --name "Nightly Package Updates" \ --schedule "0 2 * * *" \ --task "cd ~/.openclaw/workspace/skills/linux-patcher && scripts/patch-auto.sh --skip-docker" ``` ### Run Updates via Chat Simply ask OpenClaw natural language commands: **Full updates (packages + Docker containers):** - "Update my servers" ← **Includes Docker by default** - "Patch all hosts that need updates" - "Update all my infrastructure" **Packages only (exclude Docker):** - "Update my servers, excluding docker" - "Update packages only, skip Docker" - "Patch hosts without touching containers" **Query status:** - "What servers need patching?" - "Show me hosts that need updates" **What happens automatically:** When you say **"Update my servers"**: 1. ✅ Queries PatchMon for hosts needing updates 2. ✅ Detects Docker on each host 3. ✅ Updates system packages 4. ✅ **Pulls Docker images and recreates containers** (if Docker detected) 5. ✅ Reports results with success/failure count When you say **"Update my servers, excluding docker"**: 1. ✅ Queries PatchMon for hosts needing updates 2. ✅ Updates system packages only 3. ❌ Skips all Docker operations (containers keep running) 4. ✅ Reports results **Important:** Docker updates are **included by default** for maximum automation. Use "excluding docker" to skip container updates. ### Manual Override (Specific Hosts) Target individual hosts without querying PatchMon: - "Update webserver.example.com" - "Patch database.example.com packages only" - "Update app.example.com with Docker" OpenClaw will use the manual scripts for targeted updates. ## Documentation Files This skill includes comprehensive documentation: - **SKILL.md** (this file) - Overview and usage guide - **SETUP.md** - Complete setup instructions with security best practices - **WORKFLOWS.md** - Visual workflow diagrams for all modes - **references/patchmon-setup.md** - PatchMon installation and integration **First time setup?** Read `SETUP.md` first - it provides step-by-step instructions for secure configuration. **Want to understand the flow?** Check `WORKFLOWS.md` for visual diagrams of how the skill operates. ## Supported Linux Distributions | Distribution | Package Manager | Tested | Status | |--------------|-----------------|--------|--------| | Ubuntu | apt | ✅ Yes | Fully supported | | Debian | apt | ⚠️ No | Supported (untested) | | Amazon Linux 2 | yum | ⚠️ No | Supported (untested) | | Amazon Linux 2023 | dnf | ⚠️ No | Supported (untested) | | RHEL 7 | yum | ⚠️ No | Supported (untested) | | RHEL 8+ | dnf | ⚠️ No | Supported (untested) | | AlmaLinux | dnf | ⚠️ No | Supported (untested) | | Rocky Linux | dnf | ⚠️ No | Supported (untested) | | CentOS 7 | yum | ⚠️ No | Supported (untested) | | CentOS 8+ | dnf | ⚠️ No | Supported (untested) | | SUSE/OpenSUSE | zypper | ⚠️ No | Supported (untested) | The skill automatically detects the distribution and selects the appropriate package manager.

path: CONTRIBUTING.md
content: # Contributing to Linux Patcher

Thank you for considering contributing! This project welcomes contributions from the community.

## How to Contribute

### 1. Testing on Untested Distributions

**We need testers for:**
- Debian
- Amazon Linux (AL2 and AL2023)
- RHEL (7 and 8+)
- AlmaLinux
- Rocky Linux
- CentOS (7 and 8+)
- SUSE/OpenSUSE

**To contribute test results:**

1. Test the skill on your distribution:
   ```bash
   scripts/patch-auto.sh --dry-run
   scripts/patch-host-only.sh user@testhost
   ```

2. Document your findings:
   - Distribution and version
   - Commands that worked/failed
   - Any errors encountered
   - Screenshots if applicable

3. Open an issue with title: `[Testing] Distribution Name Version`

4. If commands need adjustment, submit a PR with fixes

### 2. Bug Reports

Found a bug? Please open an issue with:

- **Title:** Brief description of the bug
- **Distribution:** OS and version where bug occurs
- **Steps to reproduce:**
  1. Step one
  2. Step two
  3. ...
- **Expected behavior:** What should happen
- **Actual behavior:** What actually happened
- **Logs:** Include relevant error messages
- **Environment:**
  - OpenClaw version
  - Skill version
  - SSH configuration

### 3. Feature Requests

Have an idea? Open an issue with:

- **Title:** `[Feature Request] Your idea`
- **Description:** What you'd like to see
- **Use case:** Why this would be useful
- **Possible implementation:** (optional)

### 4. Pull Requests

**Before submitting a PR:**

1. Fork the repository
2. Create a feature branch: `git checkout -b feature/your-feature`
3. Make your changes
4. Test thoroughly on at least one distribution
5. Update documentation if needed
6. Commit with clear messages
7. Push to your fork
8. Open a PR with description of changes

**PR Guidelines:**

- Keep changes focused (one feature/fix per PR)
- Follow existing code style
- Update relevant documentation
- Add comments for complex logic
- Test on Ubuntu if possible

### 5. Documentation Improvements

Documentation improvements are always welcome:

- Fix typos
- Clarify confusing sections
- Add examples
- Improve formatting
- Add translations (future)

### 6. Distribution-Specific Contributions

If you're familiar with a specific distribution:

- Add distribution-specific tips to SETUP.md
- Improve package manager commands in detect-os.sh
- Test and verify commands work correctly
- Document distribution quirks

## Development Setup

```bash
# Clone the repo
git clone https://github.com/yourusername/linux-patcher-skill
cd linux-patcher-skill

# Make scripts executable
chmod +x scripts/*.sh

# Test detection
./scripts/detect-os.sh user@testhost

# Test dry-run
DRY_RUN=true ./scripts/patch-host-only.sh user@testhost
```

## Code Style

- Use Bash for shell scripts
- Follow existing indentation (2 spaces)
- Add comments for non-obvious logic
- Use descriptive variable names
- Include error handling
- Validate inputs

## Testing Checklist

Before submitting PR, verify:

- [ ] Scripts are executable (`chmod +x`)
- [ ] Dry-run mode works
- [ ] Error handling works (test with invalid inputs)
- [ ] Documentation updated
- [ ] No sensitive data in commits
- [ ] CHANGELOG.md updated (if applicable)

## Community Guidelines

- Be respectful and constructive
- Help others when possible
- Share knowledge
- Report security issues privately (see SECURITY.md if created)

## Questions?

- Open a discussion on GitHub
- Ask in OpenClaw Discord: https://discord.com/invite/clawd
- Check existing issues

## Recognition

Contributors will be:
- Listed in CONTRIBUTORS.md (when created)
- Mentioned in release notes
- Acknowledged in documentation

Thank you for contributing! 🎉


path: README.md
content: # Linux Patcher - OpenClaw Skill

[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
[![OpenClaw](https://img.shields.io/badge/OpenClaw-Skill-orange)](https://openclaw.ai)

Automated Linux server patching with PatchMon integration for OpenClaw.

## 🎯 Features

- ✅ **Ubuntu fully tested** - Production-ready
- ⚠️ **10+ distributions supported** - Debian, RHEL, AlmaLinux, Rocky, CentOS, Amazon Linux, SUSE (untested)
- 🔒 **Security-focused** - Restricted sudo, SSH key auth
- 🤖 **PatchMon integration** - Automatic host detection
- 🐳 **Smart Docker detection** - Auto-detects and updates containers
- 📊 **Visual workflow diagrams** - Easy to understand
- 🚀 **Chat-based interface** - "Update my servers" just works
- 🔄 **Dry-run mode** - Preview changes before applying

## 🚀 Quick Start

### Installation

```bash
# Option 1: Install from file
openclaw skill install linux-patcher.skill

# Option 2: Install from ClawHub (when published)
clawhub install linux-patcher

# Option 3: Install from this repo
git clone https://github.com/JGM2025/linux-patcher-skill
cd linux-patcher-skill
openclaw skill install .
```

### Initial Setup

```bash
# 1. Read the setup guide
cd ~/.openclaw/workspace/skills/linux-patcher
cat SETUP.md

# 2. Configure SSH keys
ssh-keygen -t ed25519 -C "openclaw-patching" -f ~/.ssh/id_openclaw
ssh-copy-id -i ~/.ssh/id_openclaw.pub admin@targethost

# 3. Configure PatchMon credentials
cp scripts/patchmon-credentials.example.conf ~/.patchmon-credentials.conf
nano ~/.patchmon-credentials.conf
chmod 600 ~/.patchmon-credentials.conf

# 4. Test with dry-run
scripts/patch-auto.sh --dry-run
```

### Usage

**Via OpenClaw chat (recommended):**

```
You: "Update my servers"
→ Updates packages + Docker containers automatically

You: "Update my servers, excluding docker"
→ Updates packages only, containers keep running

You: "What servers need patching?"
→ Queries PatchMon for update status
```

**Direct command line:**

```bash
# Automatic mode (PatchMon)
scripts/patch-auto.sh

# Skip Docker updates
scripts/patch-auto.sh --skip-docker

# Dry-run (preview only)
scripts/patch-auto.sh --dry-run

# Manual single host
scripts/patch-host-only.sh [REDACTED_SECRET]
scripts/patch-host-full.sh [REDACTED_SECRET] /opt/docker
```

## 📋 Prerequisites

### Required

- **OpenClaw** installed and running
- **SSH client** with key authentication
- **curl** and **jq** for PatchMon integration
- **Passwordless sudo** on target hosts (restricted to patching commands)
- **PatchMon** installed (required to check which hosts need updating)
  - Does NOT need to be on the OpenClaw host
  - Download: https://github.com/PatchMon/PatchMon
  - Docs: https://docs.patchmon.net

### For Automatic Host Detection

- **PatchMon server** (required for automatic mode)
  - **Important:** Does NOT need to be on the same server as OpenClaw
  - Install on any accessible server (separate host recommended)
  - OpenClaw queries PatchMon via HTTPS API
  - Download: https://github.com/PatchMon/PatchMon

### Optional

- **Docker** on target hosts (for container updates)
- **Docker Compose** on target hosts

**Note:** You can use this skill without PatchMon by manually specifying hosts, but automatic detection of which hosts need updates requires PatchMon.

## 📖 Documentation

Complete documentation is included in the skill:

- **[SKILL.md](SKILL.md)** - Main usage guide and features
- **[SETUP.md](SETUP.md)** - Complete setup with security best practices
- **[WORKFLOWS.md](WORKFLOWS.md)** - Visual workflow diagrams
- **[references/patchmon-setup.md](references/patchmon-setup.md)** - PatchMon installation

## 🌍 Supported Distributions

| Distribution | Package Manager | Status |
|--------------|-----------------|--------|
| Ubuntu | apt | ✅ Fully tested |
| Debian | apt | ⚠️ Supported (untested) |
| Amazon Linux 2 | yum | ⚠️ Supported (untested) |
| Amazon Linux 2023 | dnf | ⚠️ Supported (untested) |
| RHEL 7 | yum | ⚠️ Supported (untested) |
| RHEL 8+ | dnf | ⚠️ Supported (untested) |
| AlmaLinux | dnf | ⚠️ Supported (untested) |
| Rocky Linux | dnf | ⚠️ Supported (untested) |
| CentOS 7 | yum | ⚠️ Supported (untested) |
| CentOS 8+ | dnf | ⚠️ Supported (untested) |
| SUSE/OpenSUSE | zypper | ⚠️ Supported (untested) |

**Testing needed!** If you use this skill on untested distributions, please report results via issues.

## 🔒 Security

This skill is designed with security as a priority:

- **No passwords stored** - SSH key authentication only
- **Restricted sudo** - Only specific commands allowed (no `NOPASSWD: ALL`)
- **Principle of least privilege** - Minimal permissions granted
- **Audit trail** - All actions logged via syslog
- **Safe testing** - Dry-run mode available

See [SETUP.md](SETUP.md) for complete security configuration.

## 🎓 Examples

### Example 1: Automatic updates via PatchMon
```bash
# Query PatchMon, detect hosts, update everything
scripts/patch-auto.sh
```

### Example 2: Skip Docker updates
```bash
# Update packages only, leave containers running
scripts/patch-auto.sh --skip-docker
```

### Example 3: Test before applying
```bash
# Preview what would be updated
scripts/patch-auto.sh --dry-run

# Review output, then apply
scripts/patch-auto.sh
```

### Example 4: Via OpenClaw chat
```
You: "Update my servers"
OpenClaw: Queries PatchMon → Updates 4 hosts → Reports "✓ All hosts updated successfully"
```

### Example 5: Schedule automated patching
```bash
# Run nightly at 2 AM
cron add --name "Nightly Patching" \
  --schedule "0 2 * * *" \
  --task "cd ~/.openclaw/workspace/skills/linux-patcher && scripts/patch-auto.sh"
```

## 🤝 Contributing

Contributions welcome! Especially:

- Testing on untested distributions
- Bug reports and fixes
- Documentation improvements
- Feature requests

Please open an issue or pull request.

## 📄 License

MIT License - See [LICENSE](LICENSE) file for details.

## 🆘 Support

- **Documentation:** See SKILL.md, SETUP.md, WORKFLOWS.md
- **Issues:** https://github.com/JGM2025/linux-patcher-skill/issues
- **OpenClaw Community:** https://discord.com/invite/clawd
- **PatchMon:** https://github.com/PatchMon/PatchMon

## 🎉 Acknowledgments

- Built for [OpenClaw](https://openclaw.ai)
- Integrates with [PatchMon](https://github.com/PatchMon/PatchMon)
- Inspired by the need for simple, secure server patching

---

**Note:** Always test in a non-production environment first, especially on untested distributions.


path: references/patchmon-setup.md
content: # PatchMon Integration Guide

PatchMon is an open-source Linux patch monitoring dashboard that provides:

- Web-based UI for viewing update status across all hosts
- Per-host package tracking and history
- Security update highlighting
- Automated update scheduling
- Update history and audit logs

## Installation

### Docker Compose (Recommended)

Create `/opt/patchmon/docker-compose.yml`:

```yaml
version: '3.8'

services:
  patchmon-database:
    image: postgres:17
    container_name: patchmon-database
    restart: always
    environment:
      POSTGRES_DB: patchmon_db
      POSTGRES_USER: patchmon_user
      POSTGRES_PASSWORD: ${PATCHMON_DB_PASSWORD}
    volumes:
      - patchmon-postgres:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U patchmon_user -d patchmon_db"]
      interval: 10s
      timeout: 5s
      retries: 5

  patchmon-redis:
    image: redis:7
    container_name: patchmon-redis
    restart: always
    command: redis-server --requirepass ${PATCHMON_REDIS_PASSWORD}
    volumes:
      - patchmon-redis:/data
    healthcheck:
      test: ["CMD", "redis-cli", "-a", "${PATCHMON_REDIS_PASSWORD}", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5

  patchmon-backend:
    image: ghcr.io/patchmon/patchmon-backend:latest
    container_name: patchmon-backend
    restart: always
    environment:
      DATABASE_URL: postgresql://patchmon_user:${PATCHMON_DB_PASSWORD}@patchmon-database:5432/patchmon_db
      REDIS_HOST: patchmon-redis
      REDIS_PORT: 6379
      REDIS_PASSWORD: ${PATCHMON_REDIS_PASSWORD}
      JWT_SECRET: ${PATCHMON_JWT_SECRET}
      JWT_EXPIRES_IN: 1h
      JWT_REFRESH_EXPIRES_IN: 7d
      PORT: 3001
    volumes:
      - patchmon-agent-files:/app/agent-files
    depends_on:
      patchmon-database:
        condition: service_healthy
      patchmon-redis:
        condition: service_healthy

  patchmon-frontend:
    image: ghcr.io/patchmon/patchmon-frontend:latest
    container_name: patchmon-frontend
    restart: always
    ports:
      - "3000:3000"
    environment:
      BACKEND_HOST: patchmon-backend
      BACKEND_PORT: 3001
    depends_on:
      - patchmon-backend

volumes:
  patchmon-postgres:
  patchmon-redis:
  patchmon-agent-files:
```

Create `.env` file:

```bash
# Generate secure passwords:
# openssl rand -base64 32

PATCHMON_DB_PASSWORD=<generate-secure-password>
PATCHMON_REDIS_PASSWORD=<generate-secure-password>
PATCHMON_JWT_SECRET=<generate-secure-password>
```

Start PatchMon:

```bash
cd /opt/patchmon
docker compose up -d
```

Access at: `http://localhost:3000`

## Agent Installation

Install PatchMon agent on each monitored host:

```bash
curl -sSL https://raw.githubusercontent.com/PatchMon/PatchMon/main/agent/install.sh | sudo bash
```

Configure agent (`/etc/patchmon/config.yml`):

```yaml
server:
  url: "http://patchmon-server:3001"
  [REDACTED_SECRET]"

reporting:
  interval: 3600  # Report every hour
  report_offset: 300  # Stagger by 5 minutes

features:
  auto_update: true  # Auto-update agent itself
  docker: true       # Enable Docker monitoring
```

Start agent:

```bash
sudo systemctl enable patchmon-agent
sudo systemctl start patchmon-agent
```

## Web Dashboard Usage

### View Update Status

1. Log into PatchMon UI
2. Navigate to **Dashboard**
3. View summary cards:
   - Total Hosts
   - Needs Updating
   - Outdated Packages
   - Security Updates

### View Host Details

1. Navigate to **Hosts**
2. Click on a hostname
3. View:
   - Outdated packages list
   - Security updates
   - Update history
   - Reboot requirements

### Schedule Updates

1. Navigate to **Jobs** → **Create Job**
2. Configure:
   - Target hosts or groups
   - Update type (packages only / full)
   - Schedule (cron expression)
   - Notification settings
3. Save and enable

## Integration with Linux Patcher Skill

PatchMon and this skill complement each other:

**PatchMon provides:**
- Visual dashboard
- Update tracking
- Scheduled automated updates
- Web UI for non-technical users

**Linux Patcher skill provides:**
- OpenClaw integration
- Ad-hoc updates via chat
- Flexible scripting
- Custom workflows

### Recommended Setup

1. **Install PatchMon** for monitoring and dashboard
2. **Use PatchMon agents** for automated scheduled updates
3. **Use Linux Patcher skill** for manual/urgent updates via OpenClaw

Example workflow:
- PatchMon runs nightly updates automatically
- User asks OpenClaw: "Update webserver immediately"
- OpenClaw uses Linux Patcher skill for instant update
- Both systems log to PatchMon dashboard

## API Access (Advanced)

Query PatchMon programmatically:

```bash
# Get authentication token
[REDACTED_SECRET] -X POST https://patchmon.example.com/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","password":"your-password"}' \
  | jq -r '.token')

# List hosts needing updates
curl https://patchmon.example.com/api/v1/dashboard/hosts \
  -H "Authorization: Bearer $TOKEN" \
  | jq '.[] | select(.needsUpdates == true)'

# Get outdated packages for a host
curl https://patchmon.example.com/api/v1/dashboard/hosts/HOST_ID/packages \
  -H "Authorization: Bearer $TOKEN" \
  | jq '.outdated'
```

## Resources

- **Official Documentation:** https://docs.patchmon.net
- **GitHub Repository:** https://github.com/PatchMon/PatchMon
- **Discord Community:** https://patchmon.net/discord
- **Reddit Community:** https://reddit.com/r/patchmon

## Security Considerations

- **Use HTTPS** for production deployments (configure reverse proxy)
- **Restrict API access** with firewall rules
- **Rotate JWT secrets** regularly
- **Use strong passwords** for database and Redis
- **Limit agent permissions** to necessary commands only
- **Monitor PatchMon logs** for suspicious activity


path: scripts/patch-host-only.sh
content: #!/bin/bash
# patch-host-only.sh - Update Linux packages only (no Docker)
# Usage: ./patch-host-only.sh user@hostname

set -e

if [ $# -lt 1 ]; then
    echo "Usage: $0 user@hostname"
    echo "Example: $0 [REDACTED_SECRET]"
    exit 1
fi

HOST="$1"
DRY_RUN="${DRY_RUN:-false}"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

echo "========================================="
echo "Linux Patcher - Host-Only Mode"
echo "========================================="
echo "Target: $HOST"
echo "Dry Run: $DRY_RUN"
echo ""

# Detect OS and get package manager commands
echo "Detecting Linux distribution..."
eval "$("$SCRIPT_DIR/detect-os.sh" "$HOST")"

if [ $? -ne 0 ]; then
    echo "ERROR: Failed to detect OS on $HOST"
    exit 1
fi

echo "✓ Detected: $DISTRO_NAME ($PKG_MANAGER)"

if [ "$TESTED" = "false" ]; then
    echo ""
    echo "⚠ WARNING: $DISTRO_NAME support is UNTESTED"
    echo "  Only Ubuntu has been tested end-to-end"
    echo "  Update commands for $DISTRO_NAME are based on documentation"
    echo "  Proceed with caution and verify results"
    echo ""
fi

if [ "$DRY_RUN" = "true" ]; then
    echo ""
    echo "[DRY RUN] Would execute the following updates:"
    echo "  1. $UPDATE_CMD"
    echo "  2. $UPGRADE_CMD"
    echo "  3. $AUTOREMOVE_CMD"
    echo ""
    echo "Set DRY_RUN=false to apply changes"
    exit 0
fi

echo ""
echo "Step 1/3: Updating package lists..."
ssh "$HOST" "sudo $UPDATE_CMD" || {
    echo "ERROR: Failed to update package lists on $HOST"
    exit 1
}

echo "Step 2/3: Upgrading packages..."
ssh "$HOST" "sudo $UPGRADE_CMD" || {
    echo "ERROR: Failed to upgrade packages on $HOST"
    exit 1
}

echo "Step 3/3: Removing unused packages..."
ssh "$HOST" "sudo $AUTOREMOVE_CMD" || {
    echo "WARNING: Failed to autoremove packages on $HOST (non-critical)"
}

echo ""
echo "✓ Host-only update complete on $HOST"
echo ""

# Check for reboot requirement (best-effort, varies by distro)
echo "Checking if reboot is required..."
if ssh "$HOST" "[ -f /var/run/reboot-required ]" 2>/dev/null; then
    echo "⚠ REBOOT REQUIRED (Kernel or critical libraries updated)"
elif ssh "$HOST" "[ -f /boot/vmlinuz-\$(uname -r) ]" 2>/dev/null; then
    # Check if running kernel matches latest installed
    RUNNING_KERNEL=$(ssh "$HOST" "uname -r")
    LATEST_KERNEL=$(ssh "$HOST" "ls -t /boot/vmlinuz-* 2>/dev/null | head -n1 | sed 's|/boot/vmlinuz-||'")
    if [ "$RUNNING_KERNEL" != "$LATEST_KERNEL" ]; then
        echo "⚠ REBOOT RECOMMENDED (Kernel updated: $RUNNING_KERNEL → $LATEST_KERNEL)"
    else
        echo "✓ No reboot required"
    fi
else
    echo "ℹ Could not determine reboot status (check manually if kernel was updated)"
fi


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: suspicious | SkillSpector: suspicious (CRITICAL)