Compare commits

..

66 Commits

Author SHA1 Message Date
88d5bbb432 v2.0.53 2025-11-27 13:14:58 +00:00
5781204c88 fix(core): Refactor filesystem usage to smartfs async provider, update dependencies, tests and nginx config paths 2025-11-27 13:14:58 +00:00
5700522b8a update description 2024-05-29 14:15:00 +02:00
e266a5b22e update tsconfig 2024-04-14 18:02:55 +02:00
c9eef34901 update npmextra.json: githost 2024-04-01 21:36:51 +02:00
da85018206 update npmextra.json: githost 2024-04-01 19:59:05 +02:00
cc54dfcf56 update npmextra.json: githost 2024-03-30 21:48:05 +01:00
4016a957cf 2.0.52 2023-07-26 16:05:53 +02:00
509ee83a15 fix(core): update 2023-07-26 16:05:53 +02:00
1b6b2a24f1 switch to new org scheme 2023-07-10 10:16:53 +02:00
f18f008f84 2.0.51 2019-08-21 00:07:28 +02:00
9e1ed36def fix(core): update 2019-08-21 00:07:28 +02:00
8a35725448 2.0.50 2019-08-20 22:30:32 +02:00
5438f83a40 fix(core): update 2019-08-20 22:30:31 +02:00
5c4d5a4a85 2.0.49 2019-08-20 22:28:48 +02:00
1be3f7f388 fix(core): update 2019-08-20 22:28:48 +02:00
8c2aa23406 2.0.48 2019-08-14 13:06:05 +02:00
d2d4ad70ce fix(core): update 2019-08-14 13:06:04 +02:00
e3817f92c7 2.0.47 2019-04-11 02:01:45 +02:00
159c043ba6 fix(core): update 2019-04-11 02:01:44 +02:00
fbdb98c355 2.0.46 2019-04-11 01:42:49 +02:00
b81dc319e2 fix(core): update 2019-04-11 01:42:48 +02:00
eec249d68f 2.0.45 2019-04-11 01:32:08 +02:00
0f4a5b0cc1 fix(core): update 2019-04-11 01:32:08 +02:00
20c23751a4 2.0.44 2019-04-11 00:40:34 +02:00
6aaae7683b fix(core): update 2019-04-11 00:40:33 +02:00
826ae9f157 2.0.43 2019-04-11 00:15:06 +02:00
9dbeef0ed2 fix(core): update 2019-04-11 00:15:06 +02:00
53f6daa5d5 2.0.42 2019-04-10 23:15:37 +02:00
9ee5cd2a3d fix(core): update 2019-04-10 23:15:37 +02:00
13c27bb71e 2.0.41 2019-04-10 23:14:08 +02:00
2be54dd505 fix(core): update 2019-04-10 23:14:08 +02:00
2c5af1840e 2.0.40 2019-04-10 19:03:17 +02:00
e5b75014af fix(core): update 2019-04-10 19:03:17 +02:00
82f3b4bd7d 2.0.39 2019-02-02 12:10:00 +01:00
4186e77ca0 fix(core): cleanup 2019-02-02 12:09:59 +01:00
6a05c0087f 2.0.38 2019-01-25 12:37:13 +01:00
4206c9bc8a fix(core): update 2019-01-25 12:37:12 +01:00
0aa6966dc1 2.0.37 2019-01-22 22:42:54 +01:00
5bbd773460 fix(core): update 2019-01-22 22:42:54 +01:00
2c81f8b492 2.0.36 2019-01-22 22:07:59 +01:00
0fe7d586cf fix(core): update 2019-01-22 22:07:58 +01:00
a4c8b789ad 2.0.35 2019-01-22 22:05:03 +01:00
b4378e305a fix(core): update 2019-01-22 22:05:02 +01:00
5ff0980908 2.0.34 2019-01-22 18:59:56 +01:00
e60257d761 fix(core): update 2019-01-22 18:59:55 +01:00
e94f0edafb 2.0.33 2019-01-22 18:25:44 +01:00
c417d96e48 fix(core): update 2019-01-22 18:25:43 +01:00
c5b1dbb46e 2.0.32 2019-01-22 12:33:48 +01:00
893a2e2709 fix(core): update 2019-01-22 12:33:47 +01:00
01f0dc6b20 2.0.31 2019-01-22 12:11:32 +01:00
736a42066c fix(core): update 2019-01-22 12:11:31 +01:00
44403863d1 2.0.30 2019-01-22 12:03:00 +01:00
5be21fa100 fix(core): update 2019-01-22 12:02:59 +01:00
042167c01e 2.0.29 2019-01-22 04:03:17 +01:00
db38d038ef fix(core): update 2019-01-22 04:03:17 +01:00
a4d8a46360 2.0.28 2019-01-19 15:57:50 +01:00
84e5c10129 fix(core): update 2019-01-19 15:57:49 +01:00
98a2871f08 2.0.27 2019-01-19 15:42:46 +01:00
9bb847210a fix(core): update 2019-01-19 15:42:45 +01:00
91d4ba5715 2.0.26 2019-01-19 15:41:51 +01:00
3ee2988964 fix(core): update 2019-01-19 15:41:51 +01:00
221f1f6237 2.0.25 2019-01-19 12:17:47 +01:00
0a6fbf588e fix(core): update 2019-01-19 12:17:47 +01:00
1a8546af6e 2.0.24 2019-01-19 11:07:14 +01:00
9e01bdb8e2 fix(core): update 2019-01-19 11:07:14 +01:00
53 changed files with 9352 additions and 2209 deletions

View File

@@ -0,0 +1,66 @@
name: Default (not tags)
on:
push:
tags-ignore:
- '**'
env:
IMAGE: registry.gitlab.com/hosttoday/ht-docker-node:npmci
NPMCI_COMPUTED_REPOURL: https://${{gitea.repository_owner}}:${{secrets.GITEA_TOKEN}}@gitea.lossless.digital/${{gitea.repository}}.git
NPMCI_TOKEN_NPM: ${{secrets.NPMCI_TOKEN_NPM}}
NPMCI_TOKEN_NPM2: ${{secrets.NPMCI_TOKEN_NPM2}}
NPMCI_GIT_GITHUBTOKEN: ${{secrets.NPMCI_GIT_GITHUBTOKEN}}
NPMCI_URL_CLOUDLY: ${{secrets.NPMCI_URL_CLOUDLY}}
jobs:
security:
runs-on: ubuntu-latest
continue-on-error: true
container:
image: ${{ env.IMAGE }}
steps:
- uses: actions/checkout@v3
- name: Install pnpm and npmci
run: |
pnpm install -g pnpm
pnpm install -g @shipzone/npmci
- name: Run npm prepare
run: npmci npm prepare
- name: Audit production dependencies
run: |
npmci command npm config set registry https://registry.npmjs.org
npmci command pnpm audit --audit-level=high --prod
continue-on-error: true
- name: Audit development dependencies
run: |
npmci command npm config set registry https://registry.npmjs.org
npmci command pnpm audit --audit-level=high --dev
continue-on-error: true
test:
if: ${{ always() }}
needs: security
runs-on: ubuntu-latest
container:
image: ${{ env.IMAGE }}
steps:
- uses: actions/checkout@v3
- name: Test stable
run: |
npmci node install stable
npmci npm install
npmci npm test
- name: Test build
run: |
npmci node install stable
npmci npm install
npmci npm build

View File

@@ -0,0 +1,124 @@
name: Default (tags)
on:
push:
tags:
- '*'
env:
IMAGE: registry.gitlab.com/hosttoday/ht-docker-node:npmci
NPMCI_COMPUTED_REPOURL: https://${{gitea.repository_owner}}:${{secrets.GITEA_TOKEN}}@gitea.lossless.digital/${{gitea.repository}}.git
NPMCI_TOKEN_NPM: ${{secrets.NPMCI_TOKEN_NPM}}
NPMCI_TOKEN_NPM2: ${{secrets.NPMCI_TOKEN_NPM2}}
NPMCI_GIT_GITHUBTOKEN: ${{secrets.NPMCI_GIT_GITHUBTOKEN}}
NPMCI_URL_CLOUDLY: ${{secrets.NPMCI_URL_CLOUDLY}}
jobs:
security:
runs-on: ubuntu-latest
continue-on-error: true
container:
image: ${{ env.IMAGE }}
steps:
- uses: actions/checkout@v3
- name: Prepare
run: |
pnpm install -g pnpm
pnpm install -g @shipzone/npmci
npmci npm prepare
- name: Audit production dependencies
run: |
npmci command npm config set registry https://registry.npmjs.org
npmci command pnpm audit --audit-level=high --prod
continue-on-error: true
- name: Audit development dependencies
run: |
npmci command npm config set registry https://registry.npmjs.org
npmci command pnpm audit --audit-level=high --dev
continue-on-error: true
test:
if: ${{ always() }}
needs: security
runs-on: ubuntu-latest
container:
image: ${{ env.IMAGE }}
steps:
- uses: actions/checkout@v3
- name: Prepare
run: |
pnpm install -g pnpm
pnpm install -g @shipzone/npmci
npmci npm prepare
- name: Test stable
run: |
npmci node install stable
npmci npm install
npmci npm test
- name: Test build
run: |
npmci node install stable
npmci npm install
npmci npm build
release:
needs: test
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-latest
container:
image: ${{ env.IMAGE }}
steps:
- uses: actions/checkout@v3
- name: Prepare
run: |
pnpm install -g pnpm
pnpm install -g @shipzone/npmci
npmci npm prepare
- name: Release
run: |
npmci node install stable
npmci npm publish
metadata:
needs: test
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-latest
container:
image: ${{ env.IMAGE }}
continue-on-error: true
steps:
- uses: actions/checkout@v3
- name: Prepare
run: |
pnpm install -g pnpm
pnpm install -g @shipzone/npmci
npmci npm prepare
- name: Code quality
run: |
npmci command npm install -g typescript
npmci npm install
- name: Trigger
run: npmci trigger
- name: Build docs and upload artifacts
run: |
npmci node install stable
npmci npm install
pnpm install -g @gitzone/tsdoc
npmci command tsdoc
continue-on-error: true

23
.gitignore vendored
View File

@@ -1,5 +1,20 @@
node_modules/
nginxconfig/
coverage/
docs/
.nogit/
# artifacts
coverage/
public/
pages/
# installs
node_modules/
# caches
.yarn/
.cache/
.rpt2_cache
# builds
dist/
dist_*/
# custom

View File

@@ -1,30 +0,0 @@
image: hosttoday/ht-docker-node:npmci
stages:
- test
- release
before_script:
- "apt-get update && apt-get install nginx -y"
testSTABLE:
stage: test
script:
- npmci npm install
- npmci npm test stable
only:
- tags
tags:
- docker
- notpriv
release:
stage: release
environment: npmjs-com_registry
script:
- npmci npm prepare
- npmci npm publish
only:
- tags
tags:
- docker

11
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,11 @@
{
"version": "0.2.0",
"configurations": [
{
"command": "npm test",
"name": "Run npm test",
"request": "launch",
"type": "node-terminal"
}
]
}

26
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,26 @@
{
"json.schemas": [
{
"fileMatch": ["/npmextra.json"],
"schema": {
"type": "object",
"properties": {
"npmci": {
"type": "object",
"description": "settings for npmci"
},
"gitzone": {
"type": "object",
"description": "settings for gitzone",
"properties": {
"projectType": {
"type": "string",
"enum": ["website", "element", "service", "npm", "wcc"]
}
}
}
}
}
}
]
}

View File

@@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2016 Lossless GmbH
Copyright (c) 2016 Task Venture Capital GmbH
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -1,30 +0,0 @@
# smartnginx
control nginx from node, TypeScript ready
## Status
[![build status](https://gitlab.com/pushrocks/smartnginx/badges/master/build.svg)](https://gitlab.com/pushrocks/smartnginx/commits/master)
## Features
- easy reverse configuration
- automatic letsencrypt DNS01 challenge based ssl cert generation
- automatic nginx process handling zero-downtime config reloading
- works in Docker environements
## Usage
We recommend the use of TypeScript! :)
```typescript
import * as smartnginx from 'smartnginx';
const smartnginxInstance = new smartnginx.SmartNginx();
myNginxHost = new smartnginx.NginxHost({
hostName: 'some.example.com',
type: 'reverseProxy',
destination: '192.192.192.192' // some destination IP
});
myNginxConfig.addZone(myNginxZone); // adds the zone to the config
myNginxConfig.deploy(); // deploys the referenced NginxConfig and gracefully reloads it
```

59
changelog.md Normal file
View File

@@ -0,0 +1,59 @@
# Changelog
## 2025-11-27 - 2.0.53 - fix(core)
Refactor filesystem usage to smartfs async provider, update dependencies, tests and nginx config paths
- Replace @push.rocks/smartfile usage with @push.rocks/smartfs and introduce a shared SmartFs instance in plugins
- Convert sync file operations to async fs APIs (plugins.fs.file(...).write / plugins.fs.directory(...).create) in SmartNginx and NginxHost
- Adjust package.json: update test/build scripts, replace dependencies/devDependencies to new packages (@push.rocks/smartfs, @git.zone/*), and update versions
- Update test imports to new tapbundle path and node:path; export default tap.start() and remove unused Qenv instantiation
- Update internal path imports to 'node:path' and refactor smartnginx.plugins exports
- Change generated nginx certificate/config paths in configs from /mnt/HC_Volume_11396573/... to /mnt/data/... and regenerate default cert files
- Remove CI config (.gitlab-ci.yml) from repository
## 2024-05-29 - 2.0.52 - maintenance
Various metadata and TypeScript configuration updates; release 2.0.52.
- Update package description.
- Update tsconfig.
- Update npmextra.json (githost) entries across multiple commits.
- Release tag for 2.0.52.
## 2023-07-26 - 2.0.51 - maintenance
Org migration and core fixes; release 2.0.51.
- Switch to new organization scheme.
- fix(core): miscellaneous updates.
- Release tag for 2.0.51.
## 2019-01-09..2019-08-20 - 2.0.19..2.0.50 - maintenance (multiple patch releases)
Series of incremental patch releases with small fixes and cleanups.
- Many patch releases across the 2.0.x line (2.0.19 through 2.0.50).
- Multiple "fix(core): update" commits addressing internal issues.
- CI and cleanup fixes (including 2.0.38 cleanup).
- Release tags for each patch.
## 2018-08-10 - 2.0.0 - breaking
Major release and scope / packaging changes.
- 2.0.0 release with core updates.
- BREAKING CHANGE: change scope to @pushrocks (package scope/name changed).
- Various CI and core fixes accompanying the major release.
## 2016-08-03..2016-07-25 - 1.0.6..1.0.0 - release / maintenance
1.x series consolidations, dependency updates and interface exports.
- Update dependencies and types.
- Consolidate naming and start exporting interfaces.
- Add license.
- Release tags for 1.0.0 through 1.0.6.
## 2016-07-06..2016-07-25 - 0.0.0..0.1.0 - initial development
Initial implementation and feature work establishing core functionality.
- Initial project setup, README and CI added.
- Implement nginx communication and child process handling.
- Start storing generated configs to filesystem and improve config handling.
- Add snippets support and tests; multiple README improvements.
- Early releases and version tags (0.0.0 through 0.1.0).

3
dist/index.d.ts vendored
View File

@@ -1,3 +0,0 @@
export * from "./smartnginx.classes.nginxconfig";
export * from "./smartnginx.classes.nginxprocess";
export * from "./smartnginx.classes.nginxhost";

9
dist/index.js vendored
View File

@@ -1,9 +0,0 @@
"use strict";
function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
// classes
__export(require("./smartnginx.classes.nginxconfig"));
__export(require("./smartnginx.classes.nginxprocess"));
__export(require("./smartnginx.classes.nginxhost"));
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7O0FBRUEsVUFBVTtBQUNWLGlCQUFjLGtDQUFrQyxDQUFDLEVBQUE7QUFDakQsaUJBQWMsbUNBQW1DLENBQUMsRUFBQTtBQUNsRCxpQkFBYyxnQ0FBZ0MsQ0FBQyxFQUFBIn0=

View File

@@ -1,19 +0,0 @@
/// <reference types="q" />
import * as plugins from "./smartnginx.plugins";
import { NginxHost } from "./smartnginx.classes.nginxhost";
import { NginxProcess } from "./smartnginx.classes.nginxprocess";
/**
* main class that manages a NginxInstance
*/
export declare class NginxConfig {
hosts: NginxHost[];
cert: plugins.cert.Cert;
nginxProcess: NginxProcess;
isDeployed: boolean;
constructor(optionsArg: plugins.cert.ICertConstructorOptions);
addHost(nginxHostArg: NginxHost): void;
listHosts(): NginxHost[];
removeHost(nginxHostArg: NginxHost): void;
clean(): void;
deploy(): plugins.q.Promise<{}>;
}

View File

@@ -1,71 +0,0 @@
"use strict";
const plugins = require("./smartnginx.plugins");
const paths = require("./smartnginx.paths");
const snippets = require("./smartnginx.snippets");
const smartnginx_classes_nginxprocess_1 = require("./smartnginx.classes.nginxprocess");
let allConfigs = [];
/**
* main class that manages a NginxInstance
*/
class NginxConfig {
constructor(optionsArg) {
this.hosts = [];
this.nginxProcess = new smartnginx_classes_nginxprocess_1.NginxProcess(this);
this.isDeployed = false;
this.cert = new plugins.cert.Cert({
cfEmail: optionsArg.cfEmail,
cfKey: optionsArg.cfKey,
sslDir: paths.nginxCertBase,
gitOriginRepo: optionsArg.gitOriginRepo,
testMode: optionsArg.testMode
});
}
;
// interact with Hosts
addHost(nginxHostArg) {
this.hosts.push(nginxHostArg);
}
listHosts() {
return this.hosts;
}
;
removeHost(nginxHostArg) {
}
clean() {
this.hosts = [];
}
// handle deployment of hosts
deploy() {
let done = plugins.q.defer();
plugins.smartfile.fs.ensureDirSync(paths.nginxConfigBase);
plugins.smartfile.fs.ensureDirSync(paths.nginxHostFileBase);
plugins.smartfile.fs.ensureDirSync(paths.nginxCertBase);
for (let config of allConfigs) {
config.isDeployed = false;
}
;
this.isDeployed = true;
// write base config
plugins.smartfile.memory.toFsSync(snippets.getBaseConfigString(), paths.nginxConfFile);
// deploy hosts
let promiseArray = [];
for (let host of this.hosts) {
let hostDeployedPromise = host.deploy(this.cert);
hostDeployedPromise.then(() => {
plugins.beautylog.info(`Host ${host.hostName} deployed!`);
this.nginxProcess.reloadConfig();
});
promiseArray.push(hostDeployedPromise);
}
;
plugins.q.all(promiseArray)
.then(() => {
done.resolve();
});
return done.promise;
}
;
}
exports.NginxConfig = NginxConfig;
;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRuZ2lueC5jbGFzc2VzLm5naW54Y29uZmlnLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvc21hcnRuZ2lueC5jbGFzc2VzLm5naW54Y29uZmlnLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSxNQUFZLE9BQU8sV0FBTSxzQkFBc0IsQ0FBQyxDQUFBO0FBQ2hELE1BQVksS0FBSyxXQUFNLG9CQUFvQixDQUFDLENBQUE7QUFDNUMsTUFBWSxRQUFRLFdBQU0sdUJBQXVCLENBQUMsQ0FBQTtBQUVsRCxrREFBNkIsbUNBQW1DLENBQUMsQ0FBQTtBQUNqRSxJQUFJLFVBQVUsR0FBa0IsRUFBRSxDQUFDO0FBRW5DOztHQUVHO0FBQ0g7SUFLSSxZQUFZLFVBQWdEO1FBSjVELFVBQUssR0FBZ0IsRUFBRSxDQUFDO1FBRXhCLGlCQUFZLEdBQWlCLElBQUksOENBQVksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUNwRCxlQUFVLEdBQVksS0FBSyxDQUFDO1FBRXhCLElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBSSxPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQztZQUM5QixPQUFPLEVBQUUsVUFBVSxDQUFDLE9BQU87WUFDM0IsS0FBSyxFQUFFLFVBQVUsQ0FBQyxLQUFLO1lBQ3ZCLE1BQU0sRUFBRSxLQUFLLENBQUMsYUFBYTtZQUMzQixhQUFhLEVBQUUsVUFBVSxDQUFDLGFBQWE7WUFDdkMsUUFBUSxFQUFFLFVBQVUsQ0FBQyxRQUFRO1NBQ2hDLENBQUMsQ0FBQztJQUNQLENBQUM7O0lBRUQsc0JBQXNCO0lBQ3RCLE9BQU8sQ0FBQyxZQUF1QjtRQUMzQixJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQztJQUNsQyxDQUFDO0lBQ0QsU0FBUztRQUNMLE1BQU0sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDO0lBQ3RCLENBQUM7O0lBQ0QsVUFBVSxDQUFDLFlBQXVCO0lBRWxDLENBQUM7SUFDRCxLQUFLO1FBQ0QsSUFBSSxDQUFDLEtBQUssR0FBRyxFQUFFLENBQUM7SUFDcEIsQ0FBQztJQUNELDZCQUE2QjtJQUM3QixNQUFNO1FBQ0YsSUFBSSxJQUFJLEdBQUcsT0FBTyxDQUFDLENBQUMsQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUM3QixPQUFPLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQyxhQUFhLENBQUMsS0FBSyxDQUFDLGVBQWUsQ0FBQyxDQUFDO1FBQzFELE9BQU8sQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLGFBQWEsQ0FBQyxLQUFLLENBQUMsaUJBQWlCLENBQUMsQ0FBQztRQUM1RCxPQUFPLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQyxhQUFhLENBQUMsS0FBSyxDQUFDLGFBQWEsQ0FBQyxDQUFDO1FBQ3hELEdBQUcsQ0FBQyxDQUFDLElBQUksTUFBTSxJQUFJLFVBQVUsQ0FBQyxDQUFDLENBQUM7WUFDNUIsTUFBTSxDQUFDLFVBQVUsR0FBRyxLQUFLLENBQUM7UUFDOUIsQ0FBQztRQUFBLENBQUM7UUFDRixJQUFJLENBQUMsVUFBVSxHQUFHLElBQUksQ0FBQztRQUN2QixvQkFBb0I7UUFDcEIsT0FBTyxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUM3QixRQUFRLENBQUMsbUJBQW1CLEVBQUUsRUFDOUIsS0FBSyxDQUFDLGFBQWEsQ0FDdEIsQ0FBQztRQUNGLGVBQWU7UUFDZixJQUFJLFlBQVksR0FBRyxFQUFFLENBQUM7UUFDdEIsR0FBRyxDQUFDLENBQUMsSUFBSSxJQUFJLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7WUFDMUIsSUFBSSxtQkFBbUIsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUNqRCxtQkFBbUIsQ0FBQyxJQUFJLENBQUM7Z0JBQ3JCLE9BQU8sQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLFFBQVEsSUFBSSxDQUFDLFFBQVEsWUFBWSxDQUFDLENBQUM7Z0JBQzFELElBQUksQ0FBQyxZQUFZLENBQUMsWUFBWSxFQUFFLENBQUM7WUFDckMsQ0FBQyxDQUFDLENBQUM7WUFDSCxZQUFZLENBQUMsSUFBSSxDQUFDLG1CQUFtQixDQUFDLENBQUM7UUFDM0MsQ0FBQztRQUFBLENBQUM7UUFDRixPQUFPLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxZQUFZLENBQUM7YUFDdEIsSUFBSSxDQUFDO1lBQ0YsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ25CLENBQUMsQ0FBQyxDQUFDO1FBRVAsTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUM7SUFDeEIsQ0FBQzs7QUFDTCxDQUFDO0FBNURZLG1CQUFXLGNBNER2QixDQUFBO0FBQUEsQ0FBQyJ9

View File

@@ -1,25 +0,0 @@
/// <reference types="q" />
import * as plugins from "./smartnginx.plugins";
/**
* the host config data that NginxHost needs to create a valid instance
*/
export interface IHostConfigData {
hostName: string;
type: hostTypes;
destination: string;
}
export declare enum hostTypes {
reverseProxy = 0,
static = 1,
}
/**
* manages a single nginx host
*/
export declare class NginxHost {
hostName: string;
type: hostTypes;
destination: string;
configString: string;
constructor(optionsArg: IHostConfigData);
deploy(certInstanceArg: plugins.cert.Cert): plugins.q.Promise<{}>;
}

View File

@@ -1,35 +0,0 @@
"use strict";
const plugins = require("./smartnginx.plugins");
const paths = require("./smartnginx.paths");
const snippets = require("./smartnginx.snippets");
(function (hostTypes) {
hostTypes[hostTypes["reverseProxy"] = 0] = "reverseProxy";
hostTypes[hostTypes["static"] = 1] = "static";
})(exports.hostTypes || (exports.hostTypes = {}));
var hostTypes = exports.hostTypes;
/**
* manages a single nginx host
*/
class NginxHost {
constructor(optionsArg) {
this.hostName = optionsArg.hostName;
this.type = optionsArg.type;
this.destination = optionsArg.destination;
this.configString = snippets.getHostConfigString(optionsArg.hostName, optionsArg.destination);
}
;
deploy(certInstanceArg) {
let done = plugins.q.defer();
let filePath = plugins.path.join(paths.nginxHostFileBase, this.hostName + ".conf");
// writeConfig
plugins.smartfile.memory.toFsSync(this.configString, filePath);
// get cert
certInstanceArg.getDomainCert(this.hostName)
.then(done.resolve);
return done.promise;
}
;
}
exports.NginxHost = NginxHost;
;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRuZ2lueC5jbGFzc2VzLm5naW54aG9zdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3NtYXJ0bmdpbnguY2xhc3Nlcy5uZ2lueGhvc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLE1BQVksT0FBTyxXQUFNLHNCQUFzQixDQUFDLENBQUE7QUFDaEQsTUFBWSxLQUFLLFdBQU0sb0JBQW9CLENBQUMsQ0FBQTtBQUM1QyxNQUFZLFFBQVEsV0FBTSx1QkFLMUIsQ0FBQyxDQUxnRDtBQVdqRCxXQUFZLFNBQVM7SUFDakIseURBQVksQ0FBQTtJQUNaLDZDQUFNLENBQUE7QUFDVixDQUFDLEVBSFcsaUJBQVMsS0FBVCxpQkFBUyxRQUdwQjtBQUhELElBQVksU0FBUyxHQUFULGlCQUdYLENBQUE7QUFFRDs7R0FFRztBQUNIO0lBS0ksWUFBWSxVQUEwQjtRQUNsQyxJQUFJLENBQUMsUUFBUSxHQUFHLFVBQVUsQ0FBQyxRQUFRLENBQUM7UUFDcEMsSUFBSSxDQUFDLElBQUksR0FBRyxVQUFVLENBQUMsSUFBSSxDQUFDO1FBQzVCLElBQUksQ0FBQyxXQUFXLEdBQUcsVUFBVSxDQUFDLFdBQVcsQ0FBQztRQUMxQyxJQUFJLENBQUMsWUFBWSxHQUFHLFFBQVEsQ0FBQyxtQkFBbUIsQ0FBQyxVQUFVLENBQUMsUUFBUSxFQUFFLFVBQVUsQ0FBQyxXQUFXLENBQUMsQ0FBQztJQUNsRyxDQUFDOztJQUNELE1BQU0sQ0FBQyxlQUFrQztRQUNyQyxJQUFJLElBQUksR0FBRyxPQUFPLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQzdCLElBQUksUUFBUSxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxpQkFBaUIsRUFBRSxJQUFJLENBQUMsUUFBUSxHQUFHLE9BQU8sQ0FBQyxDQUFDO1FBQ25GLGNBQWM7UUFDZCxPQUFPLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLFlBQVksRUFBRSxRQUFRLENBQUMsQ0FBQztRQUMvRCxXQUFXO1FBQ1gsZUFBZSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDO2FBQ3ZDLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDeEIsTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUM7SUFDeEIsQ0FBQzs7QUFDTCxDQUFDO0FBckJZLGlCQUFTLFlBcUJyQixDQUFBO0FBQUEsQ0FBQyJ9

View File

@@ -1,29 +0,0 @@
/// <reference types="node" />
/// <reference types="q" />
import * as plugins from "./smartnginx.plugins";
import { NginxConfig } from "./smartnginx.classes.nginxconfig";
/**
* manages a nginxprocess for an NginxConfig
*/
export declare class NginxProcess {
started: boolean;
nginxConfig: NginxConfig;
nginxChildProcess: plugins.childProcess.ChildProcess;
constructor(nginxConfigArg: any);
/**
* start nginx
*/
start(): plugins.q.Promise<{}>;
/**
* reload config
*/
reloadConfig(): plugins.q.Promise<{}>;
/**
* stop the nginx instance
*/
stop(): plugins.q.Promise<{}>;
/**
* checks if nginx is in path
*/
check(): boolean;
}

View File

@@ -1,79 +0,0 @@
"use strict";
const plugins = require("./smartnginx.plugins");
const paths = require("./smartnginx.paths");
/**
* manages a nginxprocess for an NginxConfig
*/
class NginxProcess {
constructor(nginxConfigArg) {
this.started = false;
this.nginxConfig = nginxConfigArg;
}
;
/**
* start nginx
*/
start() {
let done = plugins.q.defer();
if (typeof this.nginxChildProcess == "undefined") {
this.nginxChildProcess = plugins.childProcess.exec(`nginx -c ${paths.nginxConfFile}`, function (error, stdout, stderr) {
console.log(`stdout: ${stdout}`);
console.log(`stderr: ${stderr}`);
if (error !== null) {
console.log(`exec error: ${error}`);
}
;
});
}
;
this.started = true;
plugins.beautylog.info("started Nginx!");
done.resolve();
return done.promise;
}
;
/**
* reload config
*/
reloadConfig() {
let done = plugins.q.defer();
if (this.started == false) {
this.start();
}
else {
plugins.shelljs.exec("nginx -s reload");
}
;
plugins.beautylog.ok("NginxProcess has loaded the new config!");
done.resolve();
return done.promise;
}
;
/**
* stop the nginx instance
*/
stop() {
let done = plugins.q.defer();
if (typeof this.nginxChildProcess != "undefined") {
plugins.shelljs.exec("nginx -s quit");
this.started = false;
plugins.beautylog.info("stopped Nginx!");
}
else {
plugins.beautylog.log("nginx already stopped!");
}
;
done.resolve();
return done.promise;
}
;
/**
* checks if nginx is in path
*/
check() {
return;
}
;
}
exports.NginxProcess = NginxProcess;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRuZ2lueC5jbGFzc2VzLm5naW54cHJvY2Vzcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3NtYXJ0bmdpbnguY2xhc3Nlcy5uZ2lueHByb2Nlc3MudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLE1BQVksT0FBTyxXQUFNLHNCQUFzQixDQUFDLENBQUE7QUFDaEQsTUFBWSxLQUFLLFdBQU0sb0JBQW9CLENBQUMsQ0FBQTtBQUk1Qzs7R0FFRztBQUNIO0lBSUksWUFBWSxjQUFjO1FBSDFCLFlBQU8sR0FBWSxLQUFLLENBQUM7UUFJckIsSUFBSSxDQUFDLFdBQVcsR0FBRyxjQUFjLENBQUM7SUFDdEMsQ0FBQzs7SUFFRDs7T0FFRztJQUNILEtBQUs7UUFDRCxJQUFJLElBQUksR0FBRyxPQUFPLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQzdCLEVBQUUsQ0FBQyxDQUFDLE9BQU8sSUFBSSxDQUFDLGlCQUFpQixJQUFJLFdBQVcsQ0FBQyxDQUFBLENBQUM7WUFDOUMsSUFBSSxDQUFDLGlCQUFpQixHQUFHLE9BQU8sQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLFlBQVksS0FBSyxDQUFDLGFBQWEsRUFBRSxFQUFFLFVBQVUsS0FBSyxFQUFFLE1BQU0sRUFBRSxNQUFNO2dCQUNqSCxPQUFPLENBQUMsR0FBRyxDQUFDLFdBQVcsTUFBTSxFQUFFLENBQUMsQ0FBQztnQkFDakMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxXQUFXLE1BQU0sRUFBRSxDQUFDLENBQUM7Z0JBQ2pDLEVBQUUsQ0FBQyxDQUFDLEtBQUssS0FBSyxJQUFJLENBQUMsQ0FBQyxDQUFDO29CQUNqQixPQUFPLENBQUMsR0FBRyxDQUFDLGVBQWUsS0FBSyxFQUFFLENBQUMsQ0FBQztnQkFDeEMsQ0FBQztnQkFBQSxDQUFDO1lBQ04sQ0FBQyxDQUFDLENBQUM7UUFDUCxDQUFDO1FBQUEsQ0FBQztRQUNGLElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxDQUFDO1FBQ3BCLE9BQU8sQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLGdCQUFnQixDQUFDLENBQUM7UUFDekMsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ2YsTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUM7SUFDeEIsQ0FBQzs7SUFFRDs7T0FFRztJQUNILFlBQVk7UUFDUixJQUFJLElBQUksR0FBRyxPQUFPLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQzdCLEVBQUUsQ0FBQSxDQUFDLElBQUksQ0FBQyxPQUFPLElBQUksS0FBSyxDQUFDLENBQUEsQ0FBQztZQUN0QixJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDakIsQ0FBQztRQUFDLElBQUksQ0FBQyxDQUFDO1lBQ0osT0FBTyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsaUJBQWlCLENBQUMsQ0FBQztRQUM1QyxDQUFDO1FBQUEsQ0FBQztRQUNGLE9BQU8sQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLHlDQUF5QyxDQUFDLENBQUE7UUFDL0QsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ2YsTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUM7SUFDeEIsQ0FBQzs7SUFFRDs7T0FFRztJQUNILElBQUk7UUFDQSxJQUFJLElBQUksR0FBRyxPQUFPLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQzdCLEVBQUUsQ0FBQyxDQUFDLE9BQU8sSUFBSSxDQUFDLGlCQUFpQixJQUFJLFdBQVcsQ0FBQyxDQUFDLENBQUM7WUFDL0MsT0FBTyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLENBQUM7WUFDdEMsSUFBSSxDQUFDLE9BQU8sR0FBRyxLQUFLLENBQUM7WUFDckIsT0FBTyxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztRQUM3QyxDQUFDO1FBQUMsSUFBSSxDQUFDLENBQUM7WUFDSixPQUFPLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyx3QkFBd0IsQ0FBQyxDQUFDO1FBQ3BELENBQUM7UUFBQSxDQUFDO1FBQ0YsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ2YsTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUM7SUFDeEIsQ0FBQzs7SUFFRDs7T0FFRztJQUNILEtBQUs7UUFDRCxNQUFNLENBQUM7SUFDWCxDQUFDOztBQUNMLENBQUM7QUFqRVksb0JBQVksZUFpRXhCLENBQUEifQ==

View File

@@ -1,5 +0,0 @@
export declare let packageBase: string;
export declare let nginxConfigBase: string;
export declare let nginxHostFileBase: string;
export declare let nginxCertBase: string;
export declare let nginxConfFile: string;

View File

@@ -1,10 +0,0 @@
"use strict";
const plugins = require("./smartnginx.plugins");
// directories
exports.packageBase = plugins.path.join(__dirname, "../");
exports.nginxConfigBase = plugins.path.join(exports.packageBase, "nginxconfig");
exports.nginxHostFileBase = plugins.path.join(exports.nginxConfigBase, "hosts");
exports.nginxCertBase = plugins.path.join(exports.nginxConfigBase, "cert");
// files
exports.nginxConfFile = plugins.path.join(exports.nginxConfigBase, "nginx.conf");
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRuZ2lueC5wYXRocy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3NtYXJ0bmdpbngucGF0aHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLE1BQVksT0FBTyxXQUFNLHNCQUd6QixDQUFDLENBSDhDO0FBRS9DLGNBQWM7QUFDSCxtQkFBVyxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBQyxLQUFLLENBQUMsQ0FBQztBQUNqRCx1QkFBZSxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLG1CQUFXLEVBQUMsYUFBYSxDQUFDLENBQUM7QUFDL0QseUJBQWlCLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsdUJBQWUsRUFBQyxPQUFPLENBQUMsQ0FBQztBQUMvRCxxQkFBYSxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLHVCQUFlLEVBQUMsTUFBTSxDQUFDLENBQUM7QUFFckUsUUFBUTtBQUNHLHFCQUFhLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsdUJBQWUsRUFBQyxZQUFZLENBQUMsQ0FBQyJ9

View File

@@ -1,9 +0,0 @@
import "typings-global";
export import beautylog = require("beautylog");
export import cert = require("cert");
export import childProcess = require("child_process");
export import path = require("path");
export import q = require("q");
export import shelljs = require("shelljs");
export import smartfile = require("smartfile");
export import smartstring = require("smartstring");

View File

@@ -1,11 +0,0 @@
"use strict";
require("typings-global");
exports.beautylog = require("beautylog");
exports.cert = require("cert");
exports.childProcess = require("child_process");
exports.path = require("path");
exports.q = require("q");
exports.shelljs = require("shelljs");
exports.smartfile = require("smartfile");
exports.smartstring = require("smartstring");
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRuZ2lueC5wbHVnaW5zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvc21hcnRuZ2lueC5wbHVnaW5zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSxRQUFPLGdCQUFnQixDQUFDLENBQUE7QUFDVixpQkFBUyxXQUFXLFdBQVcsQ0FBQyxDQUFDO0FBQ2pDLFlBQUksV0FBVyxNQUFNLENBQUMsQ0FBQztBQUN2QixvQkFBWSxXQUFXLGVBQWUsQ0FBQyxDQUFDO0FBQ3hDLFlBQUksV0FBVyxNQUFNLENBQUMsQ0FBQztBQUN2QixTQUFDLFdBQVcsR0FBRyxDQUFDLENBQUM7QUFDakIsZUFBTyxXQUFXLFNBQVMsQ0FBQyxDQUFDO0FBQzdCLGlCQUFTLFdBQVcsV0FBVyxDQUFDLENBQUM7QUFDakMsbUJBQVcsV0FBVyxhQUFhLENBQUMsQ0FBQyJ9

View File

@@ -1,2 +0,0 @@
export declare let getBaseConfigString: () => string;
export declare let getHostConfigString: (hostNameArg: string, destinationIpArg: string) => string;

View File

@@ -1,103 +0,0 @@
"use strict";
const plugins = require("./smartnginx.plugins");
const paths = require("./smartnginx.paths");
exports.getBaseConfigString = () => {
let baseConfig = plugins.smartstring.indent.normalize(`
user www-data;
worker_processes auto;
pid /run/nginx.pid;
events {
worker_connections 768;
# multi_accept on;
}
http {
server_names_hash_bucket_size 128;
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# server_tokens off;
# server_names_hash_bucket_size 64;
# server_name_in_redirect off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
##
# SSL Settings
##
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;
##
# Logging Settings
##
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
##
# Gzip Settings
##
gzip on;
gzip_disable "msie6";
# gzip_vary on;
# gzip_proxied any;
# gzip_comp_level 6;
# gzip_buffers 16 8k;
# gzip_http_version 1.1;
# gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
##
# Virtual Host Configs
##
include ${paths.nginxHostFileBase}/*.conf;
include /etc/nginx/sites-enabled/*;
}
daemon off;
`);
return baseConfig;
};
exports.getHostConfigString = (hostNameArg, destinationIpArg) => {
let hostConfig = plugins.smartstring.indent.normalize(`
upstream ${hostNameArg} {
server ${destinationIpArg};
}
server {
listen *:80 ;
server_name ${hostNameArg};
rewrite ^ https://${hostNameArg}$request_uri? permanent;
}
server {
listen *:443 ssl;
server_name ${hostNameArg};
ssl_certificate ${paths.nginxCertBase}/${hostNameArg}/fullchain.pem;
ssl_certificate_key ${paths.nginxCertBase}/${hostNameArg}/privkey.pem;
location / {
proxy_pass http://${hostNameArg};
include /etc/nginx/proxy_params;
}
location ~ /\.git {
deny all;
}
}
`);
return hostConfig;
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRuZ2lueC5zbmlwcGV0cy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3NtYXJ0bmdpbnguc25pcHBldHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLE1BQVksT0FBTyxXQUFNLHNCQUFzQixDQUFDLENBQUE7QUFDaEQsTUFBWSxLQUFLLFdBQU0sb0JBQW9CLENBQUMsQ0FBQTtBQUNqQywyQkFBbUIsR0FBRztJQUNoQyxJQUFJLFVBQVUsR0FBRyxPQUFPLENBQUMsV0FBVyxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUM7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O2FBOEQxQyxLQUFLLENBQUMsaUJBQWlCOzs7O0VBSWxDLENBQUMsQ0FBQztJQUNILE1BQU0sQ0FBQyxVQUFVLENBQUM7QUFDbkIsQ0FBQyxDQUFBO0FBR1UsMkJBQW1CLEdBQUcsQ0FBQyxXQUFrQixFQUFDLGdCQUF1QjtJQUMzRSxJQUFJLFVBQVUsR0FBRyxPQUFPLENBQUMsV0FBVyxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUM7YUFDMUMsV0FBVztZQUNaLGdCQUFnQjs7Ozs7aUJBS1gsV0FBVzs4QkFDRSxXQUFXOzs7OztpQkFLeEIsV0FBVztxQkFDUCxLQUFLLENBQUMsYUFBYSxJQUFJLFdBQVc7eUJBQzlCLEtBQUssQ0FBQyxhQUFhLElBQUksV0FBVzs7O3dCQUduQyxXQUFXOzs7Ozs7O0VBT2pDLENBQUMsQ0FBQztJQUNILE1BQU0sQ0FBQyxVQUFVLENBQUM7QUFDbkIsQ0FBQyxDQUFDIn0=

View File

@@ -0,0 +1,15 @@
-----BEGIN RSA PRIVATE KEY-----
MIICWwIBAAKBgQCHoQbEbAo/0ZDFU9AkubBRi8FeKdhCFrzK+wXZD9JnEJRa3q6o
CI+6H3YLYleGGP8Vkwca8ykz5BX0MrKAlZWpoEpqgm2lVCBKh9mqCG1bN0aPdlwh
E24/HZFbeVgyJBvH/7XZJDGlm638dSMoXMmPtwLfq1uTAmHwtHBEqdiLFwIDAQAB
AoGAJWXibtD3toc7qx2kPCwzkRi/Ng7FwdtxLWswPp0dQCwTLEdQ06agswqvyw3P
4nsMA0/qWqUIDHXtE8vS6p/Uh21aKTYNgHJA4VZdJvh5Zhogq77dtGFyME7T3914
isamRo8hxemijJG9oml7y+jW/xnMFhe98dqKf9k0RNI9G1kCQQDHhInM8HEJWnRX
ckkhGoel7HlfpTaLYIO7Ls4ErsNmBQjralRZVX1+g4+h4/QLCcOYqihNDgSUZMEt
aEC82c4LAkEArgZXP/gaua0tylBwQETOyUip2apVOvArmH9xLL9qTkXueV39skZb
36cO9RK7C+HTY4hGNcXDdihxs+Fa4sD6pQJAQc6FZQMpRVyAYxde53xIoYGNxu5H
P1FmIacebIz4Bf5DIuK/T3fTHJdoGI2HQNzHluMIx+GHwSo6TS/FqoRsYQJAe/ia
aUC20TU0nJ6nCLG72hqAnUZBh0YW2IFZP3ZxJaed1ioGE90Zj/8zoZShWTqb25j1
41KqBt+S+ID+vPCa3QJABo8fEGIy/g7M5OB5euLHQLvCvYJDn9YWAryhRedR1B2e
zEZOO0qxUJSjMdnYFYG6Na/poM3atnJ4W8pJzOtA4w==
-----END RSA PRIVATE KEY-----

View File

@@ -0,0 +1,6 @@
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCHoQbEbAo/0ZDFU9AkubBRi8Fe
KdhCFrzK+wXZD9JnEJRa3q6oCI+6H3YLYleGGP8Vkwca8ykz5BX0MrKAlZWpoEpq
gm2lVCBKh9mqCG1bN0aPdlwhE24/HZFbeVgyJBvH/7XZJDGlm638dSMoXMmPtwLf
q1uTAmHwtHBEqdiLFwIDAQAB
-----END PUBLIC KEY-----

View File

@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAuO16Nu4tMkmBqsNWezt3ENqnsbWNUqC+curHyXURaoIH2wQ1
6DIZaBIbO/WndNisMy6TnxJtiMVbKGKjkRH4w3qegthIRCKLD3+Yl1ffqpHRz19h
kNxVg4HfXRQMfH0Pnvd/4wB7g2mapk8SMwsTuEZ0j/7dAwc0dqw94g+aehgZlvxU
DFQjI/4kU9EiheDZ9TPREBMfeIb82zapINekKq5TkN/euWfsfpbZZ6qWZvTX8Neg
ulKOtDCCFauXKv2LNqy4jxWQef2XfMT8Jr4Txud3F8zqfexJYq5ywjH07ecsyi7a
/ifv7VLNXUEgwI6OFJHYnFZ314S6KlurocQUWQIDAQABAoIBAAIMpnWrBrSa+d5X
whB9uX27XITnXKpoAguNfHivvONBrcXGWVl+zkKh3ip4RFIfE7IjXpyQ6vEalD5j
zDh4uiWflt3cVFldDUISdmUb1pEYM5YcMN1c/RRujikQ8qK3ExhyLtqh7Eu8GBnR
L7rQ6x9ZoBAAtJT4Wr6rIeEmfW16lunOu97mTi/RL//EHQvlBPgyr2sHLee2aPWV
jmC4607vV+xNJPC4qd+6HJDjaXi6hNooVDO8jX48RJUVozMRX7i8GIoDotvObVbA
SCqlhbWyawzbCX1p5nvtdOZ0muSIDILudifFUzRzBm0sSL0MxIT0s6OYaQuU0moH
Q1nOr+UCgYEA94R/MkApusWYjRcNEPPE2cB1QvtoEDdfhPzwzg1xympRzn8gOwin
tpJ25H+dYHeIR5TB5GiqKRY/zwqqqiplEQRkIL+aT/mYqM/vSfchm+gVbBYZL7ql
FrE9h+i+mf0/GNoRV3VirWjIjTqBW3DQ0KvxBOos9gJCJA6pMD0xQo0CgYEAv0Pf
BvZpskgmxdOGlynUbfu9hQWOqbagU6U1dUwzYbO2EYqjxZeJn5974vJ5XlHAHy3R
WuVfGjdiNIph+mDiBFK7wUih6dwVUrKf8H1fucsprfmRkaiKnofaefrlWHMnqo45
vWAXkQoJpnR7afQmk3lK8geejMIo/M5Wm+VuS/0CgYA25iRwONsImhsj8CDtyaO3
yIA5wxlpv15oWNHwYfsDMmHCs1+quFi6nfHQ7J0zcE/B0LTQvIZBZrXwbiU8aPrR
s2+h891+L5Y0myov9ah2tBtMRfqAI53KUrWbF3xvG0SLdpKyG08vtzYEXR2j8nne
TsS+mlIunoGdDcNo96mdYQKBgDz7B72xjMuBw5LpOQ0zEf6q96bUucKUbpOcpemr
DOrGoHMBT+vsv7073QTjqByRVf7a3dfsL6EtLUtxH4Hzp7wXILOkU7M7LzU5rFLB
tmaHRteoLWhSYzfeOqMPglXsCSaQyAn//COLHr6KftquNCpqzqFSGpPoR6cqpmR4
Bu2FAoGBAN+UVwhXtSYG89pYFw5u4Oa2XwaVciaqGSkXR0Oyb8pBx65AX6Byy1FD
6IooFiAkHqDDz2iIPx7mxzTrHBfKcaHsUcgT5aXr720A6/aD6W5PsVdebWoMMTyA
OqFdoeXdMWUzCOWQYp6ViD8f0MQydHppOhugEivReRP700C1WVnx
-----END RSA PRIVATE KEY-----

View File

@@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDBDCCAeygAwIBAgIJZid+XT7/NTaWMA0GCSqGSIb3DQEBBQUAMB4xHDAaBgNV
BAMTE3NlbGZzaWduZWQuZ2l0LnpvbmUwHhcNMjUxMTI3MTMxMzM0WhcNMjYxMTI3
MTMxMzM0WjAeMRwwGgYDVQQDExNzZWxmc2lnbmVkLmdpdC56b25lMIIBIjANBgkq
hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuO16Nu4tMkmBqsNWezt3ENqnsbWNUqC+
curHyXURaoIH2wQ16DIZaBIbO/WndNisMy6TnxJtiMVbKGKjkRH4w3qegthIRCKL
D3+Yl1ffqpHRz19hkNxVg4HfXRQMfH0Pnvd/4wB7g2mapk8SMwsTuEZ0j/7dAwc0
dqw94g+aehgZlvxUDFQjI/4kU9EiheDZ9TPREBMfeIb82zapINekKq5TkN/euWfs
fpbZZ6qWZvTX8NegulKOtDCCFauXKv2LNqy4jxWQef2XfMT8Jr4Txud3F8zqfexJ
Yq5ywjH07ecsyi7a/ifv7VLNXUEgwI6OFJHYnFZ314S6KlurocQUWQIDAQABo0Uw
QzAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIC9DAmBgNVHREEHzAdhhtodHRwOi8v
ZXhhbXBsZS5vcmcvd2ViaWQjbWUwDQYJKoZIhvcNAQEFBQADggEBAH3qUHaBnNn+
e1qlZ0gUooJlLXU5tLGR9cVFV1dKuE5yxZhT0qal4A6Vif1mGKYXmHC4q0/atNsQ
RBvrbpoVtJxWpb6iIh1L5WWeP5OxqeLwZ8gp2Qj67CkwmccjIS66kkpwHBkBmXU9
nRlmGOj9OBHczqE0cp4dW6pCVvRtzC+wTX9oqAdmjyD8S8oo8I2fjCL4pJTPQtbV
RlaryWxlxscXYArA7iE9A5Cl5DdJtkOKS48Rbfw3BEQpgL0J4VeF8Lbb+ryk6BbG
XXkkH570cIdTs588gdfhkS8T6NIl+1Aicqmf+v6j3MHrzyLK3SZTQ83hoCRAEMfW
SPkrHSeL6h8=
-----END CERTIFICATE-----

View File

@@ -0,0 +1,31 @@
upstream test100.bleu.de {
keepalive 100;
server 192.192.192.191:3000;
}
server {
# The keepalive parameter sets the maximum number of idle keepalive connections
# to upstream servers that are preserved in the cache of each worker process. When
# this number is exceeded, the least recently used connections are closed.
listen *:80 ;
server_name test100.bleu.de;
rewrite ^ https://test100.bleu.de$request_uri? permanent;
}
server {
listen *:443 ssl;
server_name test100.bleu.de;
ssl_certificate /mnt/data/lossless/push.rocks/smartnginx/nginxconfig/hosts/test100.bleu.de.public.pem;
ssl_certificate_key /mnt/data/lossless/push.rocks/smartnginx/nginxconfig/hosts/test100.bleu.de.private.pem;
location / {
proxy_http_version 1.1;
proxy_buffering off;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_next_upstream error timeout http_404 http_429 http_500 http_502;
proxy_next_upstream_tries 5;
proxy_pass http://test100.bleu.de;
}
}

View File

@@ -0,0 +1 @@
some private

View File

@@ -0,0 +1 @@
some public

View File

@@ -0,0 +1,31 @@
upstream test102.bleu.de {
keepalive 100;
server 192.192.192.192:3050;
}
server {
# The keepalive parameter sets the maximum number of idle keepalive connections
# to upstream servers that are preserved in the cache of each worker process. When
# this number is exceeded, the least recently used connections are closed.
listen *:80 ;
server_name test102.bleu.de;
rewrite ^ https://test102.bleu.de$request_uri? permanent;
}
server {
listen *:443 ssl;
server_name test102.bleu.de;
ssl_certificate /mnt/data/lossless/push.rocks/smartnginx/nginxconfig/hosts/test102.bleu.de.public.pem;
ssl_certificate_key /mnt/data/lossless/push.rocks/smartnginx/nginxconfig/hosts/test102.bleu.de.private.pem;
location / {
proxy_http_version 1.1;
proxy_buffering off;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_next_upstream error timeout http_404 http_429 http_500 http_502;
proxy_next_upstream_tries 5;
proxy_pass http://test102.bleu.de;
}
}

View File

@@ -0,0 +1 @@
some private

View File

@@ -0,0 +1 @@
some public

79
nginxconfig/nginx.conf Normal file
View File

@@ -0,0 +1,79 @@
user www-data;
worker_processes auto;
pid /run/nginx/nginx.pid;
events {
worker_connections 768;
# multi_accept on;
}
http {
server_names_hash_bucket_size 128;
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# server_tokens off;
# server_names_hash_bucket_size 64;
# server_name_in_redirect off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
##
# SSL Settings
##
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;
##
# Logging Settings
##
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
##
# Gzip Settings
##
gzip on;
gzip_disable "msie6";
# gzip_vary on;
# gzip_proxied any;
# gzip_comp_level 6;
# gzip_buffers 16 8k;
# gzip_http_version 1.1;
# gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
##
# Virtual Host Configs
##
server {
listen *:80 default_server;
server_name selfsigned.git.zone;
rewrite ^ https://git.zone redirect;
}
server {
listen *:443 ssl default_server;
server_name selfsigned.git.zone;
ssl_certificate /mnt/data/lossless/push.rocks/smartnginx/nginxconfig/hosts/default.public.pem;
ssl_certificate_key /mnt/data/lossless/push.rocks/smartnginx/nginxconfig/hosts/default.private.pem;
rewrite ^ https://git.zone redirect;
}
include /mnt/data/lossless/push.rocks/smartnginx/nginxconfig/hosts/*.conf;
include /etc/nginx/sites-enabled/*;
}
daemon off;

View File

@@ -2,7 +2,28 @@
"npmci": {
"npmAccessLevel": "public"
},
"npmdocker": {
"npmdocker": {},
"gitzone": {
"projectType": "npm",
"module": {
"githost": "code.foss.global",
"gitscope": "push.rocks",
"gitrepo": "smartnginx",
"description": "A TypeScript library for controlling Nginx from Node.js, with support for generating and managing Nginx configurations dynamically.",
"npmPackagename": "@push.rocks/smartnginx",
"license": "MIT",
"keywords": [
"nginx",
"node.js",
"TypeScript",
"configuration management",
"web server",
"reverse proxy",
"SSL certificates"
]
}
},
"tsdoc": {
"legal": "\n## License and Legal Information\n\nThis repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository. \n\n**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.\n\n### Trademarks\n\nThis project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.\n\n### Company Information\n\nTask Venture Capital GmbH \nRegistered at District court Bremen HRB 35230 HB, Germany\n\nFor any legal inquiries or if you require further information, please contact us via email at hello@task.vc.\n\nBy using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.\n"
}
}

1603
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,43 +1,65 @@
{
"name": "@pushrocks/smartnginx",
"version": "2.0.23",
"name": "@push.rocks/smartnginx",
"version": "2.0.53",
"private": false,
"description": "control nginx from node, TypeScript ready",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
"description": "A TypeScript library for controlling Nginx from Node.js, with support for generating and managing Nginx configurations dynamically.",
"main": "dist_ts/index.js",
"typings": "dist_ts/index.d.ts",
"scripts": {
"test": "tstest test/",
"test": "tstest test/ --verbose",
"cleanTest": "(rm -r nginxconfig) && npm run test",
"build": "(tsbuild)"
"build": "(tsbuild tsfolders --allowimplicitany)"
},
"repository": {
"type": "git",
"url": "git+ssh://git@gitlab.com/pushrocks/smartnginx.git"
"url": "https://code.foss.global/push.rocks/smartnginx.git"
},
"keywords": [
"nginx"
"nginx",
"node.js",
"TypeScript",
"configuration management",
"web server",
"reverse proxy",
"SSL certificates"
],
"author": "Lossless GmbH",
"license": "MIT",
"bugs": {
"url": "https://gitlab.com/pushrocks/smartnginx/issues"
},
"homepage": "https://gitlab.com/pushrocks/smartnginx#README",
"homepage": "https://code.foss.global/push.rocks/smartnginx",
"dependencies": {
"@pushrocks/lik": "^3.0.4",
"@pushrocks/smartfile": "^6.0.11",
"@pushrocks/smartlog": "^2.0.11",
"@pushrocks/smartpromise": "^2.0.5",
"@pushrocks/smartshell": "^2.0.13",
"@pushrocks/smartstring": "^3.0.8"
"@push.rocks/lik": "^6.2.2",
"@push.rocks/smartfs": "^1.1.0",
"@push.rocks/smartlog": "^3.1.10",
"@push.rocks/smartpath": "^6.0.0",
"@push.rocks/smartpromise": "^4.2.3",
"@push.rocks/smartshell": "^3.3.0",
"@push.rocks/smartstring": "^4.1.0",
"@push.rocks/smartunique": "^3.0.9",
"selfsigned": "^4.0.0"
},
"devDependencies": {
"@gitzone/tsbuild": "^2.1.4",
"@gitzone/tsrun": "^1.1.17",
"@gitzone/tstest": "^1.0.18",
"@pushrocks/qenv": "^4.0.0",
"@pushrocks/tapbundle": "^3.0.7",
"tslint": "^5.12.1",
"tslint-config-prettier": "^1.17.0"
}
"@git.zone/tsbuild": "^3.1.0",
"@git.zone/tsrun": "^2.0.0",
"@git.zone/tstest": "^3.1.3",
"@push.rocks/qenv": "^6.1.3"
},
"files": [
"ts/**/*",
"ts_web/**/*",
"dist/**/*",
"dist_*/**/*",
"dist_ts/**/*",
"dist_ts_web/**/*",
"assets/**/*",
"cli.js",
"npmextra.json",
"readme.md"
],
"type": "module",
"browserslist": [
"last 1 chrome versions"
]
}

8315
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1 +1 @@
vars:
required:

1
readme.hints.md Normal file
View File

@@ -0,0 +1 @@

267
readme.md Normal file
View File

@@ -0,0 +1,267 @@
# @push.rocks/smartnginx
Control Nginx programmatically from Node.js with full TypeScript support 🚀
## Issue Reporting and Security
For reporting bugs, issues, or security vulnerabilities, please visit [community.foss.global/](https://community.foss.global/). This is the central community hub for all issue reporting. Developers who sign and comply with our contribution agreement and go through identification can also get a [code.foss.global/](https://code.foss.global/) account to submit Pull Requests directly.
## Features
- 🎯 **Dynamic Configuration** - Generate and manage Nginx configs on the fly
- 🔒 **SSL/TLS Ready** - Built-in support for SSL certificates with automatic HTTP→HTTPS redirects
- 🔄 **Hot Reload** - Apply configuration changes without downtime
- 📦 **Zero-Config Defaults** - Self-signed certificates auto-generated for immediate testing
- 🎛️ **Reverse Proxy Made Easy** - Set up proxy hosts with a single method call
- 🧠 **Smart Diffing** - Only reloads Nginx when configurations actually change
- 📝 **TypeScript First** - Full type definitions included
## Install
```bash
pnpm add @push.rocks/smartnginx
# or
npm install @push.rocks/smartnginx
```
> **Prerequisites**: Nginx must be installed and available in your system PATH.
## Quick Start
```typescript
import { SmartNginx } from '@push.rocks/smartnginx';
// Create a SmartNginx instance with a default fallback URL
const nginx = new SmartNginx({
defaultProxyUrl: 'https://your-default-site.com'
});
// Add a reverse proxy host
nginx.addHostCandidate({
hostName: 'api.example.com',
destination: 'localhost',
destinationPort: 3000,
privateKey: '<your-ssl-private-key>',
publicKey: '<your-ssl-certificate>'
});
// Deploy and start Nginx
await nginx.deploy();
```
That's it! Your reverse proxy is now running 🎉
## Usage
### Creating the SmartNginx Instance
The `SmartNginx` class is your main interface for managing Nginx:
```typescript
import { SmartNginx } from '@push.rocks/smartnginx';
const nginx = new SmartNginx({
defaultProxyUrl: 'https://fallback.example.com', // Where unmatched requests go
logger: myCustomLogger // Optional: pass a @push.rocks/smartlog instance
});
```
### Adding Host Configurations
Each host represents a domain/subdomain with its proxy rules and SSL certificates:
```typescript
// Add a host using addHostCandidate()
const myHost = nginx.addHostCandidate({
hostName: 'app.example.com', // Domain name
destination: '127.0.0.1', // Backend server address
destinationPort: 8080, // Backend port
privateKey: sslPrivateKeyPem, // SSL private key (PEM format)
publicKey: sslCertificatePem // SSL certificate (PEM format)
});
```
### Multi-Host Setup
Run multiple sites through a single Nginx instance:
```typescript
// Production API
nginx.addHostCandidate({
hostName: 'api.myapp.com',
destination: 'localhost',
destinationPort: 3000,
privateKey: apiPrivateKey,
publicKey: apiCertificate
});
// Admin panel
nginx.addHostCandidate({
hostName: 'admin.myapp.com',
destination: 'localhost',
destinationPort: 4000,
privateKey: adminPrivateKey,
publicKey: adminCertificate
});
// Staging environment
nginx.addHostCandidate({
hostName: 'staging.myapp.com',
destination: '192.168.1.100',
destinationPort: 8080,
privateKey: stagingPrivateKey,
publicKey: stagingCertificate
});
// Deploy all at once
await nginx.deploy();
```
### Deploying Configurations
The `deploy()` method is smart about changes:
```typescript
// First deploy - writes configs and starts Nginx
await nginx.deploy();
// Add more hosts dynamically
nginx.addHostCandidate({
hostName: 'newsite.example.com',
destination: 'localhost',
destinationPort: 5000,
privateKey: newPrivateKey,
publicKey: newCertificate
});
// Second deploy - detects changes, updates configs, hot-reloads Nginx
await nginx.deploy();
// If you call deploy() with no changes, it skips the reload (efficient!)
await nginx.deploy(); // → "hosts have not diverged, skipping nginx reload"
```
### Querying Deployed Hosts
```typescript
// Get all deployed hosts
const hosts = await nginx.listDeployedHosts();
console.log(`Running ${hosts.length} hosts`);
// Find a specific host by domain
const apiHost = nginx.getDeployedNginxHostByHostName('api.example.com');
if (apiHost) {
console.log(`API proxying to ${apiHost.destination}:${apiHost.destinationPort}`);
}
```
### Removing Hosts
```typescript
const hostToRemove = nginx.getDeployedNginxHostByHostName('staging.myapp.com');
if (hostToRemove) {
await nginx.removeDeployedHost(hostToRemove);
// Nginx automatically reloaded with updated config
}
```
### Stopping Nginx
```typescript
// Gracefully stop the Nginx process
await nginx.stop();
```
## Generated Configuration
SmartNginx generates production-ready Nginx configurations:
**For each host, you get:**
- HTTP (port 80) → HTTPS (port 443) automatic redirect
- Upstream with keepalive connections (100 idle connections)
- WebSocket-friendly proxy settings (HTTP/1.1, no buffering)
- Proper proxy headers (`X-Real-IP`, `X-Forwarded-For`, `X-Forwarded-Proto`)
- Smart failover (`proxy_next_upstream` on errors, timeouts, 404/429/500/502)
**Default server:**
- Self-signed certificate for unmatched domains
- Redirects to your configured `defaultProxyUrl`
## Architecture
```
┌─────────────────────────────────────────────────────────────┐
│ SmartNginx │
├─────────────────────────────────────────────────────────────┤
│ hostCandidates[] → deploy() → deployedHosts[] │
│ ↓ │
│ NginxProcess │
│ (start/reload/stop) │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ Generated Files │
├─────────────────────────────────────────────────────────────┤
│ nginxconfig/ │
│ ├── nginx.conf (main config) │
│ └── hosts/ │
│ ├── default.private.pem (self-signed key) │
│ ├── default.public.pem (self-signed cert) │
│ ├── api.example.com.conf │
│ ├── api.example.com.private.pem │
│ └── api.example.com.public.pem │
└─────────────────────────────────────────────────────────────┘
```
## API Reference
### SmartNginx
| Method | Description |
|--------|-------------|
| `addHostCandidate(config)` | Add a new host configuration |
| `deploy()` | Write configs and start/reload Nginx |
| `listDeployedHosts()` | Get all currently deployed hosts |
| `getDeployedNginxHostByHostName(hostname)` | Find a host by domain name |
| `removeDeployedHost(host)` | Remove a host and reload Nginx |
| `stop()` | Gracefully stop Nginx |
### IHostConfig
```typescript
interface IHostConfig {
hostName: string; // Domain name (e.g., 'api.example.com')
destination: string; // Backend server IP/hostname
destinationPort: number; // Backend port
privateKey: string; // SSL private key (PEM)
publicKey: string; // SSL certificate (PEM)
}
```
### NginxHost
Each host instance exposes:
- `hostName` - The configured domain
- `destination` - Backend address
- `destinationPort` - Backend port
- `configString` - The generated Nginx config (after deploy)
- `deploy()` - Write this host's config files
## License and Legal Information
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
### Trademarks
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.
### Company Information
Task Venture Capital GmbH
Registered at District court Bremen HRB 35230 HB, Germany
For any legal inquiries or if you require further information, please contact us via email at hello@task.vc.
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.

View File

@@ -1,34 +1,35 @@
import { tap, expect } from '@pushrocks/tapbundle';
import path = require('path');
import { tap, expect } from '@git.zone/tstest/tapbundle';
import * as path from 'node:path';
import { Qenv } from '@pushrocks/qenv';
const testQenv = new Qenv('./', './.nogit/');
import { Qenv } from '@push.rocks/qenv';
import * as smartnginx from '../ts/index';
import * as smartnginx from '../ts/index.js';
let testSmartNginx: smartnginx.SmartNginx;
let testNginxZone01: smartnginx.NginxHost;
let testNginxZone02: smartnginx.NginxHost;
tap.test('should create a valid instance of SmartNginx', async () => {
testSmartNginx = new smartnginx.SmartNginx({});
expect(testSmartNginx).to.be.instanceof(smartnginx.SmartNginx);
testSmartNginx = new smartnginx.SmartNginx({ defaultProxyUrl: 'https://git.zone' });
expect(testSmartNginx).toBeInstanceOf(smartnginx.SmartNginx);
});
tap.test(`should produce an instance of NginxConfig`, async () => {
testNginxZone01 = new smartnginx.NginxHost(testSmartNginx, {
hostName: 'test100.bleu.de',
destination: '192.192.192.191',
destinationPort: 3000,
privateKey: 'some private',
publicKey: 'some public'
publicKey: 'some public',
});
testNginxZone02 = new smartnginx.NginxHost(testSmartNginx, {
hostName: 'test102.bleu.de',
destination: '192.192.192.192',
destinationPort: 3050,
privateKey: 'some private',
publicKey: 'some public'
publicKey: 'some public',
});
expect(testNginxZone01).to.be.instanceof(smartnginx.NginxHost);
expect(testNginxZone01).toBeInstanceOf(smartnginx.NginxHost);
});
tap.test('.addHostCandidate() should add a zone to NginxConfig Object', async () => {
@@ -50,4 +51,4 @@ tap.test('.stop() should end the process', async () => {
testSmartNginx.nginxProcess.stop();
});
tap.start();
export default tap.start();

8
ts/00_commitinfo_data.ts Normal file
View File

@@ -0,0 +1,8 @@
/**
* autocreated commitinfo by @push.rocks/commitinfo
*/
export const commitinfo = {
name: '@push.rocks/smartnginx',
version: '2.0.53',
description: 'A TypeScript library for controlling Nginx from Node.js, with support for generating and managing Nginx configurations dynamically.'
}

View File

@@ -1,6 +1,4 @@
import * as plugins from './smartnginx.plugins';
// classes
export * from './smartnginx.classes.smartnginx';
export * from './smartnginx.classes.nginxprocess';
export * from './smartnginx.classes.nginxhost';
export * from './smartnginx.classes.smartnginx.js';
export * from './smartnginx.classes.nginxprocess.js';
export * from './smartnginx.classes.nginxhost.js';

View File

@@ -1,6 +1,7 @@
export interface IHostConfig {
hostName: string;
destination: string;
destinationPort: number;
privateKey: string;
publicKey: string;
}

View File

@@ -1,13 +1,13 @@
import * as plugins from './smartnginx.plugins';
import * as paths from './smartnginx.paths';
import * as snippets from './smartnginx.snippets';
import * as plugins from './smartnginx.plugins.js';
import * as paths from './smartnginx.paths.js';
import * as snippets from './smartnginx.snippets.js';
import { SmartNginx } from './smartnginx.classes.smartnginx';
import { SmartNginx } from './smartnginx.classes.smartnginx.js';
import { IHostConfig } from './interfaces/hostconfig';
import { type IHostConfig } from './interfaces/hostconfig.js';
export enum hostTypes {
reverseProxy
reverseProxy,
}
/**
@@ -21,6 +21,7 @@ export class NginxHost implements IHostConfig {
public hostName: string; // the host name e.g. domain name
public destination: string;
public destinationPort: number;
public configString: string; // the actual host config file as string
public privateKey: string;
public publicKey: string;
@@ -29,7 +30,7 @@ export class NginxHost implements IHostConfig {
this.smartnginxInstance = smartnginxInstanceArg;
this.hostName = optionsArg.hostName;
this.destination = optionsArg.destination;
this.configString = snippets.getHostConfigString(optionsArg.hostName, optionsArg.destination);
this.destinationPort = optionsArg.destinationPort;
this.privateKey = optionsArg.privateKey;
this.publicKey = optionsArg.publicKey;
}
@@ -40,14 +41,22 @@ export class NginxHost implements IHostConfig {
*/
public async deploy() {
const filePathConfig = plugins.path.join(paths.nginxHostDirPath, `${this.hostName}.conf`);
const filePathPrivate = plugins.path.join(paths.nginxHostDirPath, `${this.hostName}.private.pem`);
const filePathPrivate = plugins.path.join(
paths.nginxHostDirPath,
`${this.hostName}.private.pem`
);
const filePathPublic = plugins.path.join(paths.nginxHostDirPath, `${this.hostName}.public.pem`);
// writeConfig
plugins.smartfile.memory.toFsSync(this.configString, filePathConfig);
this.configString = snippets.getHostConfigString(
this.hostName,
this.destination,
this.destinationPort
);
await plugins.fs.file(filePathConfig).write(this.configString);
// write ssl
plugins.smartfile.memory.toFsSync(this.privateKey, filePathPrivate);
plugins.smartfile.memory.toFsSync(this.publicKey, filePathPublic);
await plugins.fs.file(filePathPrivate).write(this.privateKey);
await plugins.fs.file(filePathPublic).write(this.publicKey);
}
}

View File

@@ -1,9 +1,7 @@
import * as plugins from './smartnginx.plugins';
import * as paths from './smartnginx.paths';
import { SmartNginx } from './smartnginx.classes.smartnginx';
import { NginxHost } from './smartnginx.classes.nginxhost';
import { Smartshell } from '@pushrocks/smartshell';
import * as plugins from './smartnginx.plugins.js';
import * as paths from './smartnginx.paths.js';
import { SmartNginx } from './smartnginx.classes.smartnginx.js';
import { NginxHost } from './smartnginx.classes.nginxhost.js';
import { ChildProcess } from 'child_process';
@@ -14,8 +12,8 @@ export class NginxProcess {
public started: boolean = false;
public smartNginxRef: SmartNginx;
private nginxChildProcess: ChildProcess;
private smartshellInstance = new Smartshell({
executor: 'bash'
private smartshellInstance = new plugins.smartshell.Smartshell({
executor: 'bash',
});
constructor(nginxRefArg: SmartNginx) {
@@ -27,12 +25,12 @@ export class NginxProcess {
*/
public async start() {
if (!this.nginxChildProcess) {
this.nginxChildProcess = (await this.smartshellInstance.execStreaming(
`nginx -c ${paths.nginxConfFile}`
)).childProcess;
this.nginxChildProcess = (
await this.smartshellInstance.execStreaming(`nginx -c ${paths.nginxConfFile}`)
).childProcess;
}
this.started = true;
plugins.smartlog.defaultLogger.log('info', 'started Nginx!');
console.log('info', 'started Nginx!');
}
/**

View File

@@ -1,25 +1,34 @@
import * as plugins from './smartnginx.plugins';
import * as paths from './smartnginx.paths';
import * as snippets from './smartnginx.snippets';
import { NginxHost } from './smartnginx.classes.nginxhost';
import { NginxProcess } from './smartnginx.classes.nginxprocess';
import { IHostConfig } from './interfaces/hostconfig';
import * as plugins from './smartnginx.plugins.js';
import * as paths from './smartnginx.paths.js';
import * as snippets from './smartnginx.snippets.js';
import { NginxHost } from './smartnginx.classes.nginxhost.js';
import { NginxProcess } from './smartnginx.classes.nginxprocess.js';
import { type IHostConfig } from './interfaces/hostconfig.js';
export interface ISmartNginxContructorOptions {
logger?: plugins.smartlog.Smartlog;
defaultProxyUrl: string;
}
/**
* main class that manages a NginxInstance
*/
export class SmartNginx {
public options: ISmartNginxContructorOptions;
public logger: plugins.smartlog.Smartlog;
// the objectmaps
private deployedHosts = new plugins.lik.Objectmap<NginxHost>();
private hostCandidates = new plugins.lik.Objectmap<NginxHost>();
private deployedHosts = new plugins.lik.ObjectMap<NginxHost>();
private hostCandidates = new plugins.lik.ObjectMap<NginxHost>();
public nginxProcess: NginxProcess = new NginxProcess(this);
constructor(optionsArg: { logger?: plugins.smartlog.Smartlog }) {
optionsArg.logger
? (this.logger = optionsArg.logger)
: (this.logger = plugins.smartlog.defaultLogger);
constructor(optionsArg: ISmartNginxContructorOptions) {
this.options = optionsArg;
this.options.logger
? (this.logger = this.options.logger)
: (this.logger = new plugins.smartlog.Smartlog({
logContext: null
}));
}
// ===================
@@ -41,7 +50,7 @@ export class SmartNginx {
* @param hostNameArg
*/
public getDeployedNginxHostByHostName(hostNameArg: string): NginxHost {
return this.deployedHosts.find(nginxHost => {
return this.deployedHosts.findSync((nginxHost) => {
return nginxHost.hostName === hostNameArg;
});
}
@@ -58,7 +67,7 @@ export class SmartNginx {
*/
public async removeDeployedHost(nginxHostArg: NginxHost) {
if (this.hostCandidates.isEmpty()) {
this.deployedHosts.forEach(hostArg => {
this.deployedHosts.forEach((hostArg) => {
this.hostCandidates.add(hostArg);
});
}
@@ -73,12 +82,13 @@ export class SmartNginx {
private async areHostsDiverged(): Promise<boolean> {
let hostCounter = 0;
let unfoundHosts = 0;
await this.hostCandidates.forEach(async hostCandidateArg => {
await this.hostCandidates.forEach(async (hostCandidateArg) => {
let foundHost = false;
await this.deployedHosts.forEach(async deployedHostArg => {
await this.deployedHosts.forEach(async (deployedHostArg) => {
if (
hostCandidateArg.hostName === deployedHostArg.hostName &&
hostCandidateArg.destination === deployedHostArg.destination
hostCandidateArg.destination === deployedHostArg.destination &&
hostCandidateArg.destinationPort === deployedHostArg.destinationPort
) {
hostCounter++;
foundHost = true;
@@ -106,11 +116,25 @@ export class SmartNginx {
this.hostCandidates.wipe();
// write base config
plugins.smartfile.fs.ensureDirSync(paths.nginxConfigDirPath);
plugins.smartfile.memory.toFsSync(snippets.getBaseConfigString(), paths.nginxConfFile);
await plugins.fs.directory(paths.nginxConfigDirPath).recursive().create();
await plugins.fs.file(paths.nginxConfFile).write(
snippets.getBaseConfigString(this.options.defaultProxyUrl)
);
// write standard self signed certificate
const selfsignedCert = plugins.selfsigned.generate(
[{ name: 'commonName', value: 'selfsigned.git.zone' }],
{ days: 365 }
);
// deploy hosts
plugins.smartfile.fs.ensureEmptyDirSync(paths.nginxHostDirPath);
await plugins.fs.directory(paths.nginxHostDirPath).recursive().create();
await plugins.fs.file(
plugins.path.join(paths.nginxHostDirPath, './default.private.pem')
).write(selfsignedCert.private);
await plugins.fs.file(
plugins.path.join(paths.nginxHostDirPath, './default.public.pem')
).write(selfsignedCert.cert);
for (const host of this.deployedHosts.getArray()) {
await host.deploy();
this.logger.log('info', `Host ${host.hostName} deployed!`);
@@ -121,4 +145,13 @@ export class SmartNginx {
this.hostCandidates.wipe();
}
}
/**
* stops the smartnginx instance
*/
public async stop() {
if (this.nginxProcess) {
await this.nginxProcess.stop();
}
}
}

View File

@@ -1,7 +1,7 @@
import * as plugins from './smartnginx.plugins';
import * as plugins from './smartnginx.plugins.js';
// directories
export const packageBase = plugins.path.join(__dirname, '../');
export const packageBase = plugins.path.join(plugins.smartpath.get.dirnameFromImportMetaUrl(import.meta.url), '../');
export const nginxConfigDirPath = plugins.path.join(packageBase, 'nginxconfig');
export const nginxHostDirPath = plugins.path.join(nginxConfigDirPath, 'hosts');

View File

@@ -1,14 +1,25 @@
// native
import * as path from 'path';
import * as path from 'node:path';
export { path };
// @pushrocks scope
import * as lik from '@pushrocks/lik';
import * as smartlog from '@pushrocks/smartlog';
import * as smartpromise from '@pushrocks/smartpromise';
import * as smartshell from '@pushrocks/smartshell';
import * as smartfile from '@pushrocks/smartfile';
import * as smartstring from '@pushrocks/smartstring';
// @push.rocks scope
import * as lik from '@push.rocks/lik';
import * as smartfs from '@push.rocks/smartfs';
import * as smartlog from '@push.rocks/smartlog';
import * as smartpath from '@push.rocks/smartpath';
import * as smartpromise from '@push.rocks/smartpromise';
import * as smartshell from '@push.rocks/smartshell';
import * as smartstring from '@push.rocks/smartstring';
import * as smartunique from '@push.rocks/smartunique';
export { lik, smartlog, smartpromise, smartshell, smartfile, smartstring };
export { lik, smartfs, smartlog, smartpath, smartpromise, smartshell, smartstring, smartunique };
// Shared filesystem instance
const fsProvider = new smartfs.SmartFsProviderNode();
export const fs = new smartfs.SmartFs(fsProvider);
// thirdparty scope
import * as selfsigned from 'selfsigned';
export { selfsigned };

View File

@@ -1,7 +1,7 @@
import * as plugins from './smartnginx.plugins';
import * as paths from './smartnginx.paths';
export let getBaseConfigString = () => {
let baseConfig = plugins.smartstring.indent.normalize(`
import * as plugins from './smartnginx.plugins.js';
import * as paths from './smartnginx.paths.js';
export let getBaseConfigString = (defaultProxy: string) => {
const baseConfig = plugins.smartstring.indent.normalize(`
user www-data;
worker_processes auto;
pid /run/nginx/nginx.pid;
@@ -63,6 +63,20 @@ export let getBaseConfigString = () => {
# Virtual Host Configs
##
server {
listen *:80 default_server;
server_name selfsigned.git.zone;
rewrite ^ ${defaultProxy} redirect;
}
server {
listen *:443 ssl default_server;
server_name selfsigned.git.zone;
ssl_certificate ${paths.nginxHostDirPath}/default.public.pem;
ssl_certificate_key ${paths.nginxHostDirPath}/default.private.pem;
rewrite ^ ${defaultProxy} redirect;
}
include ${paths.nginxHostDirPath}/*.conf;
include /etc/nginx/sites-enabled/*;
}
@@ -71,11 +85,15 @@ export let getBaseConfigString = () => {
return baseConfig;
};
export let getHostConfigString = (hostNameArg: string, destinationIpArg: string) => {
let hostConfig = plugins.smartstring.indent.normalize(`
export let getHostConfigString = (
hostNameArg: string,
destinationIpArg: string,
destinationPortArg = 80
) => {
const hostConfig = plugins.smartstring.indent.normalize(`
upstream ${hostNameArg} {
keepalive 100;
server ${destinationIpArg};
server ${destinationIpArg}:${destinationPortArg};
}
server {
@@ -94,10 +112,13 @@ export let getHostConfigString = (hostNameArg: string, destinationIpArg: string)
ssl_certificate_key ${paths.nginxHostDirPath}/${hostNameArg}.private.pem;
location / {
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_buffering off;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_next_upstream error timeout http_404 http_429 http_500 http_502;
proxy_next_upstream_tries 5;
proxy_pass http://${hostNameArg};
}
}

14
tsconfig.json Normal file
View File

@@ -0,0 +1,14 @@
{
"compilerOptions": {
"experimentalDecorators": true,
"useDefineForClassFields": false,
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"esModuleInterop": true,
"verbatimModuleSyntax": true
},
"exclude": [
"dist_*/**/*.d.ts"
]
}

View File

@@ -1,17 +0,0 @@
{
"extends": ["tslint:latest", "tslint-config-prettier"],
"rules": {
"semicolon": [true, "always"],
"no-console": false,
"ordered-imports": false,
"object-literal-sort-keys": false,
"member-ordering": {
"options":{
"order": [
"static-method"
]
}
}
},
"defaultSeverity": "warning"
}