quicklify 0.5.0 โ†’ 0.7.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.
Files changed (38) hide show
  1. package/README.md +99 -10
  2. package/dist/commands/doctor.d.ts +10 -0
  3. package/dist/commands/doctor.d.ts.map +1 -0
  4. package/dist/commands/doctor.js +92 -0
  5. package/dist/commands/doctor.js.map +1 -0
  6. package/dist/commands/domain.d.ts +13 -0
  7. package/dist/commands/domain.d.ts.map +1 -0
  8. package/dist/commands/domain.js +218 -0
  9. package/dist/commands/domain.js.map +1 -0
  10. package/dist/commands/firewall.d.ts +15 -0
  11. package/dist/commands/firewall.d.ts.map +1 -0
  12. package/dist/commands/firewall.js +259 -0
  13. package/dist/commands/firewall.js.map +1 -0
  14. package/dist/commands/health.d.ts +9 -0
  15. package/dist/commands/health.d.ts.map +1 -0
  16. package/dist/commands/health.js +56 -0
  17. package/dist/commands/health.js.map +1 -0
  18. package/dist/commands/logs.d.ts +8 -0
  19. package/dist/commands/logs.d.ts.map +1 -0
  20. package/dist/commands/logs.js +53 -0
  21. package/dist/commands/logs.js.map +1 -0
  22. package/dist/commands/monitor.d.ts +13 -0
  23. package/dist/commands/monitor.d.ts.map +1 -0
  24. package/dist/commands/monitor.js +94 -0
  25. package/dist/commands/monitor.js.map +1 -0
  26. package/dist/commands/secure.d.ts +14 -0
  27. package/dist/commands/secure.d.ts.map +1 -0
  28. package/dist/commands/secure.js +294 -0
  29. package/dist/commands/secure.js.map +1 -0
  30. package/dist/index.js +45 -0
  31. package/dist/index.js.map +1 -1
  32. package/dist/types/index.d.ts +25 -0
  33. package/dist/types/index.d.ts.map +1 -1
  34. package/dist/utils/ssh.d.ts +1 -0
  35. package/dist/utils/ssh.d.ts.map +1 -1
  36. package/dist/utils/ssh.js +7 -0
  37. package/dist/utils/ssh.js.map +1 -1
  38. package/package.json +1 -1
package/README.md CHANGED
@@ -50,6 +50,14 @@ npx quicklify init
50
50
  - ๐Ÿ”‘ **SSH Access** - Connect to servers or run remote commands
51
51
  - ๐Ÿ”„ **Coolify Update** - Update Coolify with one command
52
52
  - ๐Ÿฅ **Health Check Polling** - Detects when Coolify is ready (no more blind waiting)
53
+ - ๐Ÿ“Š **Server Monitoring** - CPU/RAM/Disk usage and Docker container status
54
+ - ๐Ÿ“œ **Log Viewer** - View Coolify, Docker, or system logs with follow mode
55
+ - ๐Ÿฉบ **Environment Doctor** - Diagnose local setup issues
56
+ - ๐Ÿซ€ **Bulk Health Check** - Check all servers at once
57
+ - ๐Ÿ”ฅ **Firewall Management** - UFW setup, add/remove ports, protected port safety
58
+ - ๐ŸŒ **Domain Management** - Bind domains, DNS check, auto SSL via Coolify
59
+ - ๐Ÿ›ก๏ธ **SSH Hardening** - Disable password auth, fail2ban, security audit with score
60
+ - ๐Ÿงช **Dry-Run Mode** - Preview commands on firewall/domain/secure before executing
53
61
  - ๐Ÿค– **Non-Interactive Mode** - CI/CD friendly with `--provider --token --region --size --name` flags
54
62
 
55
63
  ## ๐Ÿ“ฆ Installation
@@ -116,12 +124,12 @@ Visit the URL, create your admin account, and start deploying!
116
124
  **Important:** Port 8000 is publicly accessible after deployment.
117
125
 
118
126
  **Recommended next steps:**
119
- 1. **Add a domain** and enable SSL in Coolify settings
120
- 2. Use **Cloudflare** for DDoS protection
121
- 3. Set a **strong password** on first login
122
- 4. Consider **IP whitelisting** for sensitive deployments
123
-
124
- For production use, we recommend setting up a domain instead of using the IP address directly.
127
+ 1. **Setup firewall:** `quicklify firewall setup my-server`
128
+ 2. **Add a domain:** `quicklify domain add my-server --domain example.com`
129
+ 3. **Harden SSH:** `quicklify secure setup my-server`
130
+ 4. **Run security audit:** `quicklify secure audit my-server`
131
+ 5. Set a **strong password** on first login
132
+ 6. Consider **Cloudflare** for DDoS protection
125
133
 
126
134
  ## ๐ŸŒ Supported Providers
127
135
 
@@ -162,6 +170,22 @@ For production use, we recommend setting up a domain instead of using the IP add
162
170
 
163
171
  ## ๐Ÿ“‹ Recent Updates
164
172
 
173
+ ### v0.7.0 (2026-02-20)
174
+ - **New commands:** `quicklify firewall`, `quicklify domain`, `quicklify secure`
175
+ - **Firewall management:** UFW setup, add/remove ports, protected port 22 safety, Coolify port warnings
176
+ - **Domain management:** Bind domains to Coolify, DNS A record check, auto SSL
177
+ - **SSH hardening:** Disable password auth, key-only root login, fail2ban, security audit with 0-4 score
178
+ - **Dry-run mode:** `--dry-run` flag previews all commands without executing
179
+ - Zero new dependencies, 494 tests with 97%+ statement coverage
180
+
181
+ ### v0.6.0 (2026-02-20)
182
+ - **New commands:** `quicklify logs`, `quicklify monitor`, `quicklify health`, `quicklify doctor`
183
+ - **Log viewer:** View Coolify/Docker/system logs with `--follow` real-time streaming
184
+ - **Server monitoring:** CPU/RAM/Disk usage and Docker container list
185
+ - **Bulk health check:** Check all registered servers at once with response times
186
+ - **Environment doctor:** Diagnose Node.js, SSH, config issues locally
187
+ - Zero new dependencies, 354 tests with 97%+ statement coverage
188
+
165
189
  ### v0.5.0 (2026-02-20)
166
190
  - **New commands:** `quicklify config`, `quicklify ssh`, `quicklify update`, `quicklify restart`
167
191
  - **Default config:** Set defaults for provider, region, size with `quicklify config set`
@@ -238,14 +262,26 @@ For production use, we recommend setting up a domain instead of using the IP add
238
262
  - [x] Server restart via provider API (`quicklify restart`)
239
263
  - [x] Shared server selection and token utilities (DRY refactor)
240
264
 
265
+ ### v0.6.0 (Completed)
266
+
267
+ - [x] Server monitoring - CPU/RAM/Disk usage (`quicklify monitor`)
268
+ - [x] Log viewer - Coolify/Docker/system logs (`quicklify logs`)
269
+ - [x] Bulk health check for all servers (`quicklify health`)
270
+ - [x] Environment diagnostics (`quicklify doctor`)
271
+ - [x] SSH streaming for real-time log following
272
+
273
+ ### v0.7.0 (Completed)
274
+
275
+ - [x] Firewall management - UFW setup, add/remove ports (`quicklify firewall`)
276
+ - [x] Domain management - Bind domains, DNS check, SSL (`quicklify domain`)
277
+ - [x] SSH hardening - Password disable, fail2ban, security audit (`quicklify secure`)
278
+ - [x] Dry-run mode for all security commands
279
+
241
280
  ### Future
242
281
  - [ ] Vultr support
243
282
  - [ ] Linode / AWS Lightsail support
244
- - [ ] Domain + SSL configuration helper
245
283
  - [ ] Backup/restore commands
246
- - [ ] Server monitoring (CPU/RAM/Disk)
247
284
  - [ ] Interactive TUI dashboard
248
- - [ ] Firewall management
249
285
 
250
286
  ## ๐Ÿ› ๏ธ Tech Stack
251
287
 
@@ -298,6 +334,52 @@ quicklify update my-server
298
334
  # Restart a server
299
335
  quicklify restart my-server
300
336
 
337
+ # View Coolify logs (last 50 lines)
338
+ quicklify logs my-server
339
+
340
+ # Follow Coolify logs in real-time
341
+ quicklify logs my-server --follow
342
+
343
+ # View Docker or system logs
344
+ quicklify logs my-server --service docker --lines 100
345
+ quicklify logs my-server --service system
346
+
347
+ # Show CPU/RAM/Disk usage
348
+ quicklify monitor my-server
349
+
350
+ # Show usage with Docker containers
351
+ quicklify monitor my-server --containers
352
+
353
+ # Check health of all servers
354
+ quicklify health
355
+
356
+ # Run environment diagnostics
357
+ quicklify doctor
358
+
359
+ # Firewall management
360
+ quicklify firewall setup my-server # Install UFW + Coolify ports
361
+ quicklify firewall add my-server --port 3000 # Open port 3000/tcp
362
+ quicklify firewall add my-server --port 53 --protocol udp # Open port 53/udp
363
+ quicklify firewall remove my-server --port 3000 # Close port 3000
364
+ quicklify firewall list my-server # Show firewall rules
365
+ quicklify firewall status my-server # Check UFW active/inactive
366
+ quicklify firewall setup my-server --dry-run # Preview without executing
367
+
368
+ # Domain management
369
+ quicklify domain add my-server --domain example.com # Bind domain + HTTPS
370
+ quicklify domain add my-server --domain example.com --no-ssl # HTTP only
371
+ quicklify domain remove my-server # Revert to IP:8000
372
+ quicklify domain check my-server --domain example.com # Verify DNS
373
+ quicklify domain list my-server # Show current domain
374
+ quicklify domain add my-server --domain example.com --dry-run # Preview
375
+
376
+ # SSH hardening & security
377
+ quicklify secure status my-server # Show security settings
378
+ quicklify secure audit my-server # Security score (0-4)
379
+ quicklify secure setup my-server # Harden SSH + install fail2ban
380
+ quicklify secure setup my-server --port 2222 # Change SSH port
381
+ quicklify secure setup my-server --dry-run # Preview without executing
382
+
301
383
  # Show version
302
384
  quicklify --version
303
385
 
@@ -378,13 +460,20 @@ tests/
378
460
  โ”‚ โ”œโ”€โ”€ config-command.test.ts # Config command subcommands
379
461
  โ”‚ โ”œโ”€โ”€ defaults.test.ts # Default config CRUD
380
462
  โ”‚ โ”œโ”€โ”€ destroy.test.ts # Destroy command unit tests
463
+ โ”‚ โ”œโ”€โ”€ doctor.test.ts # Doctor command tests
464
+ โ”‚ โ”œโ”€โ”€ domain.test.ts # Domain command tests
465
+ โ”‚ โ”œโ”€โ”€ firewall.test.ts # Firewall command tests
466
+ โ”‚ โ”œโ”€โ”€ health-command.test.ts # Health command tests
381
467
  โ”‚ โ”œโ”€โ”€ healthCheck.test.ts # Health check polling tests
382
468
  โ”‚ โ”œโ”€โ”€ healthCheck-edge.test.ts # Health check edge cases (302, 401, 500)
383
469
  โ”‚ โ”œโ”€โ”€ list.test.ts # List command unit tests
384
470
  โ”‚ โ”œโ”€โ”€ logger.test.ts
471
+ โ”‚ โ”œโ”€โ”€ logs.test.ts # Logs command tests
472
+ โ”‚ โ”œโ”€โ”€ monitor.test.ts # Monitor command tests
385
473
  โ”‚ โ”œโ”€โ”€ prompts.test.ts
386
474
  โ”‚ โ”œโ”€โ”€ providerFactory.test.ts # Provider factory tests
387
475
  โ”‚ โ”œโ”€โ”€ restart.test.ts # Restart command tests
476
+ โ”‚ โ”œโ”€โ”€ secure.test.ts # Secure command tests
388
477
  โ”‚ โ”œโ”€โ”€ serverSelect.test.ts # Server selection utility tests
389
478
  โ”‚ โ”œโ”€โ”€ ssh-command.test.ts # SSH command tests
390
479
  โ”‚ โ”œโ”€โ”€ ssh-utils.test.ts # SSH helper tests
@@ -410,7 +499,7 @@ Tests run automatically on every push/PR via GitHub Actions across:
410
499
 
411
500
  ### Coverage
412
501
 
413
- Current coverage: **97%+ statements/lines**, **88%+ branches**, **97%+ functions**. 311 tests across 25 test suites.
502
+ Current coverage: **97%+ statements/lines**, **85%+ branches**, **96%+ functions**. 494 tests across 32 test suites.
414
503
 
415
504
  ## ๐Ÿ”ง Troubleshooting
416
505
 
@@ -0,0 +1,10 @@
1
+ export interface CheckResult {
2
+ name: string;
3
+ status: "pass" | "fail" | "warn";
4
+ detail: string;
5
+ }
6
+ export declare function runDoctorChecks(version?: string): CheckResult[];
7
+ export declare function doctorCommand(options?: {
8
+ checkTokens?: boolean;
9
+ }, version?: string): Promise<void>;
10
+ //# sourceMappingURL=doctor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IACjC,MAAM,EAAE,MAAM,CAAC;CAChB;AAsDD,wBAAgB,eAAe,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,WAAW,EAAE,CAS/D;AAED,wBAAsB,aAAa,CACjC,OAAO,CAAC,EAAE;IAAE,WAAW,CAAC,EAAE,OAAO,CAAA;CAAE,EACnC,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CA8Bf"}
@@ -0,0 +1,92 @@
1
+ import { execSync } from "child_process";
2
+ import { existsSync, accessSync, constants } from "fs";
3
+ import { getServers } from "../utils/config.js";
4
+ import { checkSshAvailable } from "../utils/ssh.js";
5
+ import { logger } from "../utils/logger.js";
6
+ import { CONFIG_DIR } from "../utils/config.js";
7
+ function checkNodeVersion() {
8
+ const version = process.version;
9
+ const major = parseInt(version.slice(1).split(".")[0], 10);
10
+ if (major >= 20) {
11
+ return { name: "Node.js", status: "pass", detail: version };
12
+ }
13
+ return { name: "Node.js", status: "fail", detail: `${version} (requires >= 20)` };
14
+ }
15
+ function checkNpmVersion() {
16
+ try {
17
+ const version = execSync("npm --version", { stdio: "pipe" }).toString().trim();
18
+ return { name: "npm", status: "pass", detail: `v${version}` };
19
+ }
20
+ catch {
21
+ return { name: "npm", status: "fail", detail: "not found" };
22
+ }
23
+ }
24
+ function checkSsh() {
25
+ if (checkSshAvailable()) {
26
+ return { name: "SSH Client", status: "pass", detail: "available" };
27
+ }
28
+ return { name: "SSH Client", status: "warn", detail: "not found (needed for ssh/logs/monitor/update)" };
29
+ }
30
+ function checkQuicklifyVersion(version) {
31
+ if (version) {
32
+ return { name: "quicklify", status: "pass", detail: `v${version}` };
33
+ }
34
+ return { name: "quicklify", status: "warn", detail: "version unknown" };
35
+ }
36
+ function checkConfigDir() {
37
+ if (!existsSync(CONFIG_DIR)) {
38
+ return { name: "Config Dir", status: "warn", detail: `${CONFIG_DIR} (not created yet)` };
39
+ }
40
+ try {
41
+ accessSync(CONFIG_DIR, constants.R_OK | constants.W_OK);
42
+ return { name: "Config Dir", status: "pass", detail: CONFIG_DIR };
43
+ }
44
+ catch {
45
+ return { name: "Config Dir", status: "fail", detail: `${CONFIG_DIR} (not writable)` };
46
+ }
47
+ }
48
+ function checkRegisteredServers() {
49
+ const servers = getServers();
50
+ if (servers.length === 0) {
51
+ return { name: "Servers", status: "warn", detail: "0 registered (run quicklify init)" };
52
+ }
53
+ return { name: "Servers", status: "pass", detail: `${servers.length} registered` };
54
+ }
55
+ export function runDoctorChecks(version) {
56
+ return [
57
+ checkNodeVersion(),
58
+ checkNpmVersion(),
59
+ checkSsh(),
60
+ checkQuicklifyVersion(version),
61
+ checkConfigDir(),
62
+ checkRegisteredServers(),
63
+ ];
64
+ }
65
+ export async function doctorCommand(options, version) {
66
+ logger.title("Quicklify Doctor");
67
+ const results = runDoctorChecks(version);
68
+ for (const result of results) {
69
+ const colorFn = result.status === "pass"
70
+ ? logger.success
71
+ : result.status === "warn"
72
+ ? logger.warning
73
+ : logger.error;
74
+ colorFn(`${result.name}: ${result.detail}`);
75
+ }
76
+ const failures = results.filter((r) => r.status === "fail");
77
+ const warnings = results.filter((r) => r.status === "warn");
78
+ console.log();
79
+ if (failures.length > 0) {
80
+ logger.error(`${failures.length} check(s) failed. Please fix the issues above.`);
81
+ }
82
+ else if (warnings.length > 0) {
83
+ logger.warning(`All checks passed with ${warnings.length} warning(s).`);
84
+ }
85
+ else {
86
+ logger.success("All checks passed! Your environment is ready.");
87
+ }
88
+ if (options?.checkTokens) {
89
+ logger.info("Token validation is not yet implemented.");
90
+ }
91
+ }
92
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export declare function isValidDomain(domain: string): boolean;
2
+ export declare function sanitizeDomain(input: string): string;
3
+ export declare function buildSetFqdnCommand(domain: string, ssl: boolean): string;
4
+ export declare function buildGetFqdnCommand(): string;
5
+ export declare function buildDnsCheckCommand(domain: string): string;
6
+ export declare function parseDnsResult(stdout: string): string | null;
7
+ export declare function parseFqdn(stdout: string): string | null;
8
+ export declare function domainCommand(subcommand?: string, query?: string, options?: {
9
+ domain?: string;
10
+ ssl?: boolean;
11
+ dryRun?: boolean;
12
+ }): Promise<void>;
13
+ //# sourceMappingURL=domain.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"domain.d.ts","sourceRoot":"","sources":["../../src/commands/domain.ts"],"names":[],"mappings":"AAMA,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAIrD;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CASpD;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,GAAG,MAAM,CAIxE;AAED,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAI5D;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAIvD;AAED,wBAAsB,aAAa,CACjC,UAAU,CAAC,EAAE,MAAM,EACnB,KAAK,CAAC,EAAE,MAAM,EACd,OAAO,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GAC7D,OAAO,CAAC,IAAI,CAAC,CAiCf"}
@@ -0,0 +1,218 @@
1
+ import { resolveServer } from "../utils/serverSelect.js";
2
+ import { checkSshAvailable, sshExec } from "../utils/ssh.js";
3
+ import { logger, createSpinner } from "../utils/logger.js";
4
+ const COOLIFY_ENV_PATH = "/data/coolify/source/.env";
5
+ export function isValidDomain(domain) {
6
+ // RFC 1035 compliant domain validation
7
+ const pattern = /^(?!-)[a-zA-Z0-9-]{1,63}(?<!-)(\.[a-zA-Z0-9-]{1,63})*\.[a-zA-Z]{2,}$/;
8
+ return pattern.test(domain);
9
+ }
10
+ export function sanitizeDomain(input) {
11
+ let domain = input.trim();
12
+ // Strip protocol prefix
13
+ domain = domain.replace(/^https?:\/\//, "");
14
+ // Strip trailing slash
15
+ domain = domain.replace(/\/+$/, "");
16
+ // Strip port
17
+ domain = domain.replace(/:\d+$/, "");
18
+ return domain;
19
+ }
20
+ export function buildSetFqdnCommand(domain, ssl) {
21
+ const protocol = ssl ? "https" : "http";
22
+ const url = `${protocol}://${domain}`;
23
+ return `sed -i 's|^APP_URL=.*|APP_URL=${url}|' ${COOLIFY_ENV_PATH} && cd /data/coolify/source && docker compose up -d --force-recreate`;
24
+ }
25
+ export function buildGetFqdnCommand() {
26
+ return `grep '^APP_URL=' ${COOLIFY_ENV_PATH}`;
27
+ }
28
+ export function buildDnsCheckCommand(domain) {
29
+ return `dig +short A ${domain} 2>/dev/null || host -t A ${domain} 2>/dev/null || nslookup ${domain} 2>/dev/null`;
30
+ }
31
+ export function parseDnsResult(stdout) {
32
+ // dig +short returns just IP addresses
33
+ const ipMatch = stdout.match(/\b(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\b/);
34
+ return ipMatch ? ipMatch[1] : null;
35
+ }
36
+ export function parseFqdn(stdout) {
37
+ const match = stdout.match(/^APP_URL=(.+)$/m);
38
+ if (!match)
39
+ return null;
40
+ return match[1].trim();
41
+ }
42
+ export async function domainCommand(subcommand, query, options) {
43
+ if (!checkSshAvailable()) {
44
+ logger.error("SSH client not found. Please install OpenSSH.");
45
+ return;
46
+ }
47
+ const validSubcommands = ["add", "remove", "check", "list"];
48
+ const sub = subcommand || "list";
49
+ if (!validSubcommands.includes(sub)) {
50
+ logger.error(`Invalid subcommand: ${sub}. Choose from: ${validSubcommands.join(", ")}`);
51
+ return;
52
+ }
53
+ const server = await resolveServer(query, "Select a server for domain management:");
54
+ if (!server)
55
+ return;
56
+ const dryRun = options?.dryRun || false;
57
+ switch (sub) {
58
+ case "add":
59
+ await domainAdd(server.ip, server.name, options, dryRun);
60
+ break;
61
+ case "remove":
62
+ await domainRemove(server.ip, server.name, dryRun);
63
+ break;
64
+ case "check":
65
+ await domainCheck(server.ip, options);
66
+ break;
67
+ case "list":
68
+ await domainList(server.ip, server.name);
69
+ break;
70
+ }
71
+ }
72
+ async function domainAdd(ip, name, options, dryRun) {
73
+ if (!options?.domain) {
74
+ logger.error("Missing --domain. Usage: quicklify domain add <server> --domain example.com");
75
+ return;
76
+ }
77
+ const domain = sanitizeDomain(options.domain);
78
+ if (!isValidDomain(domain)) {
79
+ logger.error(`Invalid domain: ${domain}`);
80
+ return;
81
+ }
82
+ const ssl = options?.ssl !== false; // default true
83
+ const command = buildSetFqdnCommand(domain, ssl);
84
+ if (dryRun) {
85
+ logger.title("Dry Run - Add Domain");
86
+ logger.info(`Server: ${name} (${ip})`);
87
+ logger.info(`Domain: ${domain}`);
88
+ logger.info(`SSL: ${ssl ? "enabled" : "disabled"}`);
89
+ console.log();
90
+ logger.info("Commands to execute:");
91
+ for (const cmd of command.split(" && ")) {
92
+ logger.step(cmd);
93
+ }
94
+ console.log();
95
+ logger.warning("No changes applied. Remove --dry-run to execute.");
96
+ return;
97
+ }
98
+ const spinner = createSpinner(`Setting domain to ${domain}...`);
99
+ spinner.start();
100
+ try {
101
+ // Check if .env file exists
102
+ const checkResult = await sshExec(ip, `test -f ${COOLIFY_ENV_PATH} && echo "exists"`);
103
+ if (!checkResult.stdout.includes("exists")) {
104
+ spinner.fail("Coolify environment file not found");
105
+ logger.error(`Expected: ${COOLIFY_ENV_PATH}`);
106
+ logger.info("Is Coolify installed on this server?");
107
+ return;
108
+ }
109
+ const result = await sshExec(ip, command);
110
+ if (result.code !== 0) {
111
+ spinner.fail("Failed to set domain");
112
+ if (result.stderr)
113
+ logger.error(result.stderr);
114
+ return;
115
+ }
116
+ spinner.succeed(`Domain set to ${domain} on ${name}`);
117
+ const protocol = ssl ? "https" : "http";
118
+ logger.success(`Coolify is now accessible at ${protocol}://${domain}`);
119
+ logger.info("Make sure your DNS A record points to " + ip);
120
+ }
121
+ catch (error) {
122
+ spinner.fail("Failed to set domain");
123
+ logger.error(error instanceof Error ? error.message : String(error));
124
+ }
125
+ }
126
+ async function domainRemove(ip, name, dryRun) {
127
+ const command = buildSetFqdnCommand(`${ip}:8000`, false);
128
+ if (dryRun) {
129
+ logger.title("Dry Run - Remove Domain");
130
+ logger.info(`Server: ${name} (${ip})`);
131
+ logger.info(`Will reset to: http://${ip}:8000`);
132
+ console.log();
133
+ logger.info("Commands to execute:");
134
+ for (const cmd of command.split(" && ")) {
135
+ logger.step(cmd);
136
+ }
137
+ console.log();
138
+ logger.warning("No changes applied. Remove --dry-run to execute.");
139
+ return;
140
+ }
141
+ const spinner = createSpinner("Removing domain...");
142
+ spinner.start();
143
+ try {
144
+ const result = await sshExec(ip, command);
145
+ if (result.code !== 0) {
146
+ spinner.fail("Failed to remove domain");
147
+ if (result.stderr)
148
+ logger.error(result.stderr);
149
+ return;
150
+ }
151
+ spinner.succeed(`Domain removed from ${name}`);
152
+ logger.success(`Coolify is now accessible at http://${ip}:8000`);
153
+ }
154
+ catch (error) {
155
+ spinner.fail("Failed to remove domain");
156
+ logger.error(error instanceof Error ? error.message : String(error));
157
+ }
158
+ }
159
+ async function domainCheck(ip, options) {
160
+ if (!options?.domain) {
161
+ logger.error("Missing --domain. Usage: quicklify domain check <server> --domain example.com");
162
+ return;
163
+ }
164
+ const domain = sanitizeDomain(options.domain);
165
+ if (!isValidDomain(domain)) {
166
+ logger.error(`Invalid domain: ${domain}`);
167
+ return;
168
+ }
169
+ const spinner = createSpinner(`Checking DNS for ${domain}...`);
170
+ spinner.start();
171
+ try {
172
+ const result = await sshExec(ip, buildDnsCheckCommand(domain));
173
+ const resolvedIp = parseDnsResult(result.stdout);
174
+ if (!resolvedIp) {
175
+ spinner.fail(`No A record found for ${domain}`);
176
+ logger.info("Add an A record pointing to " + ip);
177
+ return;
178
+ }
179
+ if (resolvedIp === ip) {
180
+ spinner.succeed(`DNS OK: ${domain} โ†’ ${resolvedIp}`);
181
+ }
182
+ else {
183
+ spinner.warn(`DNS mismatch: ${domain} โ†’ ${resolvedIp} (expected ${ip})`);
184
+ logger.info("Update your A record to point to " + ip);
185
+ }
186
+ }
187
+ catch (error) {
188
+ spinner.fail("Failed to check DNS");
189
+ logger.error(error instanceof Error ? error.message : String(error));
190
+ }
191
+ }
192
+ async function domainList(ip, name) {
193
+ const spinner = createSpinner(`Fetching domain from ${name}...`);
194
+ spinner.start();
195
+ try {
196
+ const result = await sshExec(ip, buildGetFqdnCommand());
197
+ if (result.code !== 0) {
198
+ spinner.fail("Failed to fetch domain");
199
+ if (result.stderr)
200
+ logger.error(result.stderr);
201
+ return;
202
+ }
203
+ const fqdn = parseFqdn(result.stdout);
204
+ if (fqdn) {
205
+ spinner.succeed(`Current domain for ${name}`);
206
+ logger.info(`APP_URL: ${fqdn}`);
207
+ }
208
+ else {
209
+ spinner.succeed(`No custom domain set for ${name}`);
210
+ logger.info(`Default: http://${ip}:8000`);
211
+ }
212
+ }
213
+ catch (error) {
214
+ spinner.fail("Failed to fetch domain");
215
+ logger.error(error instanceof Error ? error.message : String(error));
216
+ }
217
+ }
218
+ //# sourceMappingURL=domain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"domain.js","sourceRoot":"","sources":["../../src/commands/domain.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { FirewallStatus, FirewallProtocol } from "../types/index.js";
2
+ export declare const PROTECTED_PORTS: number[];
3
+ export declare const COOLIFY_PORTS: number[];
4
+ export declare function isValidPort(port: number): boolean;
5
+ export declare function isProtectedPort(port: number): boolean;
6
+ export declare function buildUfwRuleCommand(action: "allow" | "delete allow", port: number, protocol?: FirewallProtocol): string;
7
+ export declare function buildFirewallSetupCommand(): string;
8
+ export declare function buildUfwStatusCommand(): string;
9
+ export declare function parseUfwStatus(stdout: string): FirewallStatus;
10
+ export declare function firewallCommand(subcommand?: string, query?: string, options?: {
11
+ port?: string;
12
+ protocol?: string;
13
+ dryRun?: boolean;
14
+ }): Promise<void>;
15
+ //# sourceMappingURL=firewall.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"firewall.d.ts","sourceRoot":"","sources":["../../src/commands/firewall.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAgB,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAExF,eAAO,MAAM,eAAe,UAAO,CAAC;AACpC,eAAO,MAAM,aAAa,UAA8B,CAAC;AAEzD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAErD;AAED,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,OAAO,GAAG,cAAc,EAChC,IAAI,EAAE,MAAM,EACZ,QAAQ,GAAE,gBAAwB,GACjC,MAAM,CAER;AAED,wBAAgB,yBAAyB,IAAI,MAAM,CAUlD;AAED,wBAAgB,qBAAqB,IAAI,MAAM,CAE9C;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,CAmB7D;AAED,wBAAsB,eAAe,CACnC,UAAU,CAAC,EAAE,MAAM,EACnB,KAAK,CAAC,EAAE,MAAM,EACd,OAAO,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GAC/D,OAAO,CAAC,IAAI,CAAC,CAoCf"}