skills/local/cali-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-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.
testing
[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".
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.