skills/local/cali-ops-server-security/SKILL.md
[Cali] Server security audit and hardening for private servers behind Tailscale. Use when: auditing server security, hardening SSH/firewall/Docker, checking for vulnerabilities, setting up fail2ban, reviewing port exposure, or responding to security alerts. Covers 6 layers: CloudFlare, UFW, Tailscale, SSH, Docker, Application. Triggers: "server security", "security audit", "harden server", "SSH hardening", "firewall rules", "UFW config", "fail2ban", "port security", "Docker security", "vulnerability check", "security review".
npx skillsauth add renatocaliari/agent-sync-public-skills cali-ops-server-securityInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
6-layer security model for private servers behind Tailscale.
Internet → CloudFlare → UFW → Tailscale → SSH → Docker → App
| Layer | Purpose | Tool | |---|---|---| | 1. CloudFlare | CDN, DDoS, SSL, WAF, hide real IP | CloudFlare DNS + Tunnel | | 2. UFW | Port filtering, default deny | UFW firewall | | 3. Tailscale | WireGuard tunnel, private network | Tailscale | | 4. SSH | Authentication, access control | OpenSSH / Tailscale SSH | | 5. Docker | Container isolation, socket security | Docker Engine | | 6. Application | Process isolation, env vars, volumes | Docker Compose |
# Server packages
tailscale # WireGuard tunnel
ufw # Firewall
docker # Container runtime
docker-compose # Multi-container apps
fail2ban # (optional) Brute-force protection
# SSH config
openssh-server # SSH daemon
sudo ufw status verbose
# Check:
# Status: active
# Default: deny (incoming), allow (outgoing)
# Only tailscale0 ports allowed (22, 2222)
# 80/tcp and 443/tcp allowed (for web)
tailscale status
# Check:
# Server listed with correct IP
# SSH enabled
# Correct tags assigned
tailscale set --ssh=true # ensure SSH enabled
# Check critical settings
grep -E "PermitRootLogin|PasswordAuthentication|X11Forwarding|MaxAuthTries|LoginGraceTime" /etc/ssh/sshd_config
# Expected:
# PermitRootLogin no
# PasswordAuthentication no
# X11Forwarding no
# MaxAuthTries 3
# LoginGraceTime 30
# Check deploy user
id deploy
cat /home/deploy/.ssh/authorized_keys
# Verify: command= restricts to docker compose only
# Verify: no-agent-forwarding, no-port-forwarding, no-X11-forwarding
# Socket permissions
ls -la /var/run/docker.sock
# Expected: srw-rw---- root docker
# No insecure registries
cat /etc/docker/daemon.json | grep insecure
# Expected: nothing or empty
# Containers not exposing ports on 0.0.0.0
sudo ss -tlnp | grep -E "0\.0\.0\.0:(3001|3002|4040|9122|9111)"
# Expected: nothing
# Check container isolation
docker ps --format "{{.Names}}: {{.Ports}}"
# Expected: no 0.0.0.0 bindings for internal services
# Check volumes
docker inspect <container> | grep -A5 "Mounts"
# Expected: named volumes or specific host paths, not /
| Issue | Risk | Fix |
|---|---|---|
| PermitRootLogin yes | Root SSH access | Set to no |
| PasswordAuthentication yes | Brute force risk | Set to no |
| Issue | Risk | Fix |
|---|---|---|
| X11Forwarding yes | Display hijacking | Set to no |
| Processes on 0.0.0.0 | Port exposure | Bind to 127.0.0.1 or tailscale0 |
| No fail2ban | No brute-force protection | Install + configure |
| Issue | Risk | Fix |
|---|---|---|
| No AllowUsers | Any user can SSH | Add AllowUsers deploy |
| No log monitoring | Missed intrusion attempts | Set up log alerts |
# Add to /etc/ssh/sshd_config
PermitRootLogin no
PasswordAuthentication no
X11Forwarding no
MaxAuthTries 3
LoginGraceTime 30
AllowUsers deploy
# Restart SSH
sudo systemctl restart ssh
# Verify rules
sudo ufw status numbered
# Remove any overly permissive rules
sudo ufw delete <rule-number>
# Rate limiting (optional)
sudo ufw limit 22/tcp
# Restrict socket access
sudo chmod 660 /var/run/docker.sock
sudo chown root:docker /var/run/docker.sock
# No privileged containers
docker inspect <container> | grep Privileged
# Expected: false
# Read-only rootfs (optional)
docker run --read-only ...
sudo apt install fail2ban
sudo systemctl enable fail2ban
# Configure
cat > /etc/fail2ban/jail.local << 'EOF'
[sshd]
enabled = true
port = 22,2222
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
EOF
sudo systemctl restart fail2ban
# Run all checks
echo "=== UFW ===" && sudo ufw status verbose
echo "=== SSH ===" && grep -E "PermitRootLogin|PasswordAuthentication|X11Forwarding" /etc/ssh/sshd_config
echo "=== Tailscale ===" && tailscale status
echo "=== Docker ===" && docker ps --format "{{.Names}}: {{.Ports}}"
echo "=== Ports ===" && sudo ss -tlnp | grep -E "0\.0\.0\.0"
# Fix SSH (run as root)
sudo sed -i 's/PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
sudo sed -i 's/PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo sed -i 's/X11Forwarding yes/X11Forwarding no/' /etc/ssh/sshd_config
sudo systemctl restart ssh
# Find processes listening on 0.0.0.0
sudo ss -tlnp | grep "0\.0\.0\.0" | awk '{print $NF, $4}'
# Should only show: sshd (22), caddy (80,443)
command= in authorized_keysAllowUsers to whitelist all deploy userssudo from deploy user instead of PermitRootLogindeploy ALL=(ALL) NOPASSWD: /usr/bin/dockerdocker-compose.yml for ports: section127.0.0.1:host_port instead of host_port:host_porttools
Auto-initialize structured documentation for any project using lat.md (knowledge graph of markdown files with [[wiki links]], // @lat: code refs, and semantic search). Detects cali-product-workflow artifacts (spec-product.md, spec-tech.md, critiques) and uses them as seed material. Falls back to extracting business rules, architecture, and design decisions directly from the codebase. Use when a project lacks structured documentation or when lat.md/ is missing. After seeding, lat.md extension hooks keep documentation alive automatically.
tools
Run supply chain security scans before installing packages or before releases. Triggers when: user installs a package (npm, pip, go get, brew), user asks to 'scan dependencies', 'check vulnerabilities', 'supply chain', 'security audit', 'run trivy', 'run socket', or before any release/deployment. Also triggers on mentions of: socket.dev, trivy, OSV-scanner, dotenvx, CVE, dependency audit. Covers all four tools with concrete commands.
tools
Create GitHub releases following project conventions. Triggers when: user says 'release', 'create release', 'push release', 'deploy to main', 'merge to main', user merges a PR to main, or when git push to main is detected. Also triggers on mentions of: gh release, semver, version bump, changelog, release-please. Covers: config-driven (read .release.yml and execute) and fallback (gh CLI) release flows, versioning rules, tag management, and the mandatory release-on-merge convention.
tools
[Cali] - INTERACTIVE SKILL: Discover servers from ~/.ssh/config, auto-detect hosts (filtering out non-server entries like github.com), prompt user to pick one via question tool, then SSH into the chosen server and render a real-time ASCII dashboard with Docker containers, images, volumes, routes, cron, orphaned resources, and cleanup suggestions. REQUIRES question tool, SSH config parsing, and shell execution.