@simplens/onboard 1.0.8 → 1.0.10
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/dist/index.js +35 -10
- package/dist/index.js.map +1 -1
- package/dist/infra.d.ts +1 -0
- package/dist/infra.d.ts.map +1 -1
- package/dist/infra.js +4 -3
- package/dist/infra.js.map +1 -1
- package/dist/services.d.ts +13 -0
- package/dist/services.d.ts.map +1 -1
- package/dist/services.js +74 -8
- package/dist/services.js.map +1 -1
- package/dist/templates.d.ts +2 -2
- package/dist/templates.d.ts.map +1 -1
- package/dist/templates.js +8 -4
- package/dist/templates.js.map +1 -1
- package/package.json +5 -1
- package/src/__tests__/env-config.test.ts +0 -28
- package/src/__tests__/errors.test.ts +0 -188
- package/src/__tests__/infra-prompts.test.ts +0 -56
- package/src/__tests__/infra.test.ts +0 -30
- package/src/__tests__/utils.test.ts +0 -142
- package/src/__tests__/validators.test.ts +0 -221
- package/src/config/constants.ts +0 -87
- package/src/config/index.ts +0 -1
- package/src/env-config.ts +0 -503
- package/src/index.ts +0 -683
- package/src/infra.ts +0 -514
- package/src/plugins.ts +0 -221
- package/src/services.ts +0 -308
- package/src/templates.ts +0 -278
- package/src/types/domain.ts +0 -135
- package/src/types/errors.ts +0 -173
- package/src/types/index.ts +0 -2
- package/src/ui.ts +0 -91
- package/src/utils/index.ts +0 -1
- package/src/utils/logger.ts +0 -144
- package/src/utils.ts +0 -183
- package/src/validators.ts +0 -196
- package/tsconfig.json +0 -19
- package/vitest.config.ts +0 -22
package/src/infra.ts
DELETED
|
@@ -1,514 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
APP_COMPOSE_TEMPLATE,
|
|
3
|
-
APP_NGINX_SERVICE_TEMPLATE,
|
|
4
|
-
APP_NGINX_SSL_SERVICE_TEMPLATE,
|
|
5
|
-
APP_CERTBOT_SERVICES_TEMPLATE,
|
|
6
|
-
INFRA_CERTBOT_SERVICES_TEMPLATE,
|
|
7
|
-
INFRA_CERTBOT_VOLUMES,
|
|
8
|
-
} from './templates.js';
|
|
9
|
-
import { writeFile, logInfo, logSuccess } from './utils.js';
|
|
10
|
-
import { multiselect } from '@clack/prompts';
|
|
11
|
-
import { handleCancel, spinner } from './ui.js';
|
|
12
|
-
import path from 'path';
|
|
13
|
-
import type { InfraService } from './types/domain.js';
|
|
14
|
-
|
|
15
|
-
const INFRA_SERVICES: InfraService[] = [
|
|
16
|
-
{ name: 'MongoDB (Database)', value: 'mongo', checked: true },
|
|
17
|
-
{ name: 'Kafka (Message Queue)', value: 'kafka', checked: true },
|
|
18
|
-
{ name: 'Kafka UI (Dashboard)', value: 'kafka-ui', checked: false },
|
|
19
|
-
{ name: 'Redis (Cache)', value: 'redis', checked: true },
|
|
20
|
-
{ name: 'Nginx (Reverse Proxy)', value: 'nginx', checked: false },
|
|
21
|
-
{ name: 'Loki (Log Aggregation)', value: 'loki', checked: false },
|
|
22
|
-
{ name: 'Grafana (Observability Dashboard)', value: 'grafana', checked: false },
|
|
23
|
-
];
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Prompts user to select which infrastructure services to deploy.
|
|
27
|
-
*
|
|
28
|
-
* @returns Array of selected service IDs (e.g., ['mongo', 'kafka', 'redis'])
|
|
29
|
-
* @throws Error if no services are selected
|
|
30
|
-
*/
|
|
31
|
-
export async function promptInfraServices(): Promise<string[]> {
|
|
32
|
-
return promptInfraServicesWithBasePath({ allowNginx: true });
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Prompts infrastructure services with optional nginx availability.
|
|
37
|
-
* If nginx is disabled, it is removed from choices and from result safety-check.
|
|
38
|
-
*/
|
|
39
|
-
export async function promptInfraServicesWithBasePath(options: {
|
|
40
|
-
allowNginx: boolean;
|
|
41
|
-
defaultNginx?: boolean;
|
|
42
|
-
}): Promise<string[]> {
|
|
43
|
-
const choices = options.allowNginx
|
|
44
|
-
? INFRA_SERVICES.map(service => {
|
|
45
|
-
if (service.value === 'nginx') {
|
|
46
|
-
return { ...service, checked: options.defaultNginx === true };
|
|
47
|
-
}
|
|
48
|
-
return service;
|
|
49
|
-
})
|
|
50
|
-
: INFRA_SERVICES.filter(service => service.value !== 'nginx');
|
|
51
|
-
|
|
52
|
-
const message = options.allowNginx
|
|
53
|
-
? 'Select infrastructure services to run (Space to select, Enter to confirm):'
|
|
54
|
-
: 'Select infrastructure services to run (Space to select, Enter to confirm) — nginx disabled:';
|
|
55
|
-
|
|
56
|
-
const selected = await multiselect({
|
|
57
|
-
message,
|
|
58
|
-
options: choices.map(s => ({
|
|
59
|
-
value: s.value,
|
|
60
|
-
label: s.name,
|
|
61
|
-
hint: s.checked ? 'recommended' : undefined,
|
|
62
|
-
})),
|
|
63
|
-
initialValues: choices.filter(s => s.checked).map(s => s.value),
|
|
64
|
-
required: true,
|
|
65
|
-
withGuide: true,
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
handleCancel(selected);
|
|
69
|
-
const result = selected as string[];
|
|
70
|
-
|
|
71
|
-
if (options.allowNginx) {
|
|
72
|
-
return result;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
return result.filter(service => service !== 'nginx');
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Service chunk definitions - each service as a complete block
|
|
82
|
-
*/
|
|
83
|
-
const SERVICE_CHUNKS: Record<string, string> = {
|
|
84
|
-
'mongo': ` mongo:
|
|
85
|
-
image: mongo:7.0
|
|
86
|
-
container_name: mongo
|
|
87
|
-
command: [ "--replSet", "rs0", "--bind_ip_all", "--port", "27017" ]
|
|
88
|
-
ports:
|
|
89
|
-
- 27017:27017
|
|
90
|
-
healthcheck:
|
|
91
|
-
test: echo "try { rs.status() } catch (err) { rs.initiate({_id:'rs0',members:[{_id:0,host:'mongo:27017'}]}) }" | mongosh --port 27017 --quiet
|
|
92
|
-
interval: 5s
|
|
93
|
-
timeout: 30s
|
|
94
|
-
start_period: 0s
|
|
95
|
-
start_interval: 1s
|
|
96
|
-
retries: 30
|
|
97
|
-
volumes:
|
|
98
|
-
- "mongo_data:/data/db"
|
|
99
|
-
- "mongo_config:/data/configdb"`,
|
|
100
|
-
|
|
101
|
-
'kafka': ` kafka:
|
|
102
|
-
image: apache/kafka-native
|
|
103
|
-
container_name: kafka
|
|
104
|
-
ports:
|
|
105
|
-
- "9092:9092"
|
|
106
|
-
environment:
|
|
107
|
-
# Configure listeners for both docker and host communication
|
|
108
|
-
KAFKA_LISTENERS: CONTROLLER://localhost:9091,HOST://0.0.0.0:9092,DOCKER://0.0.0.0:9093
|
|
109
|
-
KAFKA_ADVERTISED_LISTENERS: HOST://kafka:9092,DOCKER://kafka:9093
|
|
110
|
-
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,DOCKER:PLAINTEXT,HOST:PLAINTEXT
|
|
111
|
-
|
|
112
|
-
# Settings required for KRaft mode
|
|
113
|
-
KAFKA_NODE_ID: 1
|
|
114
|
-
KAFKA_PROCESS_ROLES: broker,controller
|
|
115
|
-
KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER
|
|
116
|
-
KAFKA_CONTROLLER_QUORUM_VOTERS: 1@localhost:9091
|
|
117
|
-
|
|
118
|
-
# Listener to use for broker-to-broker communication
|
|
119
|
-
KAFKA_INTER_BROKER_LISTENER_NAME: DOCKER
|
|
120
|
-
|
|
121
|
-
# Required for a single node cluster
|
|
122
|
-
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
|
|
123
|
-
|
|
124
|
-
# Disable auto-topic creation - API server will create topics with correct partitions
|
|
125
|
-
KAFKA_AUTO_CREATE_TOPICS_ENABLE: "false"
|
|
126
|
-
volumes:
|
|
127
|
-
- "kafka_data:/var/lib/kafka/data"`,
|
|
128
|
-
|
|
129
|
-
'kafka-ui': ` kafka-ui:
|
|
130
|
-
image: kafbat/kafka-ui:main
|
|
131
|
-
container_name: kafka-ui
|
|
132
|
-
ports:
|
|
133
|
-
- 8080:8080
|
|
134
|
-
environment:
|
|
135
|
-
DYNAMIC_CONFIG_ENABLED: "true"
|
|
136
|
-
KAFKA_CLUSTERS_0_NAME: local
|
|
137
|
-
KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS: kafka:9093
|
|
138
|
-
depends_on:
|
|
139
|
-
- kafka`,
|
|
140
|
-
|
|
141
|
-
'redis': ` redis:
|
|
142
|
-
image: redis:7-alpine
|
|
143
|
-
container_name: redis
|
|
144
|
-
ports:
|
|
145
|
-
- "6379:6379"
|
|
146
|
-
command: redis-server --appendonly yes
|
|
147
|
-
volumes:
|
|
148
|
-
- "redis_data:/data"
|
|
149
|
-
healthcheck:
|
|
150
|
-
test: [ "CMD", "redis-cli", "ping" ]
|
|
151
|
-
interval: 5s
|
|
152
|
-
timeout: 3s
|
|
153
|
-
retries: 5`,
|
|
154
|
-
|
|
155
|
-
'loki': ` loki:
|
|
156
|
-
image: grafana/loki:2.9.0
|
|
157
|
-
container_name: loki
|
|
158
|
-
ports:
|
|
159
|
-
- "3100:3100"
|
|
160
|
-
command: -config.file=/etc/loki/local-config.yaml
|
|
161
|
-
volumes:
|
|
162
|
-
- "loki_data:/loki"
|
|
163
|
-
healthcheck:
|
|
164
|
-
test: [ "CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:3100/ready || exit 1" ]
|
|
165
|
-
interval: 10s
|
|
166
|
-
timeout: 5s
|
|
167
|
-
retries: 5`,
|
|
168
|
-
|
|
169
|
-
'grafana': ` grafana:
|
|
170
|
-
image: grafana/grafana:10.2.0
|
|
171
|
-
container_name: grafana
|
|
172
|
-
ports:
|
|
173
|
-
- "3001:3000"
|
|
174
|
-
environment:
|
|
175
|
-
- GF_PATHS_PROVISIONING=/etc/grafana/provisioning
|
|
176
|
-
- GF_AUTH_ANONYMOUS_ENABLED=true
|
|
177
|
-
- GF_AUTH_ANONYMOUS_ORG_ROLE=Admin
|
|
178
|
-
- GF_SECURITY_ADMIN_PASSWORD=admin
|
|
179
|
-
volumes:
|
|
180
|
-
- "grafana_data:/var/lib/grafana"
|
|
181
|
-
depends_on:
|
|
182
|
-
loki:
|
|
183
|
-
condition: service_healthy`,
|
|
184
|
-
|
|
185
|
-
'nginx': ` nginx:
|
|
186
|
-
image: nginx:alpine
|
|
187
|
-
container_name: nginx
|
|
188
|
-
ports:
|
|
189
|
-
- "80:80"
|
|
190
|
-
volumes:
|
|
191
|
-
- "./nginx.conf:/etc/nginx/conf.d/default.conf:ro"
|
|
192
|
-
restart: unless-stopped`,
|
|
193
|
-
};
|
|
194
|
-
|
|
195
|
-
const NGINX_INFRA_SSL_SERVICE_CHUNK = ` nginx:
|
|
196
|
-
image: nginx:alpine
|
|
197
|
-
container_name: nginx
|
|
198
|
-
ports:
|
|
199
|
-
- "80:80"
|
|
200
|
-
- "443:443"
|
|
201
|
-
volumes:
|
|
202
|
-
- "./nginx.conf:/etc/nginx/conf.d/default.conf:ro"
|
|
203
|
-
- certbot-etc:/etc/letsencrypt
|
|
204
|
-
- certbot-www:/var/www/certbot
|
|
205
|
-
restart: unless-stopped`;
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* Service-to-volumes mapping
|
|
209
|
-
*/
|
|
210
|
-
const SERVICE_VOLUMES: Record<string, string[]> = {
|
|
211
|
-
'mongo': ['mongo_data', 'mongo_config'],
|
|
212
|
-
'kafka': ['kafka_data'],
|
|
213
|
-
'kafka-ui': [],
|
|
214
|
-
'redis': ['redis_data'],
|
|
215
|
-
'nginx': [],
|
|
216
|
-
'loki': ['loki_data'],
|
|
217
|
-
'grafana': ['grafana_data'],
|
|
218
|
-
};
|
|
219
|
-
|
|
220
|
-
/**
|
|
221
|
-
* Build docker-compose content from selected services
|
|
222
|
-
*/
|
|
223
|
-
function buildInfraCompose(
|
|
224
|
-
selectedServices: string[],
|
|
225
|
-
options: { includeSsl?: boolean } = {}
|
|
226
|
-
): string {
|
|
227
|
-
// Header
|
|
228
|
-
const header = `# ============================================
|
|
229
|
-
# SimpleNS Infrastructure Services
|
|
230
|
-
# All services use Docker service names for container-to-container communication.
|
|
231
|
-
# This ensures cross-platform compatibility (Windows, Linux, macOS).
|
|
232
|
-
# ============================================
|
|
233
|
-
|
|
234
|
-
services:
|
|
235
|
-
# ============================================
|
|
236
|
-
# Infrastructure Services
|
|
237
|
-
# ============================================`;
|
|
238
|
-
|
|
239
|
-
// Assemble selected service chunks
|
|
240
|
-
const serviceBlocks: string[] = [];
|
|
241
|
-
for (const service of selectedServices) {
|
|
242
|
-
if (SERVICE_CHUNKS[service]) {
|
|
243
|
-
if (service === 'nginx' && options.includeSsl === true) {
|
|
244
|
-
serviceBlocks.push(NGINX_INFRA_SSL_SERVICE_CHUNK);
|
|
245
|
-
} else {
|
|
246
|
-
serviceBlocks.push(SERVICE_CHUNKS[service]);
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
if (options.includeSsl === true) {
|
|
252
|
-
serviceBlocks.push(INFRA_CERTBOT_SERVICES_TEMPLATE);
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
// Collect volumes for selected services
|
|
256
|
-
const volumeSet = new Set<string>();
|
|
257
|
-
for (const service of selectedServices) {
|
|
258
|
-
const volumes = SERVICE_VOLUMES[service] || [];
|
|
259
|
-
volumes.forEach(v => volumeSet.add(v));
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
if (options.includeSsl === true) {
|
|
263
|
-
for (const volumeName of INFRA_CERTBOT_VOLUMES) {
|
|
264
|
-
volumeSet.add(volumeName);
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
// Build volumes section
|
|
269
|
-
const volumeLines: string[] = ['', 'volumes:'];
|
|
270
|
-
for (const volume of Array.from(volumeSet).sort()) {
|
|
271
|
-
volumeLines.push(` ${volume}:`);
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
// Build networks section with custom default network name
|
|
275
|
-
const networkLines: string[] = ['', 'networks:', ' default:', ' name: simplens'];
|
|
276
|
-
|
|
277
|
-
// Combine all parts
|
|
278
|
-
return [
|
|
279
|
-
header,
|
|
280
|
-
serviceBlocks.join('\n\n'),
|
|
281
|
-
volumeLines.join('\n'),
|
|
282
|
-
networkLines.join('\n'),
|
|
283
|
-
].join('\n');
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
/**
|
|
289
|
-
* Generate and write docker-compose.infra.yaml
|
|
290
|
-
*/
|
|
291
|
-
export async function generateInfraCompose(
|
|
292
|
-
targetDir: string,
|
|
293
|
-
selectedServices: string[],
|
|
294
|
-
options: { includeSsl?: boolean } = {}
|
|
295
|
-
): Promise<void> {
|
|
296
|
-
const s = spinner();
|
|
297
|
-
s.start('Generating docker-compose.infra.yaml...');
|
|
298
|
-
|
|
299
|
-
// Build compose content from service chunks
|
|
300
|
-
const infraContent = buildInfraCompose(selectedServices, options);
|
|
301
|
-
|
|
302
|
-
// Write infrastructure compose file
|
|
303
|
-
const infraPath = path.join(targetDir, 'docker-compose.infra.yaml');
|
|
304
|
-
await writeFile(infraPath, infraContent);
|
|
305
|
-
s.stop('Generated docker-compose.infra.yaml');
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
/**
|
|
309
|
-
* Build app docker-compose content.
|
|
310
|
-
* Optionally inject nginx reverse-proxy service before the volumes section.
|
|
311
|
-
*/
|
|
312
|
-
export function buildAppComposeContent(
|
|
313
|
-
includeNginx: boolean,
|
|
314
|
-
options: { includeSsl?: boolean } = {}
|
|
315
|
-
): string {
|
|
316
|
-
let content = APP_COMPOSE_TEMPLATE;
|
|
317
|
-
const includeSsl = options.includeSsl === true;
|
|
318
|
-
const shouldIncludeNginx = includeNginx || includeSsl;
|
|
319
|
-
const marker = '\nvolumes:';
|
|
320
|
-
|
|
321
|
-
if (!content.includes(marker)) {
|
|
322
|
-
return content;
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
if (shouldIncludeNginx) {
|
|
326
|
-
const nginxBlock = includeSsl
|
|
327
|
-
? APP_NGINX_SSL_SERVICE_TEMPLATE
|
|
328
|
-
: APP_NGINX_SERVICE_TEMPLATE;
|
|
329
|
-
content = content.replace(marker, `\n${nginxBlock}\n${marker}`);
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
if (includeSsl) {
|
|
333
|
-
content = content.replace(marker, `\n${APP_CERTBOT_SERVICES_TEMPLATE}\n${marker}`);
|
|
334
|
-
content = content.replace(
|
|
335
|
-
'\nvolumes:\n plugin-data:',
|
|
336
|
-
'\nvolumes:\n certbot-etc:\n certbot-www:\n plugin-data:'
|
|
337
|
-
);
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
return content;
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
/**
|
|
344
|
-
* Write app docker-compose.yaml
|
|
345
|
-
*/
|
|
346
|
-
export async function writeAppCompose(
|
|
347
|
-
targetDir: string,
|
|
348
|
-
options: { includeNginx?: boolean; includeSsl?: boolean } = {}
|
|
349
|
-
): Promise<void> {
|
|
350
|
-
const s = spinner();
|
|
351
|
-
s.start('Generating docker-compose.yaml...');
|
|
352
|
-
const appPath = path.join(targetDir, 'docker-compose.yaml');
|
|
353
|
-
const appContent = buildAppComposeContent(options.includeNginx === true, {
|
|
354
|
-
includeSsl: options.includeSsl === true,
|
|
355
|
-
});
|
|
356
|
-
await writeFile(appPath, appContent);
|
|
357
|
-
s.stop('Generated docker-compose.yaml');
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
/**
|
|
361
|
-
* Generate nginx.conf based on basePath configuration
|
|
362
|
-
*/
|
|
363
|
-
export async function generateNginxConfig(
|
|
364
|
-
targetDir: string,
|
|
365
|
-
basePath: string,
|
|
366
|
-
options: { enableSsl?: boolean; domain?: string; sslMode?: 'bootstrap' | 'final' } = {}
|
|
367
|
-
): Promise<void> {
|
|
368
|
-
const s = spinner();
|
|
369
|
-
s.start('Generating nginx.conf...');
|
|
370
|
-
|
|
371
|
-
// Normalize basePath (remove leading/trailing slashes for template)
|
|
372
|
-
const normalizedPath = basePath.trim().replace(/^\/|\/$/g, '');
|
|
373
|
-
const hasBasePath = normalizedPath.length > 0;
|
|
374
|
-
const enableSsl = options.enableSsl === true;
|
|
375
|
-
const domain = options.domain?.trim() || 'localhost';
|
|
376
|
-
const sslMode = options.sslMode ?? 'final';
|
|
377
|
-
|
|
378
|
-
const proxyRoutes = `
|
|
379
|
-
location /api {
|
|
380
|
-
proxy_pass http://api:3000;
|
|
381
|
-
proxy_http_version 1.1;
|
|
382
|
-
|
|
383
|
-
proxy_set_header Host $host;
|
|
384
|
-
proxy_set_header X-Real-IP $remote_addr;
|
|
385
|
-
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
386
|
-
proxy_set_header X-Forwarded-Proto $scheme;
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
location = /runtime-config.js {
|
|
390
|
-
proxy_pass http://dashboard:3002/runtime-config.js;
|
|
391
|
-
proxy_http_version 1.1;
|
|
392
|
-
|
|
393
|
-
proxy_set_header Host $host;
|
|
394
|
-
proxy_set_header X-Real-IP $remote_addr;
|
|
395
|
-
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
396
|
-
proxy_set_header X-Forwarded-Proto $scheme;
|
|
397
|
-
|
|
398
|
-
# optional: prevent caching if config is dynamic
|
|
399
|
-
add_header Cache-Control "no-store";
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
location ^~ /_next/ {
|
|
403
|
-
proxy_pass http://dashboard:3002/_next/;
|
|
404
|
-
proxy_http_version 1.1;
|
|
405
|
-
|
|
406
|
-
proxy_set_header Host $host;
|
|
407
|
-
proxy_set_header X-Real-IP $remote_addr;
|
|
408
|
-
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
409
|
-
proxy_set_header X-Forwarded-Proto $scheme;
|
|
410
|
-
|
|
411
|
-
expires 1y;
|
|
412
|
-
add_header Cache-Control "public, immutable";
|
|
413
|
-
}
|
|
414
|
-
${hasBasePath ? `
|
|
415
|
-
location ^~ /${normalizedPath}/_next/ {
|
|
416
|
-
proxy_pass http://dashboard:3002/_next/;
|
|
417
|
-
proxy_http_version 1.1;
|
|
418
|
-
|
|
419
|
-
proxy_set_header Host $host;
|
|
420
|
-
proxy_set_header X-Real-IP $remote_addr;
|
|
421
|
-
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
422
|
-
proxy_set_header X-Forwarded-Proto $scheme;
|
|
423
|
-
|
|
424
|
-
expires 1y;
|
|
425
|
-
add_header Cache-Control "public, immutable";
|
|
426
|
-
}
|
|
427
|
-
` : ''}
|
|
428
|
-
location ~* \\.(png|jpg|jpeg|gif|ico|svg|webp|woff|woff2|ttf|eot)$ {
|
|
429
|
-
proxy_pass http://dashboard:3002;
|
|
430
|
-
proxy_http_version 1.1;
|
|
431
|
-
|
|
432
|
-
proxy_set_header Host $host;
|
|
433
|
-
proxy_set_header X-Real-IP $remote_addr;
|
|
434
|
-
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
435
|
-
proxy_set_header X-Forwarded-Proto $scheme;
|
|
436
|
-
|
|
437
|
-
expires 1y;
|
|
438
|
-
add_header Cache-Control "public, max-age=31536000";
|
|
439
|
-
}
|
|
440
|
-
${hasBasePath ? `
|
|
441
|
-
location ^~ /${normalizedPath} {
|
|
442
|
-
proxy_pass http://dashboard:3002;
|
|
443
|
-
proxy_http_version 1.1;
|
|
444
|
-
|
|
445
|
-
proxy_set_header Host $host;
|
|
446
|
-
proxy_set_header X-Real-IP $remote_addr;
|
|
447
|
-
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
448
|
-
proxy_set_header X-Forwarded-Proto $scheme;
|
|
449
|
-
}
|
|
450
|
-
` : `
|
|
451
|
-
location / {
|
|
452
|
-
proxy_pass http://dashboard:3002;
|
|
453
|
-
proxy_http_version 1.1;
|
|
454
|
-
|
|
455
|
-
proxy_set_header Host $host;
|
|
456
|
-
proxy_set_header X-Real-IP $remote_addr;
|
|
457
|
-
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
458
|
-
proxy_set_header X-Forwarded-Proto $scheme;
|
|
459
|
-
}
|
|
460
|
-
`}
|
|
461
|
-
`;
|
|
462
|
-
|
|
463
|
-
const rootRedirectPath = hasBasePath ? `/${normalizedPath}` : '/';
|
|
464
|
-
|
|
465
|
-
const nginxTemplate = enableSsl
|
|
466
|
-
? sslMode === 'bootstrap'
|
|
467
|
-
? `server {
|
|
468
|
-
listen 80;
|
|
469
|
-
server_name ${domain};
|
|
470
|
-
|
|
471
|
-
location /.well-known/acme-challenge/ {
|
|
472
|
-
root /var/www/certbot;
|
|
473
|
-
}
|
|
474
|
-
${proxyRoutes}
|
|
475
|
-
}
|
|
476
|
-
`
|
|
477
|
-
: `server {
|
|
478
|
-
listen 80;
|
|
479
|
-
server_name ${domain};
|
|
480
|
-
|
|
481
|
-
location /.well-known/acme-challenge/ {
|
|
482
|
-
root /var/www/certbot;
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
location / {
|
|
486
|
-
return 301 https://$host$request_uri;
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
server {
|
|
491
|
-
listen 443 ssl;
|
|
492
|
-
server_name ${domain};
|
|
493
|
-
|
|
494
|
-
ssl_certificate /etc/letsencrypt/live/${domain}/fullchain.pem;
|
|
495
|
-
ssl_certificate_key /etc/letsencrypt/live/${domain}/privkey.pem;
|
|
496
|
-
ssl_protocols TLSv1.2 TLSv1.3;
|
|
497
|
-
ssl_prefer_server_ciphers on;
|
|
498
|
-
location = / {
|
|
499
|
-
return 302 ${rootRedirectPath};
|
|
500
|
-
}
|
|
501
|
-
${proxyRoutes}
|
|
502
|
-
}
|
|
503
|
-
`
|
|
504
|
-
: `server {
|
|
505
|
-
listen 80;
|
|
506
|
-
server_name localhost;${proxyRoutes}
|
|
507
|
-
}
|
|
508
|
-
`;
|
|
509
|
-
|
|
510
|
-
const nginxPath = path.join(targetDir, 'nginx.conf');
|
|
511
|
-
await writeFile(nginxPath, nginxTemplate);
|
|
512
|
-
const sslLabel = enableSsl ? `, SSL domain: ${domain}` : '';
|
|
513
|
-
s.stop(`Generated nginx.conf${hasBasePath ? ` with base path: /${normalizedPath}` : ' (root path)'}${sslLabel}`);
|
|
514
|
-
}
|