aboutsummaryrefslogtreecommitdiffstats
path: root/skills/ship-caddy/SKILL.md
blob: df79e393b811cbaf033a3db0f6ea3eee10e1f066 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
---
name: ship-caddy
description: Manage Caddy configuration for a deployed app. Add, update, or remove site configs. Use when you need to change how Caddy serves an app — custom domains, redirects, auth, headers, etc.
argument-hint: "<app-name> [host-nickname]"
---

# ship-caddy

Manage per-app Caddy configuration on a ship VPS.

## Read Config

```bash
python3 -c "
import json, os
cfg = json.load(open(os.path.expanduser('~/.config/ship/config.json')))
nick = '<nickname-or-default>'
h = cfg['hosts'].get(nick, cfg['hosts'][cfg['default']])
print(h['host'])
"
```

## Usage Patterns

### View current Caddy config for an app

```bash
ssh <host> "sudo cat /etc/caddy/sites-enabled/<app-name>.caddy"
```

### Add or update a site config

Read the current config first if it exists, then write the new one. Always reload
Caddy after writing — validate first by checking syntax:

```bash
ssh <host> "sudo caddy validate --config /etc/caddy/Caddyfile 2>&1"
```

If validation passes:
```bash
ssh <host> "sudo systemctl reload caddy"
```

If validation fails, show the error and do NOT reload. Tell the user what the
problem is.

### Standard reverse proxy config (most apps)

```bash
ssh <host> "sudo tee /etc/caddy/sites-enabled/<app-name>.caddy > /dev/null << 'EOF'
<domain> {
    reverse_proxy 127.0.0.1:<port>
}
EOF"
```

### Custom domain (in addition to default)

```bash
ssh <host> "sudo tee /etc/caddy/sites-enabled/<app-name>.caddy > /dev/null << 'EOF'
<custom-domain>, <default-domain> {
    reverse_proxy 127.0.0.1:<port>
}
EOF"
```

### Basic auth

```bash
ssh <host> "sudo tee /etc/caddy/sites-enabled/<app-name>.caddy > /dev/null << 'EOF'
<domain> {
    basicauth {
        <username> <bcrypt-hash>
    }
    reverse_proxy 127.0.0.1:<port>
}
EOF"
```

To generate a bcrypt hash for a password:
```bash
ssh <host> "caddy hash-password --plaintext '<password>'"
```

### Redirect www to non-www

```bash
ssh <host> "sudo tee /etc/caddy/sites-enabled/<app-name>.caddy > /dev/null << 'EOF'
www.<domain> {
    redir https://<domain>{uri} permanent
}

<domain> {
    reverse_proxy 127.0.0.1:<port>
}
EOF"
```

### Static site

```bash
ssh <host> "sudo tee /etc/caddy/sites-enabled/<app-name>.caddy > /dev/null << 'EOF'
<domain> {
    root * /var/www/<app-name>
    file_server
    encode gzip
}
EOF"
```

### Remove a site config

```bash
ssh <host> "sudo rm /etc/caddy/sites-enabled/<app-name>.caddy && sudo systemctl reload caddy"
```

Confirm with the user before removing.

### View Caddy status and logs

```bash
ssh <host> "sudo systemctl status caddy --no-pager"
ssh <host> "sudo journalctl -u caddy -n 50 --no-pager"
```

## Notes

- Always validate before reloading — never reload with a broken config
- The port for an app can be found at `/etc/ship/ports/<app-name>`
- Caddy handles HTTPS automatically — no need to configure certificates
- If the user asks for something not covered here, write the appropriate Caddy
  directives — Caddy's config language is flexible and well documented
- Main Caddyfile is at `/etc/caddy/Caddyfile` and imports all files in
  `/etc/caddy/sites-enabled/`