---
name: "Caddy Web Server"
description: "Fleet skill: Caddy Web Server — software inventory and operations reference"
version: "1.0.0"
author: "skynet"
category: "fleet"
agents: ["claude-code", "codex", "gemini", "kimi"]
tags: ["software-caddy", "fleet", "fleet", "software"]
---

# Caddy Web Server

---
name: software-caddy
description: "Expert guidance for managing the Caddy Web Server (v2.10.2) as a fleet-wide reverse proxy, primarily on Dev Server (192.168.86.33). Use for HTTPS termination, domain routing, and proxying to Spark (192.168.86.48) services."
metadata:
  author: skynet
  version: 1.0.0
---

# Caddy Web Server (v2.10.2)

Caddy is the primary reverse proxy and HTTPS edge for James's fleet. It runs on **Dev Server (192.168.86.33)** as a `systemd` service, managing all external and internal traffic routing.

## Fleet Installation Status

| Machine | Role | IP | Status |
|---------|------|----|--------|
| **Dev Server** | **Primary Edge Proxy** | 192.168.86.33 | **Active (systemd)** |
| DGX Spark | Backend Services | 192.168.86.48 | Not Installed (Proxied) |
| Mac Mini Vault | Key Management | 192.168.86.27 | Internal Only |
| Dev Workstation | Development | 192.168.86.22 | Optional (Local Testing) |

## Key Locations

- **Caddyfile:** `/etc/caddy/Caddyfile`
- **Site Configs (Included):** `/etc/caddy/conf.d/*.caddy` (if directory used)
- **Certificates/Data:** `/var/lib/caddy/.local/share/caddy`
- **Admin API:** `http://localhost:2019`
- **Binary:** `/usr/bin/caddy`

## Essential Commands (Run on Dev Server)

### Management
```bash
# Apply configuration changes gracefully (Preferred)
ssh server "sudo caddy reload --config /etc/caddy/Caddyfile"

# System-level management
ssh server "sudo systemctl status caddy"
ssh server "sudo systemctl restart caddy"
ssh server "sudo systemctl reload caddy"
```

### Configuration & Validation
```bash
# Validate Caddyfile syntax before reloading
ssh server "caddy validate --config /etc/caddy/Caddyfile"

# Format the Caddyfile (Standardize indentation)
ssh server "sudo caddy fmt --overwrite /etc/caddy/Caddyfile"

# View current JSON configuration (as Caddy sees it)
ssh server "curl -s localhost:2019/config/ | jq"
```

### Observability
```bash
# Real-time logs for all sites
ssh server "journalctl -u caddy -f -n 100"

# Filter logs for errors only
ssh server "journalctl -u caddy -g 'error' --no-pager"
```

## Fleet-Specific Patterns

### Reverse Proxy to DGX Spark (192.168.86.48)
Most web services run on Spark. Use this pattern in the Caddyfile:

```caddyfile
# Example: LiteLLM Gateway
litellm.skynet.home {
    reverse_proxy 192.168.86.48:8000
}

# Example: n8n Workflows
n8n.skynet.home {
    reverse_proxy 192.168.86.48:5678
}
```

### Common Proxy Headers
Caddy automatically handles `X-Forwarded-For` and `X-Forwarded-Proto`, but some apps (like Nextcloud or certain Python frameworks) need explicit trust.

```caddyfile
# Standard transparent proxy block
(transparent) {
    header_up Host {host}
    header_up X-Real-IP {remote_host}
}

app.skynet.home {
    import transparent
    reverse_proxy 192.168.86.48:3000
}
```

## Common Workflows

### 1. Adding a New Project Subdomain
1. SSH into **Dev Server**.
2. Edit `/etc/caddy/Caddyfile`.
3. Add a new block pointing to the machine:port (e.g., `192.168.86.48:PORT`).
4. Run `caddy fmt --overwrite /etc/caddy/Caddyfile`.
5. Run `caddy reload --config /etc/caddy/Caddyfile`.

### 2. Handling Wildcard SSL (Local DNS)
Since this is an internal fleet, Caddy uses the `acme_server` or local CA if configured. For external domains, it uses ZeroSSL/Let's Encrypt.
- Verify DNS is pointed to `192.168.86.33` before adding the domain to Caddyfile.

### 3. Debugging Connection Refused
If a site returns 502 Bad Gateway:
1. Verify the backend is running: `ssh spark "docker ps"` or `ssh spark "netstat -tulpn | grep PORT"`.
2. Check if the backend is reachable from Dev Server: `ssh server "curl -I 192.168.86.48:PORT"`.
3. Check Caddy logs for `dial tcp` errors.

## Troubleshooting

### Config Validation Fails
- **Issue:** `caddy validate` shows syntax error.
- **Fix:** Ensure all `{}` are matched and directives are correctly spelled. Check for missing trailing slashes if using `route` or `handle`.

### Permission Denied on Caddyfile
- **Issue:** Cannot write to `/etc/caddy/Caddyfile`.
- **Fix:** Always use `sudo` for editing and reloading. Caddy runs as the `caddy` user, but the service management requires root.

### Admin API Not Responding
- **Issue:** `localhost:2019` times out.
- **Fix:** Ensure `admin` is not disabled in the global options block of the Caddyfile.
  ```caddyfile
  {
      admin localhost:2019
  }
  ```

## Reference
- Full Documentation: https://caddyserver.com/docs/
- Caddyfile Directives: https://caddyserver.com/docs/caddyfile/directives
