create-paratix 0.2.0 → 0.4.0
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 +56 -319
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,368 +1,105 @@
|
|
|
1
1
|
# create-paratix
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Scaffold a new Paratix server project in a few minutes.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
`create-paratix` is the fastest way to start using Paratix on a real server. Instead of assembling a playbook, scripts, formatting, and bootstrap logic by hand, it gives you a ready-to-run project with a sensible structure and a hardened first-run workflow.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
It is designed for the moment when you already know the server you want to manage, but do not want to rebuild the same setup every time. The scaffold gives you a practical default project, then leaves the actual infrastructure logic in your hands as normal TypeScript.
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
# npm
|
|
11
|
-
npm create paratix my-server
|
|
9
|
+
For fresh machines, it also handles the awkward part that usually gets glossed over: initial SSH access, first-run hardening, switching to a dedicated admin user, and continuing safely from there.
|
|
12
10
|
|
|
13
|
-
|
|
14
|
-
pnpm create paratix my-server
|
|
11
|
+
## Features
|
|
15
12
|
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
- **Project scaffold for Paratix**: generates a ready-to-edit server project instead of just a single file.
|
|
14
|
+
- **First-run bootstrap flow**: supports explicit `--first-run` hardening before later service rollout.
|
|
15
|
+
- **Initial user selection**: works with either a root bootstrap or an existing admin user.
|
|
16
|
+
- **SSH host-key bootstrap**: can pin the current host fingerprint during scaffolding.
|
|
17
|
+
- **DX-friendly TypeScript setup**: direct `tsx` execution, bundler-style module resolution, ESLint, and Prettier included.
|
|
18
|
+
- **Practical project defaults**: scripts, formatting, files directory, env example, and ignore files are created for you.
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
bunx create-paratix my-server
|
|
21
|
-
```
|
|
20
|
+
## Getting Started
|
|
22
21
|
|
|
23
|
-
|
|
22
|
+
Create a new project:
|
|
24
23
|
|
|
25
|
-
```
|
|
24
|
+
```bash
|
|
26
25
|
# npm
|
|
27
|
-
npm create paratix my-server
|
|
26
|
+
npm create paratix my-server
|
|
28
27
|
|
|
29
28
|
# pnpm
|
|
30
|
-
pnpm create paratix my-server
|
|
29
|
+
pnpm create paratix my-server
|
|
31
30
|
|
|
32
31
|
# yarn
|
|
33
|
-
yarn create paratix my-server
|
|
32
|
+
yarn create paratix my-server
|
|
34
33
|
|
|
35
34
|
# bun
|
|
36
|
-
bunx create-paratix my-server
|
|
35
|
+
bunx create-paratix my-server
|
|
37
36
|
```
|
|
38
37
|
|
|
39
|
-
|
|
38
|
+
Then enter the directory and review the generated playbook:
|
|
40
39
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
```sh
|
|
40
|
+
```bash
|
|
44
41
|
cd my-server
|
|
45
42
|
```
|
|
46
43
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
The scaffold also includes an explicit bootstrap switch driven by `PARATIX_FIRST_RUN`:
|
|
50
|
-
|
|
51
|
-
- first run: call `paratix apply ... --first-run`, which sets `PARATIX_FIRST_RUN=true`, keeps SSH on port `22`, opens firewall port `22`, and uses `strictHostKeyChecking: "accept-new"`
|
|
52
|
-
- root bootstrap path: the generated playbook also writes a dedicated `/etc/sudoers.d` drop-in so the new admin user can continue with `NOPASSWD sudo` after the first run
|
|
53
|
-
- later runs: call `paratix apply ...` without `--first-run`, so the generated playbook switches to port `2222`, closes SSH port `22` in the firewall, and returns to strict host-key checking
|
|
54
|
-
- the generated playbook still opens port `2222` before `sshd.port(2222)` runs, so the first real apply can reconnect safely
|
|
55
|
-
- the generated playbook now stops the explicit first run after SSH hardening, kernel hardening, and automatic security upgrades, so later application services run only on the hardened baseline
|
|
56
|
-
|
|
57
|
-
**Step 4 -- Apply**
|
|
58
|
-
|
|
59
|
-
```sh
|
|
60
|
-
# pnpm / yarn / bun
|
|
61
|
-
pnpm apply:dry # dry run first -- see what would change
|
|
62
|
-
pnpm apply # apply to the server
|
|
63
|
-
|
|
64
|
-
# npm
|
|
65
|
-
npm run apply:dry
|
|
66
|
-
npm run apply
|
|
67
|
-
npm run lint
|
|
68
|
-
npm run format:check
|
|
69
|
-
npm run format:fix
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
## Project Structure
|
|
73
|
-
|
|
74
|
-
| File / Directory | Purpose |
|
|
75
|
-
| ------------------ | -------------------------------------------------------------------------------- |
|
|
76
|
-
| `server.ts` | Your playbook. Edit this file. |
|
|
77
|
-
| `package.json` | Includes `apply`, `apply:dry`, `lint`, `format:check`, and `format:fix` scripts. |
|
|
78
|
-
| `tsconfig.json` | TypeScript config (ES2024, ESNext/Bundler, strict) for direct `tsx` use. |
|
|
79
|
-
| `eslint.config.ts` | ESLint config via `eslint-config-setup` for Node-based scaffold projects. |
|
|
80
|
-
| `.prettierrc` | Prettier defaults for the scaffolded project. |
|
|
81
|
-
| `.prettierignore` | Excludes lockfiles from Prettier runs. |
|
|
82
|
-
| `.gitignore` | Excludes `node_modules/`, `dist/`, `.env`, and log files. |
|
|
83
|
-
| `.env.example` | Template for secrets. Copy to `.env` and fill in values. |
|
|
84
|
-
| `files/` | Place template files here. They get uploaded to the server at apply time. |
|
|
85
|
-
|
|
86
|
-
## Writing Your Playbook
|
|
87
|
-
|
|
88
|
-
`server.ts` exports a server definition. The generated file depends on the initial SSH user you choose:
|
|
89
|
-
|
|
90
|
-
- `root`: Bootstrap once via `root`, create a dedicated admin user, then switch `ssh.user` to that admin user and disable root login.
|
|
91
|
-
- `admin`: Connect directly as the named admin user and scaffold the hardened end state immediately.
|
|
92
|
-
|
|
93
|
-
The direct admin-user path looks like this:
|
|
94
|
-
|
|
95
|
-
```typescript
|
|
96
|
-
import { recipe, server } from "paratix"
|
|
97
|
-
import { hostname, net, package as packages, ssh, sshd, ufw, user } from "paratix/modules"
|
|
98
|
-
|
|
99
|
-
const adminUser = "paratix"
|
|
100
|
-
const adminPublicKey = "ssh-ed25519 REPLACE_ME_WITH_YOUR_PUBLIC_KEY"
|
|
101
|
-
const serverName = "my-server"
|
|
102
|
-
const FIRST_RUN = process.env["PARATIX_FIRST_RUN"] === "true"
|
|
103
|
-
const sshPorts = FIRST_RUN ? [22] : [2222]
|
|
104
|
-
const firewallTcpPorts = FIRST_RUN ? [22, 2222, 80, 443] : [2222, 80, 443]
|
|
105
|
-
const strictHostKeyChecking = FIRST_RUN ? "accept-new" : "yes"
|
|
106
|
-
|
|
107
|
-
export default server({
|
|
108
|
-
host: "1.2.3.4",
|
|
109
|
-
name: serverName,
|
|
110
|
-
env: {
|
|
111
|
-
FIRST_RUN,
|
|
112
|
-
SERVER_NAME: serverName,
|
|
113
|
-
SSH_PORT: 2222,
|
|
114
|
-
},
|
|
115
|
-
ssh: {
|
|
116
|
-
ports: sshPorts,
|
|
117
|
-
privateKey: "~/.ssh/id_ed25519", // "~" is expanded by Paratix
|
|
118
|
-
user: adminUser,
|
|
119
|
-
// FIRST_RUN keeps the bootstrap path explicit:
|
|
120
|
-
// - pass `paratix apply ... --first-run` for the bootstrap run
|
|
121
|
-
// - later runs omit that flag and go through port 2222 with strict host-key checking again
|
|
122
|
-
strictHostKeyChecking,
|
|
123
|
-
// expectedHostFingerprint: "SHA256:REPLACE_ME_WITH_YOUR_HOST_FINGERPRINT",
|
|
124
|
-
// expectedHostPublicKey: "ssh-ed25519 REPLACE_ME_WITH_YOUR_HOST_PUBLIC_KEY",
|
|
125
|
-
},
|
|
126
|
-
run: [
|
|
127
|
-
net.hosts("127.0.1.1", [serverName]),
|
|
128
|
-
hostname.set(serverName),
|
|
129
|
-
packages.upgrade("2026-03-01"),
|
|
130
|
-
packages.installed("curl", "htop", "ufw"),
|
|
131
|
-
|
|
132
|
-
recipe("admin-access", [
|
|
133
|
-
user.present(adminUser, {
|
|
134
|
-
groups: ["sudo"],
|
|
135
|
-
shell: "/bin/bash",
|
|
136
|
-
}),
|
|
137
|
-
ssh.authorizedKeys(adminUser, adminPublicKey),
|
|
138
|
-
]),
|
|
139
|
-
|
|
140
|
-
recipe("firewall", [ufw.rule("allow", firewallTcpPorts), ufw.enabled()]),
|
|
141
|
-
|
|
142
|
-
recipe("ssh-hardening", [
|
|
143
|
-
sshd.port(2222),
|
|
144
|
-
sshd.config({
|
|
145
|
-
PasswordAuthentication: "no",
|
|
146
|
-
PermitRootLogin: "no",
|
|
147
|
-
}),
|
|
148
|
-
]),
|
|
149
|
-
|
|
150
|
-
recipe("kernel-hardening", [
|
|
151
|
-
sysctl.set("fs.protected_hardlinks", "1"),
|
|
152
|
-
sysctl.set("fs.protected_symlinks", "1"),
|
|
153
|
-
sysctl.set("kernel.dmesg_restrict", "1"),
|
|
154
|
-
sysctl.set("kernel.kptr_restrict", "2"),
|
|
155
|
-
sysctl.set("net.ipv4.conf.all.rp_filter", "1"),
|
|
156
|
-
sysctl.set("net.ipv4.conf.default.rp_filter", "1"),
|
|
157
|
-
sysctl.set("net.ipv4.tcp_syncookies", "1"),
|
|
158
|
-
]),
|
|
159
|
-
|
|
160
|
-
recipe("automatic-security-upgrades", [
|
|
161
|
-
packages.installed("unattended-upgrades"),
|
|
162
|
-
file.copy("/etc/apt/apt.conf.d/20auto-upgrades", "./files/20auto-upgrades", {
|
|
163
|
-
mode: "0644",
|
|
164
|
-
owner: "root:root",
|
|
165
|
-
}),
|
|
166
|
-
file.copy("/etc/apt/apt.conf.d/50unattended-upgrades", "./files/50unattended-upgrades", {
|
|
167
|
-
mode: "0644",
|
|
168
|
-
owner: "root:root",
|
|
169
|
-
}),
|
|
170
|
-
]),
|
|
171
|
-
|
|
172
|
-
firstRun.stop("Bootstrap foundation complete; rerun without --first-run to continue."),
|
|
173
|
-
|
|
174
|
-
// Add application and user-facing services below this line.
|
|
175
|
-
],
|
|
176
|
-
})
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
The generated `tsconfig.json` is intentionally DX-oriented for `tsx`-executed TypeScript projects:
|
|
180
|
-
|
|
181
|
-
- `module: "ESNext"`
|
|
182
|
-
- `moduleResolution: "Bundler"`
|
|
183
|
-
- `include: ["**/*.ts"]`
|
|
184
|
-
|
|
185
|
-
That means extensionless relative imports in your `.ts` sources work without NodeNext-style `.js` suffixes. This is a deliberate trade-off in favor of authoring ergonomics over strict Node-ESM path checking.
|
|
186
|
-
|
|
187
|
-
The scaffold also includes Prettier out of the box:
|
|
188
|
-
|
|
189
|
-
- `format:check` runs `prettier --check .`
|
|
190
|
-
- `format:fix` runs `prettier --write .`
|
|
191
|
-
- `.prettierignore` excludes lockfiles such as `pnpm-lock.yaml`
|
|
192
|
-
|
|
193
|
-
The scaffold also includes ESLint:
|
|
194
|
-
|
|
195
|
-
- `lint` runs `eslint .`
|
|
196
|
-
- `eslint.config.ts` uses `await getEslintConfig({ node: true })`
|
|
197
|
-
|
|
198
|
-
Wenn dein Server initial nur `root` per SSH anbietet, wähle im Prompt `root` oder rufe das Scaffold nicht-interaktiv mit `--initial-user root` auf. Dieses Template bleibt bewusst als temporärer Bootstrap markiert, erstellt den dedizierten Admin-User, legt einen `NOPASSWD sudo`-Eintrag für ihn unter `/etc/sudoers.d/` an und lässt Root-Login nur vorübergehend auf `prohibit-password`, bis du `ssh.user` auf den Admin-User umgestellt hast.
|
|
199
|
-
|
|
200
|
-
Wenn bereits ein Admin-User wie `deploy`, `ubuntu` oder `admin` existiert, wähle diesen Namen direkt. Dann erzeugt `create-paratix` keinen Root-Bootstrap-Pfad, sondern scaffoldet sofort den gehärteten Zielzustand für genau diesen User.
|
|
201
|
-
|
|
202
|
-
### Initial user selection
|
|
203
|
-
|
|
204
|
-
Standardmäßig fragt `create-paratix` interaktiv:
|
|
205
|
-
|
|
206
|
-
1. Welche Domain oder IP soll als Zielhost in `server.ts` stehen?
|
|
207
|
-
2. Ist der initiale SSH-User `root` oder ein Admin-User?
|
|
208
|
-
3. Falls Admin-User: Wie heißt dieser User konkret?
|
|
209
|
-
4. Soll ein vorhandener Public Key aus `~/.ssh` direkt übernommen werden?
|
|
210
|
-
|
|
211
|
-
Im interaktiven Modus zeigt `create-paratix` dafür eine kurze Erklärung und eine Auswahl per Pfeiltasten:
|
|
212
|
-
|
|
213
|
-
- `Root user`: frischer Server mit SSH nur als `root`; Paratix bootstrapt zuerst einen dedizierten Admin-User
|
|
214
|
-
- `Admin user`: ein konkreter Admin-User existiert bereits; Paratix verbindet sich direkt als dieser User
|
|
215
|
-
|
|
216
|
-
Nicht-interaktiv funktioniert derselbe Vertrag über `--host`, `--initial-user` und optional einen Admin-Public-Key:
|
|
217
|
-
|
|
218
|
-
```sh
|
|
219
|
-
# Root bootstrap
|
|
220
|
-
pnpm create paratix my-server --host example.com --initial-user root --admin-public-key-file ~/.ssh/id_ed25519.pub
|
|
221
|
-
|
|
222
|
-
# Existing admin user
|
|
223
|
-
pnpm create paratix my-server --host deploy.example.com --initial-user deploy --admin-public-key "ssh-ed25519 AAAA... you@example.com"
|
|
224
|
-
```
|
|
225
|
-
|
|
226
|
-
Wichtig für den ersten echten Lauf: Das Scaffold liest `FIRST_RUN` aus `process.env.PARATIX_FIRST_RUN`. Für den Bootstrap rufst du Paratix explizit mit `--first-run` auf. Danach lässt du den Flag bei normalen Läufen weg; dann verwendet dasselbe Playbook Port `2222`, entfernt Port `22` aus der Firewall und kehrt zu strengem Host-Key-Checking zurück. Die Firewall-Freigabe für `2222` bleibt bewusst vor dem eigentlichen SSH-Portwechsel, damit Paratix nach `sshd.port(...)` sofort sicher reconnecten kann.
|
|
227
|
-
|
|
228
|
-
### Public key bootstrap
|
|
229
|
-
|
|
230
|
-
Im interaktiven Modus bietet `create-paratix` zusätzlich an, einen vorhandenen Public Key aus
|
|
231
|
-
`~/.ssh` direkt in `server.ts` zu übernehmen.
|
|
232
|
-
|
|
233
|
-
- Wenn du zustimmst und mehrere `.pub`-Dateien existieren, kannst du den gewünschten Key per
|
|
234
|
-
Pfeiltasten auswählen.
|
|
235
|
-
- Wenn keine lesbaren `.pub`-Dateien gefunden werden, bleibt das bestehende Placeholder-Template
|
|
236
|
-
erhalten.
|
|
237
|
-
- Nicht-interaktiv kannst du denselben Wert über `--admin-public-key` oder
|
|
238
|
-
`--admin-public-key-file` setzen.
|
|
239
|
-
- Wenn kein CLI-Key gesetzt ist, bleibt in nicht-interaktiven Aufrufen weiter der Placeholder
|
|
240
|
-
erhalten.
|
|
241
|
-
|
|
242
|
-
### Host-key bootstrap
|
|
243
|
-
|
|
244
|
-
Paratix verwendet standardmäßig striktes Host-Key-Checking. `create-paratix` bietet deshalb interaktiv an, den aktuell auf SSH-Port `22` präsentierten Host-Key direkt per `ssh2` auszulesen und als `expectedHostFingerprint` in `server.ts` zu pinnen.
|
|
245
|
-
|
|
246
|
-
Wenn du diesen Schritt bestätigst, erzeugt das Scaffold direkt einen expliziten Trust Anchor:
|
|
247
|
-
|
|
248
|
-
```ts
|
|
249
|
-
const strictHostKeyChecking = "yes"
|
|
250
|
-
// ...
|
|
251
|
-
expectedHostFingerprint: "SHA256:..."
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
Das ist ein bewusster TOFU-Schritt beim Scaffold-Zeitpunkt: Der Fingerprint stammt von dem Host-Key, den der Server im Moment des Scaffoldings auf Port `22` präsentiert. Du kannst ihn später jederzeit manuell prüfen oder ersetzen.
|
|
255
|
-
|
|
256
|
-
Wenn du den Abruf ablehnst oder er fehlschlägt, bleibt der bisherige Fallback erhalten:
|
|
257
|
-
|
|
258
|
-
```ts
|
|
259
|
-
const FIRST_RUN = process.env["PARATIX_FIRST_RUN"] === "true"
|
|
260
|
-
const strictHostKeyChecking = FIRST_RUN ? "accept-new" : "yes"
|
|
261
|
-
```
|
|
262
|
-
|
|
263
|
-
Das ist ein bewusst markierter Übergangsmodus für den ersten verifizierten Kontakt mit einem frischen Host. Direkt daneben enthält das generierte `server.ts` weiterhin kommentierte Platzhalter für:
|
|
264
|
-
|
|
265
|
-
- `expectedHostFingerprint`
|
|
266
|
-
- `expectedHostPublicKey`
|
|
267
|
-
|
|
268
|
-
Empfohlener Ablauf:
|
|
269
|
-
|
|
270
|
-
1. Verifiziere den Host-Key deines Servers out of band.
|
|
271
|
-
2. Führe den ersten `apply:dry` und `apply` mit `--first-run` aus.
|
|
272
|
-
3. Führe spätere Runs ohne `--first-run` aus.
|
|
273
|
-
4. Optional: pinne zusätzlich `expectedHostFingerprint` oder `expectedHostPublicKey`.
|
|
274
|
-
|
|
275
|
-
Key concepts:
|
|
44
|
+
Run the bootstrap flow:
|
|
276
45
|
|
|
277
|
-
|
|
278
|
-
- **Recipes** -- `recipe()` groups related modules under a name. If any module in the group changes something, signals fire after the group completes.
|
|
279
|
-
- **Signals** -- actions that run after a recipe when at least one module in it made a change. Useful for reloading services.
|
|
280
|
-
- **Env** -- values in the `env` field are available in template files as `{{KEY}}`. See [Environment Variables](#environment-variables) below.
|
|
281
|
-
|
|
282
|
-
For the full list of built-in modules and their options, see the [Paratix module reference](https://github.com/sebastian-software/paratix).
|
|
283
|
-
|
|
284
|
-
## Applying to a Server
|
|
285
|
-
|
|
286
|
-
Always do a dry run first to see what Paratix would change without touching the server:
|
|
287
|
-
|
|
288
|
-
```sh
|
|
46
|
+
```bash
|
|
289
47
|
pnpm apply:dry
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
Then apply for real:
|
|
293
|
-
|
|
294
|
-
```sh
|
|
48
|
+
pnpm apply --first-run
|
|
295
49
|
pnpm apply
|
|
296
50
|
```
|
|
297
51
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
```sh
|
|
301
|
-
paratix apply server.ts --dry-run
|
|
302
|
-
paratix apply server.ts
|
|
303
|
-
```
|
|
304
|
-
|
|
305
|
-
### CLI flags
|
|
52
|
+
The first run is intentionally staged. It applies the hardened baseline first, then later runs continue with the remaining services and application-specific steps.
|
|
306
53
|
|
|
307
|
-
|
|
308
|
-
| ------------------------------- | -------- | -------------------------------------------------------------------- |
|
|
309
|
-
| `<file>` | required | Path to the playbook file (`.ts` or `.js`). |
|
|
310
|
-
| `--dry-run` | `false` | Check state only. Shows what would change without applying anything. |
|
|
311
|
-
| `--env <key=value>` | `{}` | Set or override an env value. Repeatable: `--env A=1 --env B=2`. |
|
|
312
|
-
| `--env-file <path>` | -- | Load a `.env` file. |
|
|
313
|
-
| `--reconnect-timeout <seconds>` | `300` | Seconds to wait for SSH reconnect after a port or reboot change. |
|
|
314
|
-
| `--verbose` | `false` | Show full stack traces on errors. |
|
|
54
|
+
## What You Get
|
|
315
55
|
|
|
316
|
-
|
|
56
|
+
The scaffolded project includes:
|
|
317
57
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
58
|
+
| File / Directory | Purpose |
|
|
59
|
+
| --------------------------------- | ----------------------------------------------------------- |
|
|
60
|
+
| `server.ts` | Your Paratix playbook |
|
|
61
|
+
| `files/` | Templates and configuration files to upload |
|
|
62
|
+
| `package.json` | Apply, lint, and formatting scripts |
|
|
63
|
+
| `tsconfig.json` | TypeScript config for direct `tsx` execution |
|
|
64
|
+
| `eslint.config.ts` | ESLint config using `await getEslintConfig({ node: true })` |
|
|
65
|
+
| `.prettierrc` / `.prettierignore` | Formatting defaults, including lockfile ignores |
|
|
66
|
+
| `.env.example` | Starting point for environment values |
|
|
321
67
|
|
|
322
|
-
##
|
|
68
|
+
## Bootstrap Model
|
|
323
69
|
|
|
324
|
-
|
|
70
|
+
`create-paratix` supports two entry paths:
|
|
325
71
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
```
|
|
72
|
+
- **Root bootstrap**: for a fresh server that still only accepts SSH as `root`
|
|
73
|
+
- **Admin-user bootstrap**: for a server where a dedicated admin user already exists
|
|
329
74
|
|
|
330
|
-
The
|
|
331
|
-
|
|
332
|
-
```sh
|
|
333
|
-
# Server configuration
|
|
334
|
-
# SUDO_PASSWORD=your-sudo-password
|
|
335
|
-
# SSH_KEY_PATH=~/.ssh/id_ed25519
|
|
336
|
-
```
|
|
75
|
+
The generated project keeps this explicit:
|
|
337
76
|
|
|
338
|
-
|
|
77
|
+
- `paratix apply ... --first-run` stays on port `22`, completes the hardened bootstrap stage, and stops intentionally at the first-run checkpoint
|
|
78
|
+
- later runs use the hardened path, usually on port `2222`, with strict host-key checking again
|
|
339
79
|
|
|
340
|
-
|
|
341
|
-
2. The `env` field in `server()`
|
|
342
|
-
3. `--env <key=value>` flags -- these have the highest priority
|
|
80
|
+
When you scaffold interactively, the CLI can also:
|
|
343
81
|
|
|
344
|
-
|
|
82
|
+
- select an admin public key from `~/.ssh`
|
|
83
|
+
- pin the current host key from SSH port `22` as `expectedHostFingerprint`
|
|
345
84
|
|
|
346
|
-
|
|
85
|
+
## Non-Interactive Usage
|
|
347
86
|
|
|
348
|
-
|
|
87
|
+
You can provide the important bootstrap values on the command line:
|
|
349
88
|
|
|
350
|
-
```
|
|
351
|
-
|
|
89
|
+
```bash
|
|
90
|
+
pnpm create paratix my-server --host example.com --initial-user root --admin-public-key-file ~/.ssh/id_ed25519.pub
|
|
352
91
|
```
|
|
353
92
|
|
|
354
|
-
|
|
355
|
-
server {
|
|
356
|
-
server_name {{SERVER_NAME}};
|
|
357
|
-
}
|
|
358
|
-
```
|
|
93
|
+
Or for an existing admin user:
|
|
359
94
|
|
|
360
|
-
|
|
95
|
+
```bash
|
|
96
|
+
pnpm create paratix my-server --host deploy.example.com --initial-user deploy --admin-public-key "ssh-ed25519 AAAA... you@example.com"
|
|
97
|
+
```
|
|
361
98
|
|
|
362
|
-
##
|
|
99
|
+
## After Scaffolding
|
|
363
100
|
|
|
364
|
-
|
|
101
|
+
Edit `server.ts` and extend the generated baseline with your own services, files, deployments, and runtime configuration. The scaffold is meant to get you to a safe and productive starting point quickly, not to lock you into a fixed project shape.
|
|
365
102
|
|
|
366
103
|
## License
|
|
367
104
|
|
|
368
|
-
MIT
|
|
105
|
+
MIT — Copyright 2026 [Sebastian Software GmbH](https://sebastian-software.com)
|