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
|
---
name: ship-setup
description: Set up ship for the first time or add a new VPS host. Saves host config to ~/.config/ship/config.json and installs server dependencies. Use when configuring ship for the first time, or adding/changing a host.
argument-hint: "[host-nickname]"
---
# ship-setup
Configure ship and prepare a VPS for deployments.
## Config File
All ship skills read from `~/.config/ship/config.json`. This skill creates or updates it.
Structure:
```json
{
"default": "prod",
"hosts": {
"prod": {
"host": "ubuntu@1.2.3.4",
"domain": "example.com"
},
"staging": {
"host": "ubuntu@5.6.7.8",
"domain": "staging.example.com"
}
}
}
```
## Steps
### 1. Read existing config
Check if `~/.config/ship/config.json` exists:
```bash
cat ~/.config/ship/config.json 2>/dev/null
```
If it exists, show the user the current hosts so they know what's already configured.
### 2. Get host details
If no nickname was provided as an argument, ask the user:
- **Nickname** — a short name for this host (e.g. `prod`, `staging`, `vps`)
- **SSH connection string** — e.g. `ubuntu@1.2.3.4` or an SSH config alias like `alaskav6`
- **Base domain** — the domain pointing to this server (e.g. `example.com`)
If this is the first host, ask if it should be the default. If hosts already exist, ask if this should replace the current default.
### 3. Test SSH connection
Verify the connection works before saving anything:
```bash
ssh -o ConnectTimeout=5 <host> "echo ok"
```
If it fails, tell the user and stop. Don't save config for an unreachable host.
### 4. Save config
Write or update `~/.config/ship/config.json` with the new host. Merge with existing hosts — never overwrite the whole file. Use Python to safely read/write JSON:
```bash
python3 -c "
import json, os
path = os.path.expanduser('~/.config/ship/config.json')
os.makedirs(os.path.dirname(path), exist_ok=True)
cfg = json.load(open(path)) if os.path.exists(path) else {'default': None, 'hosts': {}}
cfg['hosts']['<nickname>'] = {'host': '<ssh-host>', 'domain': '<domain>'}
if not cfg['default']:
cfg['default'] = '<nickname>'
json.dump(cfg, open(path, 'w'), indent=2)
print('saved')
"
```
### 5. Install server dependencies
SSH in and ensure the required directories and software exist. This is idempotent — safe to run multiple times.
**Install Caddy** (if not present):
```bash
ssh <host> "which caddy || (sudo apt-get install -y debian-keyring debian-archive-keyring apt-transport-https curl && curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg && curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list && sudo apt-get update && sudo apt-get install -y caddy)"
```
**Create directory structure:**
```bash
ssh <host> "sudo mkdir -p /etc/ship/env /etc/ship/ports /etc/caddy/sites-enabled /var/www && sudo chmod 755 /etc/ship"
```
**Configure main Caddyfile** (only if not already set up):
```bash
ssh <host> "sudo test -f /etc/caddy/Caddyfile && echo exists || echo '{
}
import /etc/caddy/sites-enabled/*' | sudo tee /etc/caddy/Caddyfile"
```
**Enable and start Caddy:**
```bash
ssh <host> "sudo systemctl enable caddy && sudo systemctl start caddy"
```
### 6. Confirm
Tell the user:
- Host nickname and SSH target saved
- Whether it's the default host
- That the server is ready for deployments
- How to add another host: `/ship-setup <nickname>`
- How to deploy: `/ship-deploy`
## Notes
- Never overwrite the entire config file — always merge
- If a nickname already exists in config, confirm before overwriting it
- The SSH host can be an alias from `~/.ssh/config` — no need to require raw IP
- Default host is used by all other ship skills when no host is specified
|