suthep 0.1.0-beta.1 → 0.2.0-beta.1
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 +167 -69
- package/dist/commands/down.js +179 -0
- package/dist/commands/down.js.map +1 -0
- package/dist/commands/redeploy.js +59 -0
- package/dist/commands/redeploy.js.map +1 -0
- package/dist/commands/up.js +213 -0
- package/dist/commands/up.js.map +1 -0
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -1
- package/dist/utils/deployment.js +10 -1
- package/dist/utils/deployment.js.map +1 -1
- package/dist/utils/docker.js +35 -0
- package/dist/utils/docker.js.map +1 -1
- package/dist/utils/nginx.js +10 -0
- package/dist/utils/nginx.js.map +1 -1
- package/docs/README.md +25 -82
- package/docs/english/01-introduction.md +84 -0
- package/docs/english/02-installation.md +200 -0
- package/docs/english/03-quick-start.md +256 -0
- package/docs/english/04-configuration.md +358 -0
- package/docs/english/05-commands.md +363 -0
- package/docs/english/06-examples.md +456 -0
- package/docs/english/07-troubleshooting.md +417 -0
- package/docs/english/08-advanced.md +411 -0
- package/docs/english/README.md +48 -0
- package/docs/thai/01-introduction.md +84 -0
- package/docs/thai/02-installation.md +200 -0
- package/docs/thai/03-quick-start.md +256 -0
- package/docs/thai/04-configuration.md +358 -0
- package/docs/thai/05-commands.md +363 -0
- package/docs/thai/06-examples.md +456 -0
- package/docs/thai/07-troubleshooting.md +417 -0
- package/docs/thai/08-advanced.md +411 -0
- package/docs/thai/README.md +48 -0
- package/example/README.md +282 -53
- package/example/suthep-complete.yml +103 -0
- package/example/suthep-docker-only.yml +71 -0
- package/example/suthep-no-docker.yml +51 -0
- package/example/{muacle.yml → suthep-path-routing.yml} +20 -5
- package/example/suthep.example.yml +89 -0
- package/package.json +1 -1
- package/src/commands/down.ts +240 -0
- package/src/commands/redeploy.ts +78 -0
- package/src/commands/up.ts +271 -0
- package/src/index.ts +53 -0
- package/suthep-0.1.0-beta.1.tgz +0 -0
- package/suthep.example.yml +5 -0
- package/suthep.yml +39 -0
- package/docs/TRANSLATIONS.md +0 -211
- package/docs/en/README.md +0 -76
- package/docs/en/api-reference.md +0 -545
- package/docs/en/architecture.md +0 -369
- package/docs/en/commands.md +0 -273
- package/docs/en/configuration.md +0 -347
- package/docs/en/developer-guide.md +0 -588
- package/docs/en/docker-ports-config.md +0 -333
- package/docs/en/examples.md +0 -537
- package/docs/en/getting-started.md +0 -202
- package/docs/en/port-binding.md +0 -268
- package/docs/en/troubleshooting.md +0 -441
- package/docs/th/README.md +0 -64
- package/docs/th/commands.md +0 -202
- package/docs/th/configuration.md +0 -325
- package/docs/th/getting-started.md +0 -203
- package/example/docker-compose.yml +0 -76
- package/example/docker-ports-example.yml +0 -81
- package/example/port-binding-example.yml +0 -45
- package/example/suthep.yml +0 -46
- package/example/suthep=1.yml +0 -46
package/README.md
CHANGED
|
@@ -2,18 +2,32 @@
|
|
|
2
2
|
|
|
3
3
|
A powerful CLI tool for deploying projects with automatic Nginx reverse proxy setup, HTTPS with Certbot, and zero-downtime deployments.
|
|
4
4
|
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Features](#features)
|
|
8
|
+
- [Installation](#installation)
|
|
9
|
+
- [Quick Start](#quick-start)
|
|
10
|
+
- [Configuration](#configuration)
|
|
11
|
+
- [Commands](#commands)
|
|
12
|
+
- [Examples](#examples)
|
|
13
|
+
- [Requirements](#requirements)
|
|
14
|
+
- [Benefits](#benefits)
|
|
15
|
+
- [License](#license)
|
|
16
|
+
|
|
5
17
|
## Features
|
|
6
18
|
|
|
7
|
-
- ✅ Automatic Nginx
|
|
8
|
-
- ✅ Automatic HTTPS with Certbot
|
|
9
|
-
- ✅ Zero-
|
|
10
|
-
- ✅ Docker
|
|
11
|
-
- ✅ Multiple
|
|
12
|
-
- ✅ Health check
|
|
13
|
-
- ✅ YAML-
|
|
19
|
+
- ✅ **Automatic Nginx Reverse Proxy** - Configures Nginx automatically for your services
|
|
20
|
+
- ✅ **Automatic HTTPS** - Sets up SSL/TLS certificates with Let's Encrypt via Certbot
|
|
21
|
+
- ✅ **Zero-Downtime Deployment** - Rolling deployment strategy ensures continuous availability
|
|
22
|
+
- ✅ **Docker Support** - Deploy Docker containers or connect to existing containers
|
|
23
|
+
- ✅ **Multiple Domains** - Support for multiple domains and subdomains per service
|
|
24
|
+
- ✅ **Health Checks** - Built-in health check monitoring for service reliability
|
|
25
|
+
- ✅ **YAML Configuration** - Simple, declarative configuration file format
|
|
14
26
|
|
|
15
27
|
## Installation
|
|
16
28
|
|
|
29
|
+
Install Suthep globally using your preferred package manager:
|
|
30
|
+
|
|
17
31
|
```bash
|
|
18
32
|
npm install -g suthep
|
|
19
33
|
# or
|
|
@@ -22,39 +36,49 @@ yarn global add suthep
|
|
|
22
36
|
pnpm add -g suthep
|
|
23
37
|
```
|
|
24
38
|
|
|
25
|
-
The tool uses `tsx` to run TypeScript directly, so no build step is required for development. For production, you can
|
|
39
|
+
> **Note:** The tool uses `tsx` to run TypeScript directly, so no build step is required for development. For production builds, you can optionally compile to JavaScript using `npm run build`.
|
|
40
|
+
|
|
41
|
+
## Quick Start
|
|
42
|
+
|
|
43
|
+
### 1. Initialize Configuration
|
|
44
|
+
|
|
45
|
+
Create a new configuration file interactively:
|
|
26
46
|
|
|
27
47
|
```bash
|
|
28
|
-
|
|
48
|
+
suthep init
|
|
29
49
|
```
|
|
30
50
|
|
|
31
|
-
|
|
51
|
+
This will create a `suthep.yml` file with interactive prompts, or you can use an example configuration:
|
|
32
52
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
53
|
+
```bash
|
|
54
|
+
cp example/suthep.yml suthep.yml
|
|
55
|
+
# Edit suthep.yml with your settings
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### 2. Setup Prerequisites
|
|
38
59
|
|
|
39
|
-
|
|
40
|
-
```bash
|
|
41
|
-
cp example.yml deploy.yml
|
|
42
|
-
# Edit deploy.yml with your settings
|
|
43
|
-
```
|
|
60
|
+
Install and configure Nginx and Certbot on your system:
|
|
44
61
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
```
|
|
62
|
+
```bash
|
|
63
|
+
suthep setup
|
|
64
|
+
```
|
|
49
65
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
66
|
+
This command will:
|
|
67
|
+
- Install Nginx (if not already installed)
|
|
68
|
+
- Install Certbot (if not already installed)
|
|
69
|
+
- Configure system dependencies
|
|
70
|
+
|
|
71
|
+
### 3. Deploy Your Project
|
|
72
|
+
|
|
73
|
+
Deploy your project using the configuration file:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
suthep deploy
|
|
77
|
+
```
|
|
54
78
|
|
|
55
79
|
## Configuration
|
|
56
80
|
|
|
57
|
-
The configuration file (`
|
|
81
|
+
The configuration file (`suthep.yml`) uses a YAML format to define your deployment. Here's the complete structure:
|
|
58
82
|
|
|
59
83
|
```yaml
|
|
60
84
|
project:
|
|
@@ -98,56 +122,84 @@ deployment:
|
|
|
98
122
|
|
|
99
123
|
### Service Configuration
|
|
100
124
|
|
|
101
|
-
Each service can have:
|
|
125
|
+
Each service in the `services` array can have the following properties:
|
|
126
|
+
|
|
127
|
+
| Property | Required | Description |
|
|
128
|
+
|----------|----------|-------------|
|
|
129
|
+
| `name` | ✅ Yes | Unique identifier for the service |
|
|
130
|
+
| `port` | ✅ Yes | Port number the service runs on (host port) |
|
|
131
|
+
| `domains` | ✅ Yes | Array of domain names or subdomains to route to this service |
|
|
132
|
+
| `docker` | ❌ No | Docker configuration (see below) |
|
|
133
|
+
| `healthCheck` | ❌ No | Health check configuration (see below) |
|
|
134
|
+
| `environment` | ❌ No | Environment variables as key-value pairs |
|
|
135
|
+
|
|
136
|
+
#### Docker Configuration
|
|
137
|
+
|
|
138
|
+
When deploying Docker containers, use the `docker` object:
|
|
139
|
+
|
|
140
|
+
- **`image`**: Docker image to pull and run (e.g., `nginx:latest`)
|
|
141
|
+
- **`container`**: Name for the Docker container
|
|
142
|
+
- **`port`**: Internal port the container listens on (mapped to the service `port`)
|
|
143
|
+
|
|
144
|
+
#### Health Check Configuration
|
|
102
145
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
-
|
|
106
|
-
-
|
|
107
|
-
- **image**: Docker image to use
|
|
108
|
-
- **container**: Container name
|
|
109
|
-
- **port**: Container's internal port
|
|
110
|
-
- **healthCheck** (optional):
|
|
111
|
-
- **path**: Health check endpoint path
|
|
112
|
-
- **interval**: Check interval in seconds
|
|
113
|
-
- **environment** (optional): Environment variables
|
|
146
|
+
Configure health monitoring for your service:
|
|
147
|
+
|
|
148
|
+
- **`path`**: HTTP endpoint path for health checks (e.g., `/health`)
|
|
149
|
+
- **`interval`**: Time between health checks in seconds (default: 30)
|
|
114
150
|
|
|
115
151
|
## Commands
|
|
116
152
|
|
|
117
|
-
### `
|
|
153
|
+
### `suthep init`
|
|
118
154
|
|
|
119
|
-
Initialize a new deployment configuration file.
|
|
155
|
+
Initialize a new deployment configuration file with interactive prompts.
|
|
120
156
|
|
|
121
157
|
```bash
|
|
122
|
-
|
|
158
|
+
suthep init [-f suthep.yml]
|
|
123
159
|
```
|
|
124
160
|
|
|
125
|
-
|
|
161
|
+
**Options:**
|
|
162
|
+
- `-f, --file`: Configuration file path (default: `suthep.yml`)
|
|
163
|
+
|
|
164
|
+
### `suthep setup`
|
|
126
165
|
|
|
127
|
-
|
|
166
|
+
Install and configure Nginx and Certbot on your system. This command checks for existing installations and sets up any missing components.
|
|
128
167
|
|
|
129
168
|
```bash
|
|
130
|
-
|
|
169
|
+
suthep setup [--nginx-only] [--certbot-only]
|
|
131
170
|
```
|
|
132
171
|
|
|
133
|
-
|
|
172
|
+
**Options:**
|
|
173
|
+
- `--nginx-only`: Only install and configure Nginx
|
|
174
|
+
- `--certbot-only`: Only install and configure Certbot
|
|
134
175
|
|
|
135
|
-
|
|
176
|
+
### `suthep deploy`
|
|
177
|
+
|
|
178
|
+
Deploy your project using the configuration file. This command will:
|
|
179
|
+
1. Configure Nginx reverse proxy for all services
|
|
180
|
+
2. Obtain SSL certificates via Certbot (if enabled)
|
|
181
|
+
3. Deploy services with zero-downtime strategy
|
|
136
182
|
|
|
137
183
|
```bash
|
|
138
|
-
|
|
184
|
+
suthep deploy [-f suthep.yml] [--no-https] [--no-nginx]
|
|
139
185
|
```
|
|
140
186
|
|
|
141
|
-
Options
|
|
142
|
-
- `-f, --file`: Configuration file path (default: `
|
|
143
|
-
- `--no-https`: Skip HTTPS setup
|
|
144
|
-
- `--no-nginx`: Skip Nginx configuration
|
|
187
|
+
**Options:**
|
|
188
|
+
- `-f, --file`: Configuration file path (default: `suthep.yml`)
|
|
189
|
+
- `--no-https`: Skip HTTPS/SSL certificate setup
|
|
190
|
+
- `--no-nginx`: Skip Nginx configuration (useful for testing)
|
|
145
191
|
|
|
146
192
|
## Examples
|
|
147
193
|
|
|
148
|
-
### Simple Node.js Service
|
|
194
|
+
### Example 1: Simple Node.js API Service
|
|
195
|
+
|
|
196
|
+
Deploy a Node.js API service with health checks:
|
|
149
197
|
|
|
150
198
|
```yaml
|
|
199
|
+
project:
|
|
200
|
+
name: my-api
|
|
201
|
+
version: 1.0.0
|
|
202
|
+
|
|
151
203
|
services:
|
|
152
204
|
- name: api
|
|
153
205
|
port: 3000
|
|
@@ -155,9 +207,26 @@ services:
|
|
|
155
207
|
- api.example.com
|
|
156
208
|
healthCheck:
|
|
157
209
|
path: /health
|
|
210
|
+
interval: 30
|
|
211
|
+
environment:
|
|
212
|
+
NODE_ENV: production
|
|
213
|
+
|
|
214
|
+
nginx:
|
|
215
|
+
configPath: /etc/nginx/sites-available
|
|
216
|
+
reloadCommand: sudo nginx -t && sudo systemctl reload nginx
|
|
217
|
+
|
|
218
|
+
certbot:
|
|
219
|
+
email: admin@example.com
|
|
220
|
+
staging: false
|
|
221
|
+
|
|
222
|
+
deployment:
|
|
223
|
+
strategy: rolling
|
|
224
|
+
healthCheckTimeout: 30000
|
|
158
225
|
```
|
|
159
226
|
|
|
160
|
-
### Docker Container Service
|
|
227
|
+
### Example 2: Docker Container Service
|
|
228
|
+
|
|
229
|
+
Deploy a web application using a Docker container:
|
|
161
230
|
|
|
162
231
|
```yaml
|
|
163
232
|
services:
|
|
@@ -169,9 +238,12 @@ services:
|
|
|
169
238
|
port: 80
|
|
170
239
|
domains:
|
|
171
240
|
- example.com
|
|
241
|
+
- www.example.com
|
|
172
242
|
```
|
|
173
243
|
|
|
174
|
-
### Multiple Domains
|
|
244
|
+
### Example 3: Multiple Domains for Single Service
|
|
245
|
+
|
|
246
|
+
Route multiple domains to the same service:
|
|
175
247
|
|
|
176
248
|
```yaml
|
|
177
249
|
services:
|
|
@@ -181,9 +253,13 @@ services:
|
|
|
181
253
|
- dashboard.example.com
|
|
182
254
|
- admin.example.com
|
|
183
255
|
- app.example.com
|
|
256
|
+
healthCheck:
|
|
257
|
+
path: /api/health
|
|
184
258
|
```
|
|
185
259
|
|
|
186
|
-
### Connect to Existing Docker Container
|
|
260
|
+
### Example 4: Connect to Existing Docker Container
|
|
261
|
+
|
|
262
|
+
Connect to an already running Docker container:
|
|
187
263
|
|
|
188
264
|
```yaml
|
|
189
265
|
services:
|
|
@@ -196,21 +272,43 @@ services:
|
|
|
196
272
|
- db.example.com
|
|
197
273
|
```
|
|
198
274
|
|
|
275
|
+
> **Note:** When connecting to an existing container, omit the `image` field. The tool will use the existing container.
|
|
276
|
+
|
|
199
277
|
## Requirements
|
|
200
278
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
-
|
|
204
|
-
-
|
|
205
|
-
-
|
|
279
|
+
### System Requirements
|
|
280
|
+
|
|
281
|
+
- **Node.js** 16 or higher
|
|
282
|
+
- **Nginx** (installed automatically via `suthep setup`)
|
|
283
|
+
- **Certbot** (installed automatically via `suthep setup`)
|
|
284
|
+
- **Docker** (optional, required only for Docker-based services)
|
|
285
|
+
- **sudo access** (required for Nginx and Certbot operations)
|
|
286
|
+
|
|
287
|
+
### Permissions
|
|
288
|
+
|
|
289
|
+
Suthep requires sudo privileges to:
|
|
290
|
+
- Install system packages (Nginx, Certbot)
|
|
291
|
+
- Modify Nginx configuration files
|
|
292
|
+
- Reload Nginx service
|
|
293
|
+
- Obtain SSL certificates from Let's Encrypt
|
|
294
|
+
|
|
295
|
+
## Benefits
|
|
296
|
+
|
|
297
|
+
### Cost Optimization
|
|
298
|
+
|
|
299
|
+
Suthep helps optimize infrastructure costs by:
|
|
300
|
+
|
|
301
|
+
- **Multi-Service Management** - Run multiple services on a single server efficiently
|
|
302
|
+
- **Automated Configuration** - Eliminates manual Nginx and SSL setup, saving time and reducing errors
|
|
303
|
+
- **Zero-Downtime Deployments** - Rolling deployment strategy ensures continuous service availability
|
|
304
|
+
- **Health Monitoring** - Built-in health checks help maintain service reliability and catch issues early
|
|
206
305
|
|
|
207
|
-
|
|
306
|
+
### Developer Experience
|
|
208
307
|
|
|
209
|
-
|
|
210
|
-
-
|
|
211
|
-
- Automatic
|
|
212
|
-
-
|
|
213
|
-
- Health checks ensure service reliability
|
|
308
|
+
- **Simple Configuration** - YAML-based configuration is easy to understand and maintain
|
|
309
|
+
- **One Command Deployment** - Deploy entire infrastructure with a single command
|
|
310
|
+
- **Automatic SSL** - HTTPS certificates are obtained and renewed automatically
|
|
311
|
+
- **Docker Integration** - Seamless support for containerized applications
|
|
214
312
|
|
|
215
313
|
## License
|
|
216
314
|
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import fs from "fs-extra";
|
|
3
|
+
import { loadConfig } from "../utils/config-loader.js";
|
|
4
|
+
import { stopDockerContainer, removeDockerContainer, isContainerRunning } from "../utils/docker.js";
|
|
5
|
+
import { disableSite, generateNginxConfig, generateMultiServiceNginxConfig, writeNginxConfig, enableSite, reloadNginx } from "../utils/nginx.js";
|
|
6
|
+
async function downCommand(options) {
|
|
7
|
+
console.log(chalk.blue.bold("\n🛑 Bringing Down Services\n"));
|
|
8
|
+
try {
|
|
9
|
+
if (!await fs.pathExists(options.file)) {
|
|
10
|
+
throw new Error(`Configuration file not found: ${options.file}`);
|
|
11
|
+
}
|
|
12
|
+
console.log(chalk.cyan(`📄 Loading configuration from ${options.file}...`));
|
|
13
|
+
const config = await loadConfig(options.file);
|
|
14
|
+
console.log(chalk.green(`✅ Configuration loaded for project: ${config.project.name}`));
|
|
15
|
+
let servicesToDown = [];
|
|
16
|
+
if (options.all) {
|
|
17
|
+
servicesToDown = config.services;
|
|
18
|
+
console.log(
|
|
19
|
+
chalk.cyan(
|
|
20
|
+
`📋 Bringing down all services: ${servicesToDown.map((s) => s.name).join(", ")}
|
|
21
|
+
`
|
|
22
|
+
)
|
|
23
|
+
);
|
|
24
|
+
} else if (options.serviceName) {
|
|
25
|
+
const service = config.services.find((s) => s.name === options.serviceName);
|
|
26
|
+
if (!service) {
|
|
27
|
+
throw new Error(
|
|
28
|
+
`Service "${options.serviceName}" not found in configuration. Available services: ${config.services.map((s) => s.name).join(", ")}`
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
servicesToDown = [service];
|
|
32
|
+
console.log(chalk.cyan(`📋 Bringing down service: ${options.serviceName}
|
|
33
|
+
`));
|
|
34
|
+
} else {
|
|
35
|
+
throw new Error("Either specify a service name or use --all flag");
|
|
36
|
+
}
|
|
37
|
+
const domainToServices = /* @__PURE__ */ new Map();
|
|
38
|
+
const allDomains = /* @__PURE__ */ new Set();
|
|
39
|
+
for (const service of servicesToDown) {
|
|
40
|
+
for (const domain of service.domains) {
|
|
41
|
+
allDomains.add(domain);
|
|
42
|
+
if (!domainToServices.has(domain)) {
|
|
43
|
+
domainToServices.set(domain, []);
|
|
44
|
+
}
|
|
45
|
+
domainToServices.get(domain).push(service);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
for (const service of servicesToDown) {
|
|
49
|
+
if (service.docker) {
|
|
50
|
+
console.log(chalk.cyan(`
|
|
51
|
+
🐳 Stopping Docker container for service: ${service.name}`));
|
|
52
|
+
try {
|
|
53
|
+
const containerName = service.docker.container;
|
|
54
|
+
try {
|
|
55
|
+
await stopDockerContainer(containerName);
|
|
56
|
+
console.log(chalk.green(` ✅ Stopped container: ${containerName}`));
|
|
57
|
+
} catch (error) {
|
|
58
|
+
const errorMessage = error?.message || String(error) || "Unknown error";
|
|
59
|
+
if (errorMessage.toLowerCase().includes("no such container") || errorMessage.toLowerCase().includes("container not found")) {
|
|
60
|
+
console.log(
|
|
61
|
+
chalk.yellow(` ⚠️ Container ${containerName} not found (already stopped)`)
|
|
62
|
+
);
|
|
63
|
+
} else {
|
|
64
|
+
throw error;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
await removeDockerContainer(containerName);
|
|
69
|
+
console.log(chalk.green(` ✅ Removed container: ${containerName}`));
|
|
70
|
+
} catch (error) {
|
|
71
|
+
const errorMessage = error?.message || String(error) || "Unknown error";
|
|
72
|
+
if (errorMessage.toLowerCase().includes("no such container") || errorMessage.toLowerCase().includes("container not found")) {
|
|
73
|
+
console.log(
|
|
74
|
+
chalk.yellow(` ⚠️ Container ${containerName} not found (already removed)`)
|
|
75
|
+
);
|
|
76
|
+
} else {
|
|
77
|
+
throw error;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
} catch (error) {
|
|
81
|
+
console.error(
|
|
82
|
+
chalk.red(` ❌ Failed to stop/remove container for service ${service.name}:`),
|
|
83
|
+
error instanceof Error ? error.message : error
|
|
84
|
+
);
|
|
85
|
+
throw error;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (allDomains.size > 0) {
|
|
90
|
+
console.log(chalk.cyan(`
|
|
91
|
+
⚙️ Updating Nginx configurations...`));
|
|
92
|
+
const servicesBeingDowned = new Set(servicesToDown.map((s) => s.name));
|
|
93
|
+
for (const domain of allDomains) {
|
|
94
|
+
const configName = domain.replace(/\./g, "_");
|
|
95
|
+
const allServicesForDomain = config.services.filter((s) => s.domains.includes(domain));
|
|
96
|
+
const remainingServices = allServicesForDomain.filter(
|
|
97
|
+
(s) => !servicesBeingDowned.has(s.name)
|
|
98
|
+
);
|
|
99
|
+
const activeServices = [];
|
|
100
|
+
for (const service of remainingServices) {
|
|
101
|
+
if (service.docker) {
|
|
102
|
+
const isRunning = await isContainerRunning(service.docker.container);
|
|
103
|
+
if (isRunning) {
|
|
104
|
+
activeServices.push(service);
|
|
105
|
+
}
|
|
106
|
+
} else {
|
|
107
|
+
activeServices.push(service);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
try {
|
|
111
|
+
if (activeServices.length === 0) {
|
|
112
|
+
console.log(
|
|
113
|
+
chalk.cyan(` 📋 No active services on ${domain}, disabling Nginx config...`)
|
|
114
|
+
);
|
|
115
|
+
await disableSite(configName, config.nginx.configPath);
|
|
116
|
+
console.log(chalk.green(` ✅ Disabled Nginx config for ${domain}`));
|
|
117
|
+
} else {
|
|
118
|
+
console.log(
|
|
119
|
+
chalk.cyan(
|
|
120
|
+
` 📋 Regenerating Nginx config for ${domain} with ${activeServices.length} active service(s): ${activeServices.map((s) => s.name).join(", ")}`
|
|
121
|
+
)
|
|
122
|
+
);
|
|
123
|
+
let nginxConfigContent;
|
|
124
|
+
if (activeServices.length === 1) {
|
|
125
|
+
nginxConfigContent = generateNginxConfig(activeServices[0], false);
|
|
126
|
+
} else {
|
|
127
|
+
nginxConfigContent = generateMultiServiceNginxConfig(activeServices, domain, false);
|
|
128
|
+
}
|
|
129
|
+
const { certificateExists } = await import("../utils/certbot.js");
|
|
130
|
+
const hasHttps = await certificateExists(domain);
|
|
131
|
+
if (hasHttps) {
|
|
132
|
+
if (activeServices.length === 1) {
|
|
133
|
+
nginxConfigContent = generateNginxConfig(activeServices[0], true);
|
|
134
|
+
} else {
|
|
135
|
+
nginxConfigContent = generateMultiServiceNginxConfig(activeServices, domain, true);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
await writeNginxConfig(configName, config.nginx.configPath, nginxConfigContent);
|
|
139
|
+
await enableSite(configName, config.nginx.configPath);
|
|
140
|
+
console.log(
|
|
141
|
+
chalk.green(
|
|
142
|
+
` ✅ Updated Nginx config for ${domain} (${activeServices.length} service(s) active)`
|
|
143
|
+
)
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
} catch (error) {
|
|
147
|
+
console.error(
|
|
148
|
+
chalk.red(` ❌ Failed to update Nginx config for ${domain}:`),
|
|
149
|
+
error instanceof Error ? error.message : error
|
|
150
|
+
);
|
|
151
|
+
throw error;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
console.log(chalk.cyan(`
|
|
155
|
+
🔄 Reloading Nginx...`));
|
|
156
|
+
try {
|
|
157
|
+
await reloadNginx(config.nginx.reloadCommand);
|
|
158
|
+
console.log(chalk.green(` ✅ Nginx reloaded`));
|
|
159
|
+
} catch (error) {
|
|
160
|
+
console.error(
|
|
161
|
+
chalk.red(` ❌ Failed to reload Nginx:`),
|
|
162
|
+
error instanceof Error ? error.message : error
|
|
163
|
+
);
|
|
164
|
+
throw error;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
console.log(chalk.green.bold("\n✅ Services brought down successfully!\n"));
|
|
168
|
+
} catch (error) {
|
|
169
|
+
console.error(
|
|
170
|
+
chalk.red("\n❌ Failed to bring down services:"),
|
|
171
|
+
error instanceof Error ? error.message : error
|
|
172
|
+
);
|
|
173
|
+
process.exit(1);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
export {
|
|
177
|
+
downCommand
|
|
178
|
+
};
|
|
179
|
+
//# sourceMappingURL=down.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"down.js","sources":["../../src/commands/down.ts"],"sourcesContent":["import chalk from 'chalk'\nimport fs from 'fs-extra'\nimport type { ServiceConfig } from '../types/config'\nimport { loadConfig } from '../utils/config-loader'\nimport { isContainerRunning, removeDockerContainer, stopDockerContainer } from '../utils/docker'\nimport {\n disableSite,\n enableSite,\n generateMultiServiceNginxConfig,\n generateNginxConfig,\n reloadNginx,\n writeNginxConfig,\n} from '../utils/nginx'\n\ninterface DownOptions {\n file: string\n all: boolean\n serviceName?: string\n}\n\nexport async function downCommand(options: DownOptions): Promise<void> {\n console.log(chalk.blue.bold('\\n🛑 Bringing Down Services\\n'))\n\n try {\n // Load configuration\n if (!(await fs.pathExists(options.file))) {\n throw new Error(`Configuration file not found: ${options.file}`)\n }\n\n console.log(chalk.cyan(`📄 Loading configuration from ${options.file}...`))\n const config = await loadConfig(options.file)\n\n console.log(chalk.green(`✅ Configuration loaded for project: ${config.project.name}`))\n\n // Determine which services to bring down\n let servicesToDown: ServiceConfig[] = []\n\n if (options.all) {\n servicesToDown = config.services\n console.log(\n chalk.cyan(\n `📋 Bringing down all services: ${servicesToDown.map((s) => s.name).join(', ')}\\n`\n )\n )\n } else if (options.serviceName) {\n const service = config.services.find((s) => s.name === options.serviceName)\n if (!service) {\n throw new Error(\n `Service \"${\n options.serviceName\n }\" not found in configuration. Available services: ${config.services\n .map((s) => s.name)\n .join(', ')}`\n )\n }\n servicesToDown = [service]\n console.log(chalk.cyan(`📋 Bringing down service: ${options.serviceName}\\n`))\n } else {\n throw new Error('Either specify a service name or use --all flag')\n }\n\n // Group services by domain for nginx config management\n const domainToServices = new Map<string, ServiceConfig[]>()\n const allDomains = new Set<string>()\n\n for (const service of servicesToDown) {\n for (const domain of service.domains) {\n allDomains.add(domain)\n if (!domainToServices.has(domain)) {\n domainToServices.set(domain, [])\n }\n domainToServices.get(domain)!.push(service)\n }\n }\n\n // Stop and remove Docker containers\n for (const service of servicesToDown) {\n if (service.docker) {\n console.log(chalk.cyan(`\\n🐳 Stopping Docker container for service: ${service.name}`))\n try {\n const containerName = service.docker.container\n\n // Stop container\n try {\n await stopDockerContainer(containerName)\n console.log(chalk.green(` ✅ Stopped container: ${containerName}`))\n } catch (error: any) {\n const errorMessage = error?.message || String(error) || 'Unknown error'\n if (\n errorMessage.toLowerCase().includes('no such container') ||\n errorMessage.toLowerCase().includes('container not found')\n ) {\n console.log(\n chalk.yellow(` ⚠️ Container ${containerName} not found (already stopped)`)\n )\n } else {\n throw error\n }\n }\n\n // Remove container\n try {\n await removeDockerContainer(containerName)\n console.log(chalk.green(` ✅ Removed container: ${containerName}`))\n } catch (error: any) {\n const errorMessage = error?.message || String(error) || 'Unknown error'\n if (\n errorMessage.toLowerCase().includes('no such container') ||\n errorMessage.toLowerCase().includes('container not found')\n ) {\n console.log(\n chalk.yellow(` ⚠️ Container ${containerName} not found (already removed)`)\n )\n } else {\n throw error\n }\n }\n } catch (error) {\n console.error(\n chalk.red(` ❌ Failed to stop/remove container for service ${service.name}:`),\n error instanceof Error ? error.message : error\n )\n throw error\n }\n }\n }\n\n // Handle Nginx configs by domain\n // Check which services remain active for each domain\n if (allDomains.size > 0) {\n console.log(chalk.cyan(`\\n⚙️ Updating Nginx configurations...`))\n\n // Create a set of service names being brought down for quick lookup\n const servicesBeingDowned = new Set(servicesToDown.map((s) => s.name))\n\n // For each domain, find all services that use it (from all config services)\n // and determine which ones remain active\n for (const domain of allDomains) {\n const configName = domain.replace(/\\./g, '_')\n\n // Find all services that use this domain (from entire config)\n const allServicesForDomain = config.services.filter((s) => s.domains.includes(domain))\n\n // Filter out services being brought down\n const remainingServices = allServicesForDomain.filter(\n (s) => !servicesBeingDowned.has(s.name)\n )\n\n // Check if remaining services are actually running (have active containers)\n const activeServices: ServiceConfig[] = []\n for (const service of remainingServices) {\n if (service.docker) {\n const isRunning = await isContainerRunning(service.docker.container)\n if (isRunning) {\n activeServices.push(service)\n }\n } else {\n // Service without docker - assume it's running if not being brought down\n activeServices.push(service)\n }\n }\n\n try {\n if (activeServices.length === 0) {\n // No active services on this domain, disable the config\n console.log(\n chalk.cyan(` 📋 No active services on ${domain}, disabling Nginx config...`)\n )\n await disableSite(configName, config.nginx.configPath)\n console.log(chalk.green(` ✅ Disabled Nginx config for ${domain}`))\n } else {\n // Regenerate config with remaining active services\n console.log(\n chalk.cyan(\n ` 📋 Regenerating Nginx config for ${domain} with ${\n activeServices.length\n } active service(s): ${activeServices.map((s) => s.name).join(', ')}`\n )\n )\n\n // Generate config for remaining services\n let nginxConfigContent: string\n if (activeServices.length === 1) {\n nginxConfigContent = generateNginxConfig(activeServices[0], false)\n } else {\n nginxConfigContent = generateMultiServiceNginxConfig(activeServices, domain, false)\n }\n\n // Check if HTTPS is enabled (check if certificate exists)\n const { certificateExists } = await import('../utils/certbot')\n const hasHttps = await certificateExists(domain)\n if (hasHttps) {\n // Regenerate with HTTPS\n if (activeServices.length === 1) {\n nginxConfigContent = generateNginxConfig(activeServices[0], true)\n } else {\n nginxConfigContent = generateMultiServiceNginxConfig(activeServices, domain, true)\n }\n }\n\n await writeNginxConfig(configName, config.nginx.configPath, nginxConfigContent)\n await enableSite(configName, config.nginx.configPath)\n console.log(\n chalk.green(\n ` ✅ Updated Nginx config for ${domain} (${activeServices.length} service(s) active)`\n )\n )\n }\n } catch (error) {\n console.error(\n chalk.red(` ❌ Failed to update Nginx config for ${domain}:`),\n error instanceof Error ? error.message : error\n )\n throw error\n }\n }\n\n // Reload Nginx to apply changes\n console.log(chalk.cyan(`\\n🔄 Reloading Nginx...`))\n try {\n await reloadNginx(config.nginx.reloadCommand)\n console.log(chalk.green(` ✅ Nginx reloaded`))\n } catch (error) {\n console.error(\n chalk.red(` ❌ Failed to reload Nginx:`),\n error instanceof Error ? error.message : error\n )\n throw error\n }\n }\n\n console.log(chalk.green.bold('\\n✅ Services brought down successfully!\\n'))\n } catch (error) {\n console.error(\n chalk.red('\\n❌ Failed to bring down services:'),\n error instanceof Error ? error.message : error\n )\n process.exit(1)\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import fs from "fs-extra";
|
|
3
|
+
import { loadConfig } from "../utils/config-loader.js";
|
|
4
|
+
import { deployCommand } from "./deploy.js";
|
|
5
|
+
import { downCommand } from "./down.js";
|
|
6
|
+
async function redeployCommand(options) {
|
|
7
|
+
console.log(chalk.blue.bold("\n🔄 Redeploying Services\n"));
|
|
8
|
+
try {
|
|
9
|
+
if (!await fs.pathExists(options.file)) {
|
|
10
|
+
throw new Error(`Configuration file not found: ${options.file}`);
|
|
11
|
+
}
|
|
12
|
+
const config = await loadConfig(options.file);
|
|
13
|
+
let servicesToRedeploy = [];
|
|
14
|
+
if (options.all) {
|
|
15
|
+
servicesToRedeploy = config.services;
|
|
16
|
+
console.log(
|
|
17
|
+
chalk.cyan(
|
|
18
|
+
`📋 Redeploying all services: ${servicesToRedeploy.map((s) => s.name).join(", ")}
|
|
19
|
+
`
|
|
20
|
+
)
|
|
21
|
+
);
|
|
22
|
+
} else if (options.serviceName) {
|
|
23
|
+
const service = config.services.find((s) => s.name === options.serviceName);
|
|
24
|
+
if (!service) {
|
|
25
|
+
throw new Error(
|
|
26
|
+
`Service "${options.serviceName}" not found in configuration. Available services: ${config.services.map((s) => s.name).join(", ")}`
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
servicesToRedeploy = [service];
|
|
30
|
+
console.log(chalk.cyan(`📋 Redeploying service: ${options.serviceName}
|
|
31
|
+
`));
|
|
32
|
+
} else {
|
|
33
|
+
throw new Error("Either specify a service name or use --all flag");
|
|
34
|
+
}
|
|
35
|
+
console.log(chalk.yellow("Step 1: Bringing down services...\n"));
|
|
36
|
+
await downCommand({
|
|
37
|
+
file: options.file,
|
|
38
|
+
all: options.all,
|
|
39
|
+
serviceName: options.serviceName
|
|
40
|
+
});
|
|
41
|
+
console.log(chalk.yellow("\nStep 2: Deploying services...\n"));
|
|
42
|
+
await deployCommand({
|
|
43
|
+
file: options.file,
|
|
44
|
+
https: options.https,
|
|
45
|
+
nginx: options.nginx
|
|
46
|
+
});
|
|
47
|
+
console.log(chalk.green.bold("\n✅ Services redeployed successfully!\n"));
|
|
48
|
+
} catch (error) {
|
|
49
|
+
console.error(
|
|
50
|
+
chalk.red("\n❌ Failed to redeploy services:"),
|
|
51
|
+
error instanceof Error ? error.message : error
|
|
52
|
+
);
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
export {
|
|
57
|
+
redeployCommand
|
|
58
|
+
};
|
|
59
|
+
//# sourceMappingURL=redeploy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redeploy.js","sources":["../../src/commands/redeploy.ts"],"sourcesContent":["import chalk from 'chalk'\nimport fs from 'fs-extra'\nimport type { ServiceConfig } from '../types/config'\nimport { loadConfig } from '../utils/config-loader'\nimport { deployCommand } from './deploy'\nimport { downCommand } from './down'\n\ninterface RedeployOptions {\n file: string\n all: boolean\n serviceName?: string\n https: boolean\n nginx: boolean\n}\n\nexport async function redeployCommand(options: RedeployOptions): Promise<void> {\n console.log(chalk.blue.bold('\\n🔄 Redeploying Services\\n'))\n\n try {\n // Load configuration to validate service names\n if (!(await fs.pathExists(options.file))) {\n throw new Error(`Configuration file not found: ${options.file}`)\n }\n\n const config = await loadConfig(options.file)\n\n // Determine which services to redeploy\n let servicesToRedeploy: ServiceConfig[] = []\n\n if (options.all) {\n servicesToRedeploy = config.services\n console.log(\n chalk.cyan(\n `📋 Redeploying all services: ${servicesToRedeploy.map((s) => s.name).join(', ')}\\n`\n )\n )\n } else if (options.serviceName) {\n const service = config.services.find((s) => s.name === options.serviceName)\n if (!service) {\n throw new Error(\n `Service \"${\n options.serviceName\n }\" not found in configuration. Available services: ${config.services\n .map((s) => s.name)\n .join(', ')}`\n )\n }\n servicesToRedeploy = [service]\n console.log(chalk.cyan(`📋 Redeploying service: ${options.serviceName}\\n`))\n } else {\n throw new Error('Either specify a service name or use --all flag')\n }\n\n // Step 1: Bring down the services\n console.log(chalk.yellow('Step 1: Bringing down services...\\n'))\n await downCommand({\n file: options.file,\n all: options.all,\n serviceName: options.serviceName,\n })\n\n // Step 2: Deploy the services (which will bring them back up)\n console.log(chalk.yellow('\\nStep 2: Deploying services...\\n'))\n await deployCommand({\n file: options.file,\n https: options.https,\n nginx: options.nginx,\n })\n\n console.log(chalk.green.bold('\\n✅ Services redeployed successfully!\\n'))\n } catch (error) {\n console.error(\n chalk.red('\\n❌ Failed to redeploy services:'),\n error instanceof Error ? error.message : error\n )\n process.exit(1)\n }\n}\n"],"names":[],"mappings":";;;;;AAeA,eAAsB,gBAAgB,SAAyC;AAC7E,UAAQ,IAAI,MAAM,KAAK,KAAK,6BAA6B,CAAC;AAE1D,MAAI;AAEF,QAAI,CAAE,MAAM,GAAG,WAAW,QAAQ,IAAI,GAAI;AACxC,YAAM,IAAI,MAAM,iCAAiC,QAAQ,IAAI,EAAE;AAAA,IACjE;AAEA,UAAM,SAAS,MAAM,WAAW,QAAQ,IAAI;AAG5C,QAAI,qBAAsC,CAAA;AAE1C,QAAI,QAAQ,KAAK;AACf,2BAAqB,OAAO;AAC5B,cAAQ;AAAA,QACN,MAAM;AAAA,UACJ,gCAAgC,mBAAmB,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,IAAI,CAAC;AAAA;AAAA,QAAA;AAAA,MAClF;AAAA,IAEJ,WAAW,QAAQ,aAAa;AAC9B,YAAM,UAAU,OAAO,SAAS,KAAK,CAAC,MAAM,EAAE,SAAS,QAAQ,WAAW;AAC1E,UAAI,CAAC,SAAS;AACZ,cAAM,IAAI;AAAA,UACR,YACE,QAAQ,WACV,qDAAqD,OAAO,SACzD,IAAI,CAAC,MAAM,EAAE,IAAI,EACjB,KAAK,IAAI,CAAC;AAAA,QAAA;AAAA,MAEjB;AACA,2BAAqB,CAAC,OAAO;AAC7B,cAAQ,IAAI,MAAM,KAAK,2BAA2B,QAAQ,WAAW;AAAA,CAAI,CAAC;AAAA,IAC5E,OAAO;AACL,YAAM,IAAI,MAAM,iDAAiD;AAAA,IACnE;AAGA,YAAQ,IAAI,MAAM,OAAO,qCAAqC,CAAC;AAC/D,UAAM,YAAY;AAAA,MAChB,MAAM,QAAQ;AAAA,MACd,KAAK,QAAQ;AAAA,MACb,aAAa,QAAQ;AAAA,IAAA,CACtB;AAGD,YAAQ,IAAI,MAAM,OAAO,mCAAmC,CAAC;AAC7D,UAAM,cAAc;AAAA,MAClB,MAAM,QAAQ;AAAA,MACd,OAAO,QAAQ;AAAA,MACf,OAAO,QAAQ;AAAA,IAAA,CAChB;AAED,YAAQ,IAAI,MAAM,MAAM,KAAK,yCAAyC,CAAC;AAAA,EACzE,SAAS,OAAO;AACd,YAAQ;AAAA,MACN,MAAM,IAAI,kCAAkC;AAAA,MAC5C,iBAAiB,QAAQ,MAAM,UAAU;AAAA,IAAA;AAE3C,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;"}
|