@devalade/shipnode 2.0.0 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
ADDED
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
# @devalade/shipnode
|
|
2
|
+
|
|
3
|
+
Deploy Node.js apps to a single VPS — zero-downtime releases, PM2, Caddy, SSH, no Docker required.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g @devalade/shipnode
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick start
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# 1. Generate config
|
|
15
|
+
shipnode init
|
|
16
|
+
|
|
17
|
+
# 2. Provision the server (Node, PM2, Caddy, mise)
|
|
18
|
+
shipnode setup
|
|
19
|
+
|
|
20
|
+
# 3. Deploy
|
|
21
|
+
shipnode deploy
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Configuration
|
|
25
|
+
|
|
26
|
+
`shipnode init` creates a `shipnode.config.ts` in your project root. You can also write it by hand using the fluent builder:
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
import { shipnode } from '@devalade/shipnode';
|
|
30
|
+
|
|
31
|
+
export default shipnode
|
|
32
|
+
.backend()
|
|
33
|
+
.ssh({ host: '1.2.3.4', user: 'deploy' })
|
|
34
|
+
.deployTo('/var/www/myapp')
|
|
35
|
+
.pm2('myapp', { instances: 2 })
|
|
36
|
+
.port(3000)
|
|
37
|
+
.domain('api.example.com')
|
|
38
|
+
.healthCheck('/health')
|
|
39
|
+
.nodeVersion('22')
|
|
40
|
+
.pkgManager('pnpm')
|
|
41
|
+
.build();
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Frontend apps
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
import { shipnode } from '@devalade/shipnode';
|
|
48
|
+
|
|
49
|
+
export default shipnode
|
|
50
|
+
.frontend()
|
|
51
|
+
.ssh({ host: '1.2.3.4', user: 'deploy' })
|
|
52
|
+
.deployTo('/var/www/myapp')
|
|
53
|
+
.domain('example.com')
|
|
54
|
+
.buildDir('dist')
|
|
55
|
+
.build();
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### All options
|
|
59
|
+
|
|
60
|
+
| Method | Default | Description |
|
|
61
|
+
|---|---|---|
|
|
62
|
+
| `.backend()` / `.frontend()` | — | App type |
|
|
63
|
+
| `.ssh({ host, user, port?, identityFile? })` | port 22 | SSH connection |
|
|
64
|
+
| `.deployTo(path)` | `/var/www/app` | Remote deploy path |
|
|
65
|
+
| `.pm2(name, opts?)` | — | PM2 process name + options |
|
|
66
|
+
| `.port(n)` | `3000` | Backend port |
|
|
67
|
+
| `.domain(d)` | — | Domain for Caddy config |
|
|
68
|
+
| `.nodeVersion(v)` | `lts` | Node version (via mise) |
|
|
69
|
+
| `.pkgManager(pm)` | auto-detected | `npm` \| `yarn` \| `pnpm` \| `bun` |
|
|
70
|
+
| `.buildDir(dir)` | auto-detected | Frontend build output dir |
|
|
71
|
+
| `.zeroDowntime({ keepReleases? })` | true, 5 | Zero-downtime releases |
|
|
72
|
+
| `.legacy()` | — | Simple in-place deploy |
|
|
73
|
+
| `.healthCheck(path, opts?)` | `/health`, 30s, 3 retries | Post-deploy health check |
|
|
74
|
+
| `.noHealthCheck()` | — | Skip health check |
|
|
75
|
+
| `.envFile(f)` | `.env` | Local .env file to upload |
|
|
76
|
+
| `.sharedDirs(dirs)` | — | Dirs persisted across releases |
|
|
77
|
+
| `.sharedFiles(files)` | — | Files persisted across releases |
|
|
78
|
+
| `.database(opts)` | — | Database connection config |
|
|
79
|
+
| `.backup(opts)` | — | S3 backup config |
|
|
80
|
+
| `.cloudflare(opts)` | — | Cloudflare Tunnel config |
|
|
81
|
+
| `.preDeploy(fn)` | — | Hook: runs before symlink switch |
|
|
82
|
+
| `.postDeploy(fn)` | — | Hook: runs after deploy |
|
|
83
|
+
|
|
84
|
+
## Commands
|
|
85
|
+
|
|
86
|
+
### Core
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
shipnode init # Generate shipnode.config.ts interactively
|
|
90
|
+
shipnode setup # Install Node, PM2, Caddy, fail2ban on server
|
|
91
|
+
shipnode deploy # Deploy (zero-downtime by default)
|
|
92
|
+
shipnode deploy --dry-run # Preview without making changes
|
|
93
|
+
shipnode deploy --skip-build # Skip local build step
|
|
94
|
+
shipnode doctor # Check local + remote config
|
|
95
|
+
shipnode doctor --security # Run security audit
|
|
96
|
+
shipnode status # Show PM2 process status
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Release management
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
shipnode rollback # Roll back to the previous release
|
|
103
|
+
shipnode rollback --steps 3 # Roll back 3 releases
|
|
104
|
+
shipnode migrate # Migrate existing deploy to zero-downtime structure
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Environment
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
shipnode env # Upload local .env to server
|
|
111
|
+
shipnode run "npm run migrate" # Run a one-off command on the server
|
|
112
|
+
shipnode run bash # Open an interactive shell
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Process management
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
shipnode logs # Tail PM2 logs (last 100 lines)
|
|
119
|
+
shipnode logs --lines 500 # Show 500 lines
|
|
120
|
+
shipnode restart # Reload PM2 with --update-env
|
|
121
|
+
shipnode stop # Stop the application
|
|
122
|
+
shipnode metrics # Open PM2 monit dashboard
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Security & maintenance
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
shipnode harden # SSH hardening, UFW firewall, fail2ban
|
|
129
|
+
shipnode unlock # Clear a stuck deployment lock
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Users
|
|
133
|
+
|
|
134
|
+
Manage SSH users via `.shipnode/users.yml`:
|
|
135
|
+
|
|
136
|
+
```yaml
|
|
137
|
+
- username: alice
|
|
138
|
+
publicKey: ssh-ed25519 AAAA... alice@laptop
|
|
139
|
+
sudo: true
|
|
140
|
+
- username: bob
|
|
141
|
+
publicKey: ssh-ed25519 AAAA... bob@laptop
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
shipnode user sync # Create/update users from users.yml
|
|
146
|
+
shipnode user list # List non-system users on server
|
|
147
|
+
shipnode user remove alice # Remove a user
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Backups
|
|
151
|
+
|
|
152
|
+
Requires `backup` config and `aws` CLI on the server.
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
export default shipnode
|
|
156
|
+
// ...
|
|
157
|
+
.backup({
|
|
158
|
+
s3Bucket: 'my-backups',
|
|
159
|
+
s3Prefix: 'myapp/',
|
|
160
|
+
schedule: 'daily', // hourly | daily | weekly
|
|
161
|
+
retentionDays: 14,
|
|
162
|
+
})
|
|
163
|
+
.build();
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
shipnode backup setup # Install backup script + systemd timer
|
|
168
|
+
shipnode backup run # Run a backup immediately
|
|
169
|
+
shipnode backup status # Show timer and last run log
|
|
170
|
+
shipnode backup list # List recent backups in S3
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Cloudflare Tunnel
|
|
174
|
+
|
|
175
|
+
Expose your app and SSH through Cloudflare without opening ports. Requires `CLOUDFLARE_API_TOKEN` env var.
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
export default shipnode
|
|
179
|
+
// ...
|
|
180
|
+
.cloudflare({
|
|
181
|
+
zone: 'example.com',
|
|
182
|
+
appHostname: 'app.example.com',
|
|
183
|
+
sshHostname: 'ssh.example.com',
|
|
184
|
+
lockdownFirewall: true, // Restrict inbound to CF IPs only
|
|
185
|
+
})
|
|
186
|
+
.build();
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
shipnode cloudflare init # Install cloudflared, create tunnel, configure DNS
|
|
191
|
+
shipnode cloudflare audit # Verify DNS records and tunnel
|
|
192
|
+
shipnode cloudflare status # Show cloudflared service status
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### CI/CD
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
shipnode ci github # Generate .github/workflows/shipnode-deploy.yml
|
|
199
|
+
shipnode ci env-sync # Push .env vars to GitHub repository secrets
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Configuration
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
shipnode config show # Print resolved config
|
|
206
|
+
shipnode config validate # Validate config file
|
|
207
|
+
shipnode config path # Print path to config file
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Customization
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
shipnode eject pm2 # Eject PM2 ecosystem template to .shipnode/templates/
|
|
214
|
+
shipnode eject caddy # Eject Caddy config template
|
|
215
|
+
shipnode eject all # Eject all templates
|
|
216
|
+
shipnode upgrade # Upgrade to the latest version
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## Deploy hooks
|
|
220
|
+
|
|
221
|
+
Run code before or after the symlink switch:
|
|
222
|
+
|
|
223
|
+
```ts
|
|
224
|
+
export default shipnode
|
|
225
|
+
.backend()
|
|
226
|
+
// ...
|
|
227
|
+
.preDeploy(async ({ exec }) => {
|
|
228
|
+
await exec('npx prisma migrate deploy');
|
|
229
|
+
})
|
|
230
|
+
.postDeploy(async ({ exec, config }) => {
|
|
231
|
+
await exec(`curl -s https://${config.domain}/health`);
|
|
232
|
+
})
|
|
233
|
+
.build();
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## Zero-downtime releases
|
|
237
|
+
|
|
238
|
+
By default, shipnode uses a Capistrano-style release structure:
|
|
239
|
+
|
|
240
|
+
```
|
|
241
|
+
/var/www/myapp/
|
|
242
|
+
releases/
|
|
243
|
+
20240101T120000/ ← previous
|
|
244
|
+
20240102T090000/ ← current (symlinked)
|
|
245
|
+
shared/
|
|
246
|
+
.env
|
|
247
|
+
uploads/
|
|
248
|
+
current -> releases/20240102T090000
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
PM2 is reloaded against `current/` after the symlink switch. If the health check fails, you can roll back instantly with `shipnode rollback`.
|
|
252
|
+
|
|
253
|
+
## Requirements
|
|
254
|
+
|
|
255
|
+
**Local:** Node ≥ 18, `rsync`, `ssh`
|
|
256
|
+
|
|
257
|
+
**Server:** Ubuntu/Debian (setup installs everything else via `apt`)
|
|
258
|
+
|
|
259
|
+
## License
|
|
260
|
+
|
|
261
|
+
MIT
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { writeFile, pathExists,
|
|
1
|
+
import { writeFile, pathExists, ensureDir } from 'fs-extra';
|
|
2
2
|
import { resolve } from 'path';
|
|
3
3
|
import { ui } from '../ui.js';
|
|
4
4
|
const ECOSYSTEM_CONFIG = `// ShipNode PM2 Ecosystem — customize and commit this file
|
|
@@ -40,7 +40,7 @@ const CADDYFILE_FRONTEND = `# ShipNode Caddy — frontend static files template
|
|
|
40
40
|
`;
|
|
41
41
|
export async function cmdEject(cwd, target) {
|
|
42
42
|
const templatesDir = resolve(cwd, '.shipnode', 'templates');
|
|
43
|
-
await
|
|
43
|
+
await ensureDir(templatesDir);
|
|
44
44
|
const ejected = [];
|
|
45
45
|
const skipped = [];
|
|
46
46
|
async function writeTemplate(filename, content) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eject.js","sourceRoot":"","sources":["../../../src/cli/commands/eject.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,
|
|
1
|
+
{"version":3,"file":"eject.js","sourceRoot":"","sources":["../../../src/cli/commands/eject.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAC5D,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC/B,OAAO,EAAE,EAAE,EAAE,MAAM,UAAU,CAAC;AAE9B,MAAM,gBAAgB,GAAG;;;;;;;;;;;;;;;CAexB,CAAC;AAEF,MAAM,iBAAiB,GAAG;;;;;;;;;;;CAWzB,CAAC;AAEF,MAAM,kBAAkB,GAAG;;;;;;;;CAQ1B,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,GAAW,EAAE,MAA+B;IACzE,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC;IAC5D,MAAM,SAAS,CAAC,YAAY,CAAC,CAAC;IAE9B,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,KAAK,UAAU,aAAa,CAAC,QAAgB,EAAE,OAAe;QAC5D,MAAM,QAAQ,GAAG,OAAO,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;QACjD,IAAI,MAAM,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC/B,EAAE,CAAC,IAAI,CAAC,YAAY,QAAQ,wBAAwB,CAAC,CAAC;YACtD,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACzB,CAAC;aAAM,CAAC;YACN,MAAM,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;YAC3C,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACzB,CAAC;IACH,CAAC;IAED,IAAI,MAAM,KAAK,KAAK,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;QACzC,MAAM,aAAa,CAAC,sBAAsB,EAAE,gBAAgB,CAAC,CAAC;IAChE,CAAC;IAED,IAAI,MAAM,KAAK,OAAO,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;QAC3C,MAAM,aAAa,CAAC,mBAAmB,EAAE,iBAAiB,CAAC,CAAC;QAC5D,MAAM,aAAa,CAAC,oBAAoB,EAAE,kBAAkB,CAAC,CAAC;IAChE,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,EAAE,CAAC,OAAO,CAAC,4CAA4C,CAAC,CAAC;QACzD,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YACxB,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACpB,CAAC;IACH,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,EAAE,CAAC,IAAI,CAAC,4BAA4B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC5D,CAAC;AACH,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { writeFile,
|
|
1
|
+
import { writeFile, ensureDir, pathExists } from 'fs-extra';
|
|
2
2
|
import { resolve } from 'path';
|
|
3
3
|
import { createInterface } from 'readline';
|
|
4
4
|
import { detectFramework, detectPkgManager } from '../../domain/framework/detector.js';
|
|
@@ -121,7 +121,7 @@ async function getAppName(cwd) {
|
|
|
121
121
|
}
|
|
122
122
|
async function generateShipnodeDir(cwd, detectedOrm) {
|
|
123
123
|
const dir = resolve(cwd, '.shipnode');
|
|
124
|
-
await
|
|
124
|
+
await ensureDir(dir);
|
|
125
125
|
const preDeployPath = resolve(dir, 'pre-deploy.sh');
|
|
126
126
|
const postDeployPath = resolve(dir, 'post-deploy.sh');
|
|
127
127
|
const ignorePath = resolve(cwd, '.shipnodeignore');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"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"}
|