Skip to content

Commit e91213b

Browse files
Release new version (#24)
* Feat: Update Features Backup & Restore (#12) * feat: Update Features Backup & Restore * Feat: Slave Mode (#13) * feat: Update Features Backup & Restore * Feat: Features update (#14) * feat: Update software * Features update version and update noti Change Password (#15) * feat: Update Features Backup & Restore * Fix frontend error (#16) * Refactor services to use centralized API module and token storage * Feat: Enhance Slave Mode UI with mode switch button and update node mode mutation * feat: Improve SSLDialog layout with enhanced text wrapping for certificate fields * refactor: replace js-cookie with localStorage for token management (#17) * feat: add syncInterval and lastSyncHash columns to system_configs table (#18) * feat: Update project goal description and remove security recommendation * feat: Update project goal description and remove security recommendation * About readme (#21) * feat: Update project goal description and remove security recommendation * Refactor be (#22) * Refactor code structure for improved readability and maintainability * style: limit max height of certificate, private key, and chain input fields (#23) --------- Co-authored-by: SangND <dacsang97@gmail.com>
1 parent d135a56 commit e91213b

File tree

250 files changed

+22527
-8851
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

250 files changed

+22527
-8851
lines changed

.github/workflows/api-test.yml

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
name: API Tests
2+
3+
on:
4+
push:
5+
branches: [main, develop, beta_developer]
6+
paths:
7+
- 'apps/api/**'
8+
- '.github/workflows/api-test.yml'
9+
- 'pnpm-lock.yaml'
10+
pull_request:
11+
branches: [main, develop, beta_developer]
12+
paths:
13+
- 'apps/api/**'
14+
- '.github/workflows/api-test.yml'
15+
- 'pnpm-lock.yaml'
16+
17+
jobs:
18+
test:
19+
name: Run API Tests
20+
runs-on: ubuntu-latest
21+
22+
permissions:
23+
contents: read
24+
pull-requests: write
25+
26+
services:
27+
postgres:
28+
image: postgres:16-alpine
29+
env:
30+
POSTGRES_USER: postgres
31+
POSTGRES_PASSWORD: postgres
32+
POSTGRES_DB: nginx_waf_test
33+
ports:
34+
- 5432:5432
35+
options: >-
36+
--health-cmd pg_isready
37+
--health-interval 10s
38+
--health-timeout 5s
39+
--health-retries 5
40+
41+
steps:
42+
- name: Checkout code
43+
uses: actions/checkout@v4
44+
45+
- name: Setup pnpm
46+
uses: pnpm/action-setup@v4
47+
with:
48+
version: 8.15.0
49+
50+
- name: Setup Node.js
51+
uses: actions/setup-node@v4
52+
with:
53+
node-version: '20'
54+
cache: 'pnpm'
55+
56+
- name: Install dependencies
57+
run: pnpm install --frozen-lockfile
58+
59+
- name: Setup test environment
60+
working-directory: apps/api
61+
run: |
62+
cp .env.test .env
63+
echo "DATABASE_URL=postgresql://postgres:postgres@localhost:5432/nginx_waf_test?schema=public" >> .env
64+
65+
- name: Generate Prisma Client
66+
working-directory: apps/api
67+
run: pnpm prisma generate
68+
69+
- name: Run database migrations
70+
working-directory: apps/api
71+
run: pnpm prisma migrate deploy
72+
env:
73+
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/nginx_waf_test?schema=public
74+
75+
- name: Run tests
76+
working-directory: apps/api
77+
run: pnpm test:coverage
78+
env:
79+
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/nginx_waf_test?schema=public
80+
NODE_ENV: test
81+
JWT_ACCESS_SECRET: test-access-secret-key-12345
82+
JWT_REFRESH_SECRET: test-refresh-secret-key-12345
83+
JWT_ACCESS_EXPIRES_IN: 15m
84+
JWT_REFRESH_EXPIRES_IN: 7d
85+
SESSION_SECRET: test-session-secret-12345
86+
CORS_ORIGIN: http://localhost:5173,http://localhost:3000
87+
BCRYPT_ROUNDS: 4
88+
TWO_FACTOR_APP_NAME: Nginx WAF Admin Test
89+
BACKUP_DIR: ./test-backups
90+
SSL_DIR: ./test-ssl
91+
PORT: 3001
92+
93+
- name: 'Report Coverage'
94+
# Set if: always() to also generate the report if tests are failing
95+
# Only works if you set `reportOnFailure: true` in your vite config as specified above
96+
if: always()
97+
uses: davelosert/vitest-coverage-report-action@v2
98+
with:
99+
working-directory: apps/api

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,7 @@ yarn.lock
4343
*.sw?
4444
landing/*
4545
.env
46-
.pnpm-store/
46+
.pnpm-store/
47+
.seeded
48+
*.md
49+
/docs/*

README.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ Comprehensive Nginx management system with ModSecurity WAF, Domain Management, S
66

77

88

9+
# Project Goal
10+
This project began as a private service built for a company. Later, my client and I decided to make it open source and free for the community to meet the personal or organizational needs of providing users with an easy way to configure Loadbalancer for server systems with SSL termination, Web Application Firewall, and it should be so easy that even a monkey could do it. This goal remains the same Although there may be advanced options, they are optional and the project should be as simple as possible to minimize the barrier to entry. The software will have all the features of an application for a digital business that is needed in the context of technological development to rapidly develop the system along with ensuring system security.
911

10-
Recommendations: The software is developed with the support of AI so it cannot be absolutely secure, so please protect the Portal and API with a firewall to ensure safety. If you find any problems, please notify us and we will handle it..
1112

1213
## ✨ Key Features
1314

@@ -30,6 +31,7 @@ Recommendations: The software is developed with the support of AI so it cannot b
3031
|----------|--------|-------------|
3132
| **New Server (Production)** | `./scripts/deploy.sh` | Full installation of Nginx + ModSecurity + Backend + Frontend with systemd services |
3233
| **Development/Testing** | `./scripts/quickstart.sh` | Quick run in dev mode (no Nginx installation, no root required) |
34+
| **Upgrade New Version** | `./scripts/update.sh` | Full update to new version |
3335

3436
### 🖥️ Production Deployment (New Server)
3537

@@ -42,6 +44,17 @@ cd nginx-love
4244
bash scripts/deploy.sh
4345
```
4446

47+
### 🖥️ Production Upgrade Deployment (Upgrade New Version)
48+
49+
```bash
50+
# Run Upgrade script (requires root)
51+
cd nginx-love
52+
git pull
53+
bash scripts/update.sh
54+
```
55+
56+
57+
4558
**Minimum Requirements:**
4659
- Ubuntu/Debian server (22.04+ recommended)
4760
- Root access

apps/api/.env.test

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Test Environment Configuration
2+
NODE_ENV=test
3+
4+
# Test Database (PostgreSQL in Docker)
5+
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/nginx_waf_test?schema=public"
6+
7+
# JWT Secrets (test values)
8+
JWT_ACCESS_SECRET="test-access-secret-key-12345"
9+
JWT_REFRESH_SECRET="test-refresh-secret-key-12345"
10+
JWT_ACCESS_EXPIRES_IN="15m"
11+
JWT_REFRESH_EXPIRES_IN="7d"
12+
13+
# Session
14+
SESSION_SECRET="test-session-secret-12345"
15+
16+
# CORS
17+
CORS_ORIGIN="http://localhost:5173,http://localhost:3000"
18+
19+
# BCrypt (lower rounds for faster tests)
20+
BCRYPT_ROUNDS="4"
21+
22+
# 2FA
23+
TWO_FACTOR_APP_NAME="Nginx WAF Admin Test"
24+
25+
# Paths (test paths)
26+
BACKUP_DIR="./test-backups"
27+
SSL_DIR="./test-ssl"
28+
29+
# Server
30+
PORT=3001

apps/api/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ dist/
88
coverage/
99
.vscode/
1010
.idea/
11+
!src/domains/logs/

apps/api/package.json

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
"dev": "ts-node-dev --respawn --transpile-only src/index.ts",
88
"build": "tsc",
99
"start": "node dist/index.js",
10+
"test": "vitest run",
11+
"test:watch": "vitest",
12+
"test:ui": "vitest --ui",
13+
"test:coverage": "vitest run --coverage",
1014
"clean": "rm -rf dist node_modules",
1115
"prisma:generate": "prisma generate",
1216
"prisma:migrate": "prisma migrate dev",
@@ -16,7 +20,12 @@
1620
"prisma": {
1721
"seed": "ts-node prisma/seed.ts"
1822
},
19-
"keywords": ["nginx", "waf", "modsecurity", "admin"],
23+
"keywords": [
24+
"nginx",
25+
"waf",
26+
"modsecurity",
27+
"admin"
28+
],
2029
"author": "",
2130
"license": "MIT",
2231
"dependencies": {
@@ -32,8 +41,8 @@
3241
"jsonwebtoken": "^9.0.2",
3342
"morgan": "^1.10.0",
3443
"nodemailer": "^6.9.14",
35-
"speakeasy": "^2.0.0",
3644
"qrcode": "^1.5.4",
45+
"speakeasy": "^2.0.0",
3746
"winston": "^3.13.1"
3847
},
3948
"devDependencies": {
@@ -47,9 +56,15 @@
4756
"@types/nodemailer": "^6.4.15",
4857
"@types/qrcode": "^1.5.5",
4958
"@types/speakeasy": "^2.0.10",
59+
"@types/supertest": "^6.0.3",
60+
"@vitest/coverage-v8": "3.2.4",
61+
"@vitest/ui": "^3.2.4",
5062
"prisma": "^5.18.0",
63+
"supertest": "^7.1.4",
5164
"ts-node": "^10.9.2",
5265
"ts-node-dev": "^2.0.0",
53-
"typescript": "^5.5.4"
66+
"typescript": "^5.5.4",
67+
"vitest": "^3.2.4",
68+
"zod": "^4.1.11"
5469
}
5570
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
-- CreateEnum
2+
CREATE TYPE "BackupStatus" AS ENUM ('success', 'failed', 'running', 'pending');
3+
4+
-- CreateTable
5+
CREATE TABLE "backup_schedules" (
6+
"id" TEXT NOT NULL,
7+
"name" TEXT NOT NULL,
8+
"schedule" TEXT NOT NULL,
9+
"enabled" BOOLEAN NOT NULL DEFAULT true,
10+
"lastRun" TIMESTAMP(3),
11+
"nextRun" TIMESTAMP(3),
12+
"status" "BackupStatus" NOT NULL DEFAULT 'pending',
13+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
14+
"updatedAt" TIMESTAMP(3) NOT NULL,
15+
16+
CONSTRAINT "backup_schedules_pkey" PRIMARY KEY ("id")
17+
);
18+
19+
-- CreateTable
20+
CREATE TABLE "backup_files" (
21+
"id" TEXT NOT NULL,
22+
"scheduleId" TEXT,
23+
"filename" TEXT NOT NULL,
24+
"filepath" TEXT NOT NULL,
25+
"size" BIGINT NOT NULL,
26+
"status" "BackupStatus" NOT NULL DEFAULT 'success',
27+
"type" TEXT NOT NULL DEFAULT 'full',
28+
"metadata" JSONB,
29+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
30+
31+
CONSTRAINT "backup_files_pkey" PRIMARY KEY ("id")
32+
);
33+
34+
-- CreateIndex
35+
CREATE INDEX "backup_files_scheduleId_idx" ON "backup_files"("scheduleId");
36+
37+
-- CreateIndex
38+
CREATE INDEX "backup_files_createdAt_idx" ON "backup_files"("createdAt");
39+
40+
-- AddForeignKey
41+
ALTER TABLE "backup_files" ADD CONSTRAINT "backup_files_scheduleId_fkey" FOREIGN KEY ("scheduleId") REFERENCES "backup_schedules"("id") ON DELETE SET NULL ON UPDATE CASCADE;
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
-- CreateEnum
2+
CREATE TYPE "SlaveNodeStatus" AS ENUM ('online', 'offline', 'syncing', 'error');
3+
4+
-- CreateEnum
5+
CREATE TYPE "SyncLogStatus" AS ENUM ('success', 'failed', 'partial', 'running');
6+
7+
-- CreateEnum
8+
CREATE TYPE "SyncLogType" AS ENUM ('full_sync', 'incremental_sync', 'health_check');
9+
10+
-- CreateTable
11+
CREATE TABLE "slave_nodes" (
12+
"id" TEXT NOT NULL,
13+
"name" TEXT NOT NULL,
14+
"host" TEXT NOT NULL,
15+
"port" INTEGER NOT NULL DEFAULT 3001,
16+
"apiKey" TEXT NOT NULL,
17+
"status" "SlaveNodeStatus" NOT NULL DEFAULT 'offline',
18+
"lastSeen" TIMESTAMP(3),
19+
"version" TEXT,
20+
"syncEnabled" BOOLEAN NOT NULL DEFAULT true,
21+
"syncInterval" INTEGER NOT NULL DEFAULT 60,
22+
"configHash" TEXT,
23+
"lastSyncAt" TIMESTAMP(3),
24+
"latency" INTEGER,
25+
"cpuUsage" DOUBLE PRECISION,
26+
"memoryUsage" DOUBLE PRECISION,
27+
"diskUsage" DOUBLE PRECISION,
28+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
29+
"updatedAt" TIMESTAMP(3) NOT NULL,
30+
31+
CONSTRAINT "slave_nodes_pkey" PRIMARY KEY ("id")
32+
);
33+
34+
-- CreateTable
35+
CREATE TABLE "sync_logs" (
36+
"id" TEXT NOT NULL,
37+
"nodeId" TEXT NOT NULL,
38+
"type" "SyncLogType" NOT NULL,
39+
"status" "SyncLogStatus" NOT NULL DEFAULT 'running',
40+
"configHash" TEXT,
41+
"changesCount" INTEGER,
42+
"errorMessage" TEXT,
43+
"startedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
44+
"completedAt" TIMESTAMP(3),
45+
"duration" INTEGER,
46+
47+
CONSTRAINT "sync_logs_pkey" PRIMARY KEY ("id")
48+
);
49+
50+
-- CreateTable
51+
CREATE TABLE "config_versions" (
52+
"id" TEXT NOT NULL,
53+
"version" SERIAL NOT NULL,
54+
"configHash" TEXT NOT NULL,
55+
"configData" JSONB NOT NULL,
56+
"createdBy" TEXT,
57+
"description" TEXT,
58+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
59+
60+
CONSTRAINT "config_versions_pkey" PRIMARY KEY ("id")
61+
);
62+
63+
-- CreateIndex
64+
CREATE UNIQUE INDEX "slave_nodes_name_key" ON "slave_nodes"("name");
65+
66+
-- CreateIndex
67+
CREATE UNIQUE INDEX "slave_nodes_apiKey_key" ON "slave_nodes"("apiKey");
68+
69+
-- CreateIndex
70+
CREATE INDEX "slave_nodes_status_idx" ON "slave_nodes"("status");
71+
72+
-- CreateIndex
73+
CREATE INDEX "slave_nodes_lastSeen_idx" ON "slave_nodes"("lastSeen");
74+
75+
-- CreateIndex
76+
CREATE INDEX "sync_logs_nodeId_startedAt_idx" ON "sync_logs"("nodeId", "startedAt");
77+
78+
-- CreateIndex
79+
CREATE UNIQUE INDEX "config_versions_configHash_key" ON "config_versions"("configHash");
80+
81+
-- CreateIndex
82+
CREATE INDEX "config_versions_createdAt_idx" ON "config_versions"("createdAt");
83+
84+
-- AddForeignKey
85+
ALTER TABLE "sync_logs" ADD CONSTRAINT "sync_logs_nodeId_fkey" FOREIGN KEY ("nodeId") REFERENCES "slave_nodes"("id") ON DELETE CASCADE ON UPDATE CASCADE;
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
-- CreateEnum
2+
CREATE TYPE "NodeMode" AS ENUM ('master', 'slave');
3+
4+
-- CreateTable
5+
CREATE TABLE "system_configs" (
6+
"id" TEXT NOT NULL,
7+
"nodeMode" "NodeMode" NOT NULL DEFAULT 'master',
8+
"masterApiEnabled" BOOLEAN NOT NULL DEFAULT true,
9+
"slaveApiEnabled" BOOLEAN NOT NULL DEFAULT false,
10+
"masterHost" TEXT,
11+
"masterPort" INTEGER,
12+
"masterApiKey" TEXT,
13+
"syncInterval" INTEGER NOT NULL DEFAULT 60,
14+
"lastSyncHash" TEXT,
15+
"connected" BOOLEAN NOT NULL DEFAULT false,
16+
"lastConnectedAt" TIMESTAMP(3),
17+
"connectionError" TEXT,
18+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
19+
"updatedAt" TIMESTAMP(3) NOT NULL,
20+
21+
CONSTRAINT "system_configs_pkey" PRIMARY KEY ("id")
22+
);
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
-- AlterEnum
2+
ALTER TYPE "ActivityType" ADD VALUE 'system';
3+
4+
-- AlterTable
5+
ALTER TABLE "activity_logs" ALTER COLUMN "userId" DROP NOT NULL;

0 commit comments

Comments
 (0)