summaryrefslogtreecommitdiffstats
path: root/README.md
blob: 4394e355bb9fd244900633330ea6ce95ac5601e3 (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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
# Ship - VPS Deployment CLI

Simple CLI tool for deploying Go apps and static sites to a VPS with automatic HTTPS via Caddy.

## Features

- Single command deployment from your laptop
- Automatic HTTPS via Caddy + Let's Encrypt
- Automatic port allocation (no manual tracking)
- Environment variable management
- Systemd process management with auto-restart
- Support for multiple apps/sites on one VPS
- State stored locally (VPS is stateless and easily recreatable)
- Zero dependencies on VPS (just installs Caddy)

## Installation

```bash
# Build the CLI
go build -o ~/bin/ship ./cmd/ship

# Or install to GOPATH
go install ./cmd/ship
```

## Quick Start

### 1. Initialize Your VPS (One-time)

```bash
# Initialize a fresh VPS (this sets it as the default host)
ship host init user@your-vps-ip
```

This will:
- Install Caddy
- Configure Caddy for automatic HTTPS
- Create necessary directories
- Set up the VPS for deployments

### 2. Deploy a Go App

```bash
# Build your app for Linux
GOOS=linux GOARCH=amd64 go build -o myapp

# Deploy it
ship --binary ./myapp --domain api.example.com

# With environment variables
ship --binary ./myapp --domain api.example.com \
  --env DB_HOST=localhost \
  --env API_KEY=secret

# Or from an env file
ship --binary ./myapp --domain api.example.com \
  --env-file .env.production
```

### 3. Deploy a Static Site

```bash
# Build your site
npm run build

# Deploy it
ship --static --dir ./dist --domain example.com
```

## App Requirements

Your Go app must:
1. Listen on HTTP (not HTTPS - Caddy handles that)
2. Accept port via `--port` flag or `PORT` environment variable
3. Bind to `localhost` or `127.0.0.1` only

Example:

```go
package main

import (
    "flag"
    "fmt"
    "net/http"
    "os"
)

func main() {
    port := flag.String("port", os.Getenv("PORT"), "port to listen on")
    flag.Parse()

    if *port == "" {
        *port = "8080" // fallback for local dev
    }

    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("Hello World"))
    })

    addr := "127.0.0.1:" + *port
    fmt.Printf("Listening on %s\n", addr)
    http.ListenAndServe(addr, nil)
}
```

## Commands

### Host Management

```bash
# Initialize a fresh VPS (one-time setup, sets as default)
ship host init user@vps-ip

# Update system packages (apt update && apt upgrade)
ship host update

# Check host status
ship host status

# SSH into the host
ship host ssh
```

### Deploy App/Site
```bash
# Go app
ship --binary ./myapp --domain api.example.com

# Static site
ship --static --dir ./dist --domain example.com

# Custom name (defaults to binary/directory name)
ship --name myapi --binary ./myapp --domain api.example.com
```

### List Deployments
```bash
ship list
```

### Manage Deployments
```bash
# View logs
ship logs myapp

# View status
ship status myapp

# Restart app
ship restart myapp

# Remove deployment
ship remove myapp
```

### Environment Variables
```bash
# View current env vars (secrets are masked)
ship env list myapi

# Set env vars
ship env set myapi DB_HOST=localhost API_KEY=secret

# Load from file
ship env set myapi -f .env.production

# Unset env var
ship env unset myapi API_KEY
```

## Configuration

The host you initialize becomes the default, so you don't need to specify `--host` for every command. The default host is stored in `~/.config/ship/state.json`.

## How It Works

1. **State on Laptop**: All deployment state lives at `~/.config/ship/state.json` on your laptop
2. **SSH Orchestration**: The CLI uses SSH to run commands on your VPS
3. **File Transfer**: Binaries transferred via SCP, static sites via rsync
4. **Caddy for HTTPS**: Caddy automatically handles HTTPS certificates
5. **Systemd for Processes**: Apps run as systemd services with auto-restart
6. **Dumb VPS**: The VPS is stateless - you can recreate it by redeploying from local state

## File Structure

### On Laptop
```
~/.config/ship/state.json    # All deployment state (including default host)
```

### On VPS
```
/usr/local/bin/myapp                   # Go binary
/var/lib/myapp/                        # Working directory
/etc/systemd/system/myapp.service      # Systemd unit
/etc/caddy/sites-enabled/myapp.caddy   # Caddy config
/etc/ship/env/myapp.env                # Environment variables

/var/www/mysite/                       # Static site files
/etc/caddy/sites-enabled/mysite.caddy  # Caddy config
```

## Security

- Each Go app runs as dedicated system user
- Systemd security hardening enabled (NoNewPrivileges, PrivateTmp)
- Static sites served as www-data
- Caddy automatically manages TLS certificates
- Environment files stored with 0600 permissions
- Secrets masked when displaying environment variables

## Supported OS

- Ubuntu 20.04+
- Debian 11+

## License

MIT