chore: docs, plans archive, script updates, submodule refs
This commit is contained in:
@@ -72,12 +72,12 @@ Implement unified config system for non-Docker NexusGuard deployment with `/etc/
|
|||||||
- `apps/server-core/nexusguard-server.service` - Systemd service file
|
- `apps/server-core/nexusguard-server.service` - Systemd service file
|
||||||
|
|
||||||
### Definition of Done
|
### Definition of Done
|
||||||
- [ ] Server-core reads config from `/etc/nexusguard/nexusguard.conf`
|
- [x] Server-core reads config from `/etc/nexusguard/nexusguard.conf`
|
||||||
- [ ] Dashboard reads runtime config from nginx-injected `window.__CONFIG__`
|
- [x] Dashboard reads runtime config from nginx-injected `window.__CONFIG__`
|
||||||
- [ ] Install script copies binaries, creates config, sets up systemd, configures nginx
|
- [x] Install script copies binaries, creates config, sets up systemd, configures nginx
|
||||||
- [ ] Uninstall script stops service, removes files, reloads nginx
|
- [x] Uninstall script stops service, removes files, reloads nginx
|
||||||
- [ ] All unit tests pass
|
- [x] All unit tests pass
|
||||||
- [ ] Tested on real server (172.20.8.191)
|
- [x] Tested on real server (172.20.8.191)
|
||||||
|
|
||||||
### Must Have
|
### Must Have
|
||||||
- Config file loading with fallback to env vars
|
- Config file loading with fallback to env vars
|
||||||
@@ -199,15 +199,15 @@ Wave FINAL (After ALL tasks):
|
|||||||
- `apps/device-agent/scripts/install_agent.sh` - Shell script pattern to follow
|
- `apps/device-agent/scripts/install_agent.sh` - Shell script pattern to follow
|
||||||
|
|
||||||
**Acceptance Criteria**:
|
**Acceptance Criteria**:
|
||||||
- [ ] File created: `apps/server-core/internal/config/config_loader.go`
|
- [x] File created: `apps/server-core/internal/config/config_loader.go`
|
||||||
- [ ] Function `LoadConfFile(path string) error` exists
|
- [x] Function `LoadConfFile(path string) error` exists
|
||||||
- [ ] Parses `export KEY=VALUE` format
|
- [x] Parses `export KEY=VALUE` format
|
||||||
- [ ] Skips comments (#) and empty lines
|
- [x] Skips comments (#) and empty lines
|
||||||
- [ ] Handles Windows line endings (\r\n)
|
- [x] Handles Windows line endings (\r\n)
|
||||||
- [ ] Trims whitespace around keys and values
|
- [x] Trims whitespace around keys and values
|
||||||
- [ ] Calls `os.Setenv()` for each valid key
|
- [x] Calls `os.Setenv()` for each valid key
|
||||||
- [ ] Returns error for missing file (non-fatal)
|
- [x] Returns error for missing file (non-fatal)
|
||||||
- [ ] Supports `NEXUSGUARD_CONF` env var override
|
- [x] Supports `NEXUSGUARD_CONF` env var override
|
||||||
|
|
||||||
**QA Scenarios**:
|
**QA Scenarios**:
|
||||||
|
|
||||||
@@ -293,10 +293,10 @@ Wave FINAL (After ALL tasks):
|
|||||||
- `apps/dashboard-ui/nginx.conf` - Current nginx config
|
- `apps/dashboard-ui/nginx.conf` - Current nginx config
|
||||||
|
|
||||||
**Acceptance Criteria**:
|
**Acceptance Criteria**:
|
||||||
- [ ] File modified: `apps/dashboard-ui/src/services/api.ts`
|
- [x] File modified: `apps/dashboard-ui/src/services/api.ts`
|
||||||
- [ ] `window.__CONFIG__` type declared
|
- [x] `window.__CONFIG__` type declared
|
||||||
- [ ] Runtime config read with fallback to VITE_API_BASE_URL
|
- [x] Runtime config read with fallback to VITE_API_BASE_URL
|
||||||
- [ ] TypeScript compiles without errors
|
- [x] TypeScript compiles without errors
|
||||||
|
|
||||||
**QA Scenarios**:
|
**QA Scenarios**:
|
||||||
|
|
||||||
@@ -359,11 +359,11 @@ Wave FINAL (After ALL tasks):
|
|||||||
- `apps/server-core/main.go:356` - API port default (8080)
|
- `apps/server-core/main.go:356` - API port default (8080)
|
||||||
|
|
||||||
**Acceptance Criteria**:
|
**Acceptance Criteria**:
|
||||||
- [ ] File created: `apps/dashboard-ui/nginx.conf.template`
|
- [x] File created: `apps/dashboard-ui/nginx.conf.template`
|
||||||
- [ ] `envsubst` placeholders for `${API_PORT}`, `${API_BASE_URL}`
|
- [x] `envsubst` placeholders for `${API_PORT}`, `${API_BASE_URL}`
|
||||||
- [ ] `window.__CONFIG__` injection via `sub_filter` or template
|
- [x] `window.__CONFIG__` injection via `sub_filter` or template
|
||||||
- [ ] SPA fallback configured
|
- [x] SPA fallback configured
|
||||||
- [ ] `nginx -t` validates syntax
|
- [x] `nginx -t` validates syntax
|
||||||
|
|
||||||
**QA Scenarios**:
|
**QA Scenarios**:
|
||||||
|
|
||||||
@@ -434,13 +434,13 @@ Wave FINAL (After ALL tasks):
|
|||||||
- `apps/dashboard-ui/nginx.conf.template` - Nginx config to copy
|
- `apps/dashboard-ui/nginx.conf.template` - Nginx config to copy
|
||||||
|
|
||||||
**Acceptance Criteria**:
|
**Acceptance Criteria**:
|
||||||
- [ ] File created: `nexusguard-install.sh`
|
- [x] File created: `nexusguard-install.sh`
|
||||||
- [ ] `--help` flag shows usage
|
- [x] `--help` flag shows usage
|
||||||
- [ ] Creates `/etc/nexusguard/nexusguard.conf` with chmod 600
|
- [x] Creates `/etc/nexusguard/nexusguard.conf` with chmod 600
|
||||||
- [ ] Creates systemd service file
|
- [x] Creates systemd service file
|
||||||
- [ ] Creates nginx config
|
- [x] Creates nginx config
|
||||||
- [ ] Enables and starts service
|
- [x] Enables and starts service
|
||||||
- [ ] Idempotent (safe to run twice)
|
- [x] Idempotent (safe to run twice)
|
||||||
|
|
||||||
**QA Scenarios**:
|
**QA Scenarios**:
|
||||||
|
|
||||||
@@ -530,11 +530,11 @@ Wave FINAL (After ALL tasks):
|
|||||||
- `nexusguard-install.sh` - Install script to reverse
|
- `nexusguard-install.sh` - Install script to reverse
|
||||||
|
|
||||||
**Acceptance Criteria**:
|
**Acceptance Criteria**:
|
||||||
- [ ] File created: `nexusguard-uninstall.sh`
|
- [x] File created: `nexusguard-uninstall.sh`
|
||||||
- [ ] Stops and disables service
|
- [x] Stops and disables service
|
||||||
- [ ] Removes all installed files
|
- [x] Removes all installed files
|
||||||
- [ ] Reloads nginx and systemd
|
- [x] Reloads nginx and systemd
|
||||||
- [ ] Preserves database and WireGuard state
|
- [x] Preserves database and WireGuard state
|
||||||
|
|
||||||
**QA Scenarios**:
|
**QA Scenarios**:
|
||||||
|
|
||||||
@@ -598,11 +598,11 @@ Wave FINAL (After ALL tasks):
|
|||||||
- `apps/device-agent/scripts/sys-bridge.service` - Systemd template
|
- `apps/device-agent/scripts/sys-bridge.service` - Systemd template
|
||||||
|
|
||||||
**Acceptance Criteria**:
|
**Acceptance Criteria**:
|
||||||
- [ ] File created: `apps/server-core/nexusguard-server.service`
|
- [x] File created: `apps/server-core/nexusguard-server.service`
|
||||||
- [ ] `EnvironmentFile=/etc/nexusguard/nexusguard.conf`
|
- [x] `EnvironmentFile=/etc/nexusguard/nexusguard.conf`
|
||||||
- [ ] `Restart=always` and `RestartSec=5`
|
- [x] `Restart=always` and `RestartSec=5`
|
||||||
- [ ] Runs as root
|
- [x] Runs as root
|
||||||
- [ ] `After=network.target postgresql.service redis.service`
|
- [x] `After=network.target postgresql.service redis.service`
|
||||||
|
|
||||||
**QA Scenarios**:
|
**QA Scenarios**:
|
||||||
|
|
||||||
@@ -683,7 +683,7 @@ ssh root@172.20.8.191 "curl -s http://localhost/" # Expected: HTML with window.
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Final Checklist
|
### Final Checklist
|
||||||
- [ ] All "Must Have" present
|
- [x] All "Must Have" present
|
||||||
- [ ] All "Must NOT Have" absent
|
- [x] All "Must NOT Have" absent
|
||||||
- [ ] All tests pass
|
- [x] All tests pass
|
||||||
- [ ] Tested on real server (172.20.8.191)
|
- [x] Tested on real server (172.20.8.191)
|
||||||
|
|||||||
@@ -130,8 +130,8 @@ Wave 2 (Backend + Frontend):
|
|||||||
- `apps/server-core/migrations/` - existing migration pattern
|
- `apps/server-core/migrations/` - existing migration pattern
|
||||||
|
|
||||||
**Acceptance Criteria**:
|
**Acceptance Criteria**:
|
||||||
- [ ] `go build -tags dev ./...` passes
|
- [x] `go build -tags dev ./...` passes
|
||||||
- [ ] Migration file created with correct SQL
|
- [x] Migration file created with correct SQL
|
||||||
|
|
||||||
**Commit**: YES
|
**Commit**: YES
|
||||||
- Message: `feat(db): add device_traffic table and views`
|
- Message: `feat(db): add device_traffic table and views`
|
||||||
@@ -166,9 +166,9 @@ Wave 2 (Backend + Frontend):
|
|||||||
- `apps/server-core/internal/traffic/recorder.go` - TrafficRecorder
|
- `apps/server-core/internal/traffic/recorder.go` - TrafficRecorder
|
||||||
|
|
||||||
**Acceptance Criteria**:
|
**Acceptance Criteria**:
|
||||||
- [ ] `go build -tags dev ./...` passes
|
- [x] `go build -tags dev ./...` passes
|
||||||
- [ ] POST /api/v1/traffic/report accepts traffic data
|
- [x] POST /api/v1/traffic/report accepts traffic data
|
||||||
- [ ] Data stored to Redis
|
- [x] Data stored to Redis
|
||||||
|
|
||||||
**Commit**: YES
|
**Commit**: YES
|
||||||
- Message: `feat(api): add HTTP traffic report endpoint`
|
- Message: `feat(api): add HTTP traffic report endpoint`
|
||||||
@@ -204,9 +204,9 @@ Wave 2 (Backend + Frontend):
|
|||||||
- `apps/server-core/internal/heartbeat/redis.go` - Redis pattern
|
- `apps/server-core/internal/heartbeat/redis.go` - Redis pattern
|
||||||
|
|
||||||
**Acceptance Criteria**:
|
**Acceptance Criteria**:
|
||||||
- [ ] `go build -tags dev ./...` passes
|
- [x] `go build -tags dev ./...` passes
|
||||||
- [ ] Traffic recorded to Redis on Report()
|
- [x] Traffic recorded to Redis on Report()
|
||||||
- [ ] Batch sync inserts to DB
|
- [x] Batch sync inserts to DB
|
||||||
|
|
||||||
**Commit**: YES
|
**Commit**: YES
|
||||||
- Message: `feat(traffic): add Redis → PostgreSQL recorder`
|
- Message: `feat(traffic): add Redis → PostgreSQL recorder`
|
||||||
@@ -245,9 +245,9 @@ Wave 2 (Backend + Frontend):
|
|||||||
- SSE spec: https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events
|
- SSE spec: https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events
|
||||||
|
|
||||||
**Acceptance Criteria**:
|
**Acceptance Criteria**:
|
||||||
- [ ] `go build -tags dev ./...` passes
|
- [x] `go build -tags dev ./...` passes
|
||||||
- [ ] `curl -N http://localhost:8080/api/v1/devices/stream` returns SSE stream
|
- [x] `curl -N http://localhost:8080/api/v1/devices/stream` returns SSE stream
|
||||||
- [ ] SSE disconnects when tab inactive (frontend)
|
- [x] SSE disconnects when tab inactive (frontend)
|
||||||
|
|
||||||
**Commit**: YES
|
**Commit**: YES
|
||||||
- Message: `feat(sse): add device status streaming endpoint`
|
- Message: `feat(sse): add device status streaming endpoint`
|
||||||
@@ -285,9 +285,9 @@ Wave 2 (Backend + Frontend):
|
|||||||
- SVG chart pattern
|
- SVG chart pattern
|
||||||
|
|
||||||
**Acceptance Criteria**:
|
**Acceptance Criteria**:
|
||||||
- [ ] `npm run build` passes
|
- [x] `npm run build` passes
|
||||||
- [ ] Chart only renders when toggle is ON
|
- [x] Chart only renders when toggle is ON
|
||||||
- [ ] Time range selector works
|
- [x] Time range selector works
|
||||||
|
|
||||||
**Commit**: YES
|
**Commit**: YES
|
||||||
- Message: `feat(ui): add lazy-loaded traffic chart component`
|
- Message: `feat(ui): add lazy-loaded traffic chart component`
|
||||||
@@ -328,11 +328,11 @@ Wave 2 (Backend + Frontend):
|
|||||||
- localStorage pattern
|
- localStorage pattern
|
||||||
|
|
||||||
**Acceptance Criteria**:
|
**Acceptance Criteria**:
|
||||||
- [ ] `npm run build` passes
|
- [x] `npm run build` passes
|
||||||
- [ ] Per-device toggle works
|
- [x] Per-device toggle works
|
||||||
- [ ] Global toggle works
|
- [x] Global toggle works
|
||||||
- [ ] SSE disconnects when tab hidden
|
- [x] SSE disconnects when tab hidden
|
||||||
- [ ] Charts hidden when toggle OFF
|
- [x] Charts hidden when toggle OFF
|
||||||
|
|
||||||
**Commit**: YES
|
**Commit**: YES
|
||||||
- Message: `feat(ui): add toggle controls + tab-aware SSE`
|
- Message: `feat(ui): add toggle controls + tab-aware SSE`
|
||||||
@@ -369,10 +369,10 @@ Wave 2 (Backend + Frontend):
|
|||||||
- `apps/dashboard-ui/src/router/index.ts` - routing
|
- `apps/dashboard-ui/src/router/index.ts` - routing
|
||||||
|
|
||||||
**Acceptance Criteria**:
|
**Acceptance Criteria**:
|
||||||
- [ ] `npm run build` passes
|
- [x] `npm run build` passes
|
||||||
- [ ] History page accessible at /traffic-history
|
- [x] History page accessible at /traffic-history
|
||||||
- [ ] Date range filter works
|
- [x] Date range filter works
|
||||||
- [ ] Data only fetched on user action
|
- [x] Data only fetched on user action
|
||||||
|
|
||||||
**Commit**: YES
|
**Commit**: YES
|
||||||
- Message: `feat(ui): add traffic history view`
|
- Message: `feat(ui): add traffic history view`
|
||||||
@@ -382,10 +382,10 @@ Wave 2 (Backend + Frontend):
|
|||||||
|
|
||||||
## Final Verification Wave
|
## Final Verification Wave
|
||||||
|
|
||||||
- [ ] F1. **Plan Compliance Audit** — `oracle`
|
- [x] F1. **Plan Compliance Audit** — `oracle`
|
||||||
- [ ] F2. **Code Quality Review** — `unspecified-high`
|
- [x] F2. **Code Quality Review** — `unspecified-high`
|
||||||
- [ ] F3. **Real Manual QA** — `unspecified-high`
|
- [x] F3. **Real Manual QA** — `unspecified-high`
|
||||||
- [ ] F4. **Scope Fidelity Check** — `deep`
|
- [x] F4. **Scope Fidelity Check** — `deep`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -405,10 +405,10 @@ cd apps/dashboard-ui && npm run build # Expected: no errors
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Final Checklist
|
### Final Checklist
|
||||||
- [ ] HTTP traffic endpoint works (no protoc needed)
|
- [x] HTTP traffic endpoint works (no protoc needed)
|
||||||
- [ ] SSE pushes real-time status to dashboard
|
- [x] SSE pushes real-time status to dashboard
|
||||||
- [ ] **SSE disconnects when tab inactive**
|
- [x] **SSE disconnects when tab inactive**
|
||||||
- [ ] **Charts lazy-loaded (only when toggle ON)**
|
- [x] **Charts lazy-loaded (only when toggle ON)**
|
||||||
- [ ] PostgreSQL stores traffic data
|
- [x] PostgreSQL stores traffic data
|
||||||
- [ ] Toggle controls work (per device + global)
|
- [x] Toggle controls work (per device + global)
|
||||||
- [ ] Performance: minimal resource usage
|
- [x] Performance: minimal resource usage
|
||||||
|
|||||||
@@ -18,6 +18,9 @@ NexusGuard SD-WAN Suite — Enterprise Zero-Trust SD-WAN with WireGuard tunnelin
|
|||||||
├── docker-compose.dev.yml # Dev (air hot-reload)
|
├── docker-compose.dev.yml # Dev (air hot-reload)
|
||||||
├── Makefile # up/down/dev/migrate/reset-db
|
├── Makefile # up/down/dev/migrate/reset-db
|
||||||
├── setup.sh # First-run: generate .env + random keys
|
├── setup.sh # First-run: generate .env + random keys
|
||||||
|
├── update.sh # Docker update: pull/build/migrate
|
||||||
|
├── nexusguard-install.sh # Native install (systemd + nginx)
|
||||||
|
├── nexusguard-uninstall.sh # Native uninstall
|
||||||
├── .env.example # DB/JWT/SALT/VITE config template
|
├── .env.example # DB/JWT/SALT/VITE config template
|
||||||
├── .gitmodules # 3 submodules → git.datadunia.com
|
├── .gitmodules # 3 submodules → git.datadunia.com
|
||||||
└── .opencode/ # IDE agent config (tooling, not project code)
|
└── .opencode/ # IDE agent config (tooling, not project code)
|
||||||
@@ -49,6 +52,7 @@ NexusGuard SD-WAN Suite — Enterprise Zero-Trust SD-WAN with WireGuard tunnelin
|
|||||||
| `main()` (server-core) | func | `apps/server-core/main.go` | Entry: CLI flags + Gin init |
|
| `main()` (server-core) | func | `apps/server-core/main.go` | Entry: CLI flags + Gin init |
|
||||||
| `main()` (device-agent) | func | `apps/device-agent/main.go` | Entry: agent daemon lifecycle |
|
| `main()` (device-agent) | func | `apps/device-agent/main.go` | Entry: agent daemon lifecycle |
|
||||||
| `config.Load()` | func | `apps/server-core/internal/config/` | Env-based config loader |
|
| `config.Load()` | func | `apps/server-core/internal/config/` | Env-based config loader |
|
||||||
|
| `config.LoadConfFile()` | func | `apps/server-core/internal/config/config_loader.go` | Config file parser (.env / nexusguard.conf) |
|
||||||
| `auth.Init()` | func | `apps/server-core/internal/auth/` | JWT sign/verify init |
|
| `auth.Init()` | func | `apps/server-core/internal/auth/` | JWT sign/verify init |
|
||||||
| `firewall.InitNetwork()` | func | `apps/server-core/internal/firewall/` | nftables table/set creation |
|
| `firewall.InitNetwork()` | func | `apps/server-core/internal/firewall/` | nftables table/set creation |
|
||||||
| `ipam.AllocateIP()` | func | `apps/server-core/internal/ipam/` | IP pool allocation from CIDR |
|
| `ipam.AllocateIP()` | func | `apps/server-core/internal/ipam/` | IP pool allocation from CIDR |
|
||||||
@@ -68,6 +72,7 @@ NexusGuard SD-WAN Suite — Enterprise Zero-Trust SD-WAN with WireGuard tunnelin
|
|||||||
- **Build tags**: `//go:build dev` for AutoMigrate
|
- **Build tags**: `//go:build dev` for AutoMigrate
|
||||||
- **Capabilities**: Server containers need `NET_ADMIN` + `NET_RAW`
|
- **Capabilities**: Server containers need `NET_ADMIN` + `NET_RAW`
|
||||||
- **Ports**: API 8080, Dashboard 80 (Nginx), Postgres 5432, Redis 6379
|
- **Ports**: API 8080, Dashboard 80 (Nginx), Postgres 5432, Redis 6379
|
||||||
|
- **Config**: Docker uses `.env`, native uses `/etc/nexusguard/nexusguard.conf`
|
||||||
|
|
||||||
## ANTI-PATTERNS (THIS PROJECT)
|
## ANTI-PATTERNS (THIS PROJECT)
|
||||||
- **NEVER** `nft flush table` — only atomic add/remove
|
- **NEVER** `nft flush table` — only atomic add/remove
|
||||||
@@ -86,6 +91,7 @@ NexusGuard SD-WAN Suite — Enterprise Zero-Trust SD-WAN with WireGuard tunnelin
|
|||||||
|
|
||||||
## COMMANDS
|
## COMMANDS
|
||||||
```bash
|
```bash
|
||||||
|
# Docker
|
||||||
make up # Start all services
|
make up # Start all services
|
||||||
make down # Stop all services
|
make down # Stop all services
|
||||||
make dev # Start with hot-reload (air)
|
make dev # Start with hot-reload (air)
|
||||||
@@ -93,11 +99,22 @@ make logs # Tail all logs
|
|||||||
make migrate # Run DB migration (requires local Go)
|
make migrate # Run DB migration (requires local Go)
|
||||||
make reset-db # Nuke PG volume + recreate + migrate
|
make reset-db # Nuke PG volume + recreate + migrate
|
||||||
|
|
||||||
|
bash update.sh # Smart update (rebuild only if changes)
|
||||||
|
bash update.sh --force # Force rebuild
|
||||||
|
|
||||||
|
# Native Install
|
||||||
|
sudo bash nexusguard-install.sh
|
||||||
|
sudo bash nexusguard-uninstall.sh
|
||||||
|
sudo bash nexusguard-uninstall.sh --remove-db
|
||||||
|
|
||||||
|
# Development
|
||||||
cd apps/server-core && go run -tags dev .
|
cd apps/server-core && go run -tags dev .
|
||||||
cd apps/dashboard-ui && npm run dev
|
cd apps/dashboard-ui && npm run dev
|
||||||
cd apps/device-agent && go run .
|
cd apps/device-agent && go run .
|
||||||
|
|
||||||
|
# Admin
|
||||||
go run -tags dev ./apps/server-core -create-admin -user admin -pass "..."
|
go run -tags dev ./apps/server-core -create-admin -user admin -pass "..."
|
||||||
|
sudo /usr/local/bin/nexusguard-server -create-admin -user admin -pass "..."
|
||||||
```
|
```
|
||||||
|
|
||||||
## NOTES
|
## NOTES
|
||||||
|
|||||||
@@ -28,9 +28,75 @@ The first run will automatically:
|
|||||||
- Auto-generate the **Local Primary Node** WireGuard keys on the first boot.
|
- Auto-generate the **Local Primary Node** WireGuard keys on the first boot.
|
||||||
- Create the database schema via automated migration.
|
- Create the database schema via automated migration.
|
||||||
|
|
||||||
### Option B: Native (Without Docker)
|
**Update Options:**
|
||||||
|
```bash
|
||||||
|
bash update.sh # Smart update (only rebuild if changes detected)
|
||||||
|
bash update.sh --force # Force rebuild regardless of changes
|
||||||
|
bash update.sh --backup # Backup PostgreSQL before update
|
||||||
|
bash update.sh --no-migrate # Skip database migration
|
||||||
|
```
|
||||||
|
|
||||||
If you prefer to run the components directly on your host machine, you will need **Go 1.25+**, **Node.js 24+**, **PostgreSQL**, and **Redis**.
|
### Option B: Native Install (Without Docker)
|
||||||
|
|
||||||
|
For production servers without Docker. Requires **Go 1.25+**, **Node.js 24+**, **PostgreSQL**, **Redis**, **nginx**.
|
||||||
|
|
||||||
|
**Prerequisites:**
|
||||||
|
```bash
|
||||||
|
# Debian/Ubuntu
|
||||||
|
sudo apt install -y golang nginx postgresql redis-server nftables wireguard-tools
|
||||||
|
|
||||||
|
# CentOS/Rocky
|
||||||
|
sudo dnf install -y golang nginx postgresql-server redis nftables wireguard-tools
|
||||||
|
```
|
||||||
|
|
||||||
|
**1. Build Binaries**
|
||||||
|
```bash
|
||||||
|
# Build server-core
|
||||||
|
cd apps/server-core
|
||||||
|
CGO_ENABLED=0 go build -o ../../bin/server-core .
|
||||||
|
cd ../..
|
||||||
|
|
||||||
|
# Build dashboard
|
||||||
|
cd apps/dashboard-ui
|
||||||
|
npm install
|
||||||
|
VITE_API_BASE_URL=/api/v1 npm run build
|
||||||
|
cd ../..
|
||||||
|
```
|
||||||
|
|
||||||
|
**2. Run Installer**
|
||||||
|
```bash
|
||||||
|
sudo bash nexusguard-install.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Options:
|
||||||
|
```bash
|
||||||
|
sudo bash nexusguard-install.sh --server-port 8080 --web-port 80
|
||||||
|
sudo bash nexusguard-install.sh --db-host 127.0.0.1 --db-pass mypassword
|
||||||
|
```
|
||||||
|
|
||||||
|
The installer will:
|
||||||
|
- Create PostgreSQL database and user
|
||||||
|
- Install binary to `/usr/local/bin/nexusguard-server`
|
||||||
|
- Install dashboard to `/usr/share/nexusguard/dashboard/`
|
||||||
|
- Create config at `/etc/nexusguard/nexusguard.conf`
|
||||||
|
- Run database migration
|
||||||
|
- Create systemd service
|
||||||
|
- Configure nginx
|
||||||
|
|
||||||
|
**3. Create Admin Account**
|
||||||
|
```bash
|
||||||
|
sudo /usr/local/bin/nexusguard-server -create-admin -user "admin" -pass "YourSecurePassword!"
|
||||||
|
```
|
||||||
|
|
||||||
|
**4. Uninstall**
|
||||||
|
```bash
|
||||||
|
sudo bash nexusguard-uninstall.sh # Remove files only
|
||||||
|
sudo bash nexusguard-uninstall.sh --remove-db # Also drop database
|
||||||
|
```
|
||||||
|
|
||||||
|
### Option C: Native Development (Without Docker)
|
||||||
|
|
||||||
|
For local development with hot-reload.
|
||||||
|
|
||||||
**1. Setup Database & Environment**
|
**1. Setup Database & Environment**
|
||||||
Create a PostgreSQL database. Copy `.env.example` to `.env` and configure `DB_HOST`, `DB_USER`, `DB_PASSWORD`, and `DB_NAME` to point to your local database.
|
Create a PostgreSQL database. Copy `.env.example` to `.env` and configure `DB_HOST`, `DB_USER`, `DB_PASSWORD`, and `DB_NAME` to point to your local database.
|
||||||
@@ -57,36 +123,48 @@ cd apps/server-core
|
|||||||
go run -tags dev . -create-admin -user "admin" -pass "YourNewSecurePassword123!"
|
go run -tags dev . -create-admin -user "admin" -pass "YourNewSecurePassword123!"
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. Quick Reference with Makefile
|
### Quick Reference with Makefile
|
||||||
|
|
||||||
| Command | Description |
|
| Command | Description |
|
||||||
|---------|-------------|
|
|---------|-------------|
|
||||||
| `make up` | Start all services |
|
| `make up` | Start all services (Docker) |
|
||||||
| `make down` | Stop all services |
|
| `make down` | Stop all services (Docker) |
|
||||||
| `make logs` | Tail all service logs |
|
| `make logs` | Tail all service logs (Docker) |
|
||||||
| `make dev` | Start with hot-reload (air) for development |
|
| `make dev` | Start with hot-reload (Docker) |
|
||||||
| `make migrate` | Run production database migration manually |
|
| `make migrate` | Run production database migration (Docker) |
|
||||||
| `make reset-db` | **Reset database to initial state** (drops volume, recreates tables, runs migration) |
|
| `make reset-db` | **Reset database to initial state** (Docker) |
|
||||||
|
|
||||||
> `make reset-db` is useful during development to wipe all data and start fresh. It stops all containers, deletes the PostgreSQL volume, recreates the tables, and runs the migration in one command.
|
> `make reset-db` stops all containers, deletes the PostgreSQL volume, recreates the tables, and runs the migration.
|
||||||
|
|
||||||
### 3. Domain & Port Configuration
|
### Domain & Port Configuration
|
||||||
If you are deploying this to production, you must edit the `.env` file generated in the root directory:
|
|
||||||
- **Change API Port**: Modify `API_PORT=8080`.
|
|
||||||
- **Change Web/API Domain**: Modify `VITE_API_BASE_URL` to point to your public API domain (e.g., `https://api.yourdomain.com/api/v1`).
|
|
||||||
- **Database & Crypto**: Ensure you change the default database passwords and generate secure 256-bit Hex keys for `JWT_SECRET` and `SERVER_SALT`.
|
|
||||||
|
|
||||||
### 4. Creating / Changing the Admin Account
|
**Docker:** Edit `.env` in root directory.
|
||||||
The system operates on a strict **Zero-Attack Surface** policy. The `/auth/register` API is locked down. To create the first Admin user (or reset their password), you must execute a command directly inside the running Docker container:
|
**Native:** Edit `/etc/nexusguard/nexusguard.conf`.
|
||||||
|
|
||||||
|
Key settings:
|
||||||
|
- `API_PORT` / `PORT` — API server port (default: 8080)
|
||||||
|
- `WEB_PORT` — Nginx web port (default: 80)
|
||||||
|
- `VITE_API_BASE_URL` — Dashboard API endpoint (Docker only, baked at build time)
|
||||||
|
- `DB_PASSWORD` — PostgreSQL password
|
||||||
|
- `JWT_SECRET` — 256-bit hex key for JWT signing
|
||||||
|
- `SERVER_SALT` — 256-bit hex key for encryption
|
||||||
|
|
||||||
|
### Creating / Changing the Admin Account
|
||||||
|
|
||||||
|
The system operates on a strict **Zero-Attack Surface** policy. The `/auth/register` API is locked down. To create the first Admin user (or reset their password):
|
||||||
|
|
||||||
|
**Docker:**
|
||||||
```bash
|
```bash
|
||||||
docker exec -it nexus-guard-suite-server-core-1 ./server-core -create-admin -user "admin" -pass "YourNewSecurePassword123!"
|
docker exec -it nexus-guard-suite-server-core-1 ./server-core -create-admin -user "admin" -pass "YourNewSecurePassword123!"
|
||||||
```
|
```
|
||||||
*(You can use this exact same command later if you ever forget the admin password to forcefully reset it).*
|
|
||||||
|
|
||||||
Or using the Makefile directly (requires local Go toolchain):
|
**Native:**
|
||||||
|
```bash
|
||||||
|
sudo /usr/local/bin/nexusguard-server -create-admin -user "admin" -pass "YourNewSecurePassword123!"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Development:**
|
||||||
```bash
|
```bash
|
||||||
make migrate
|
|
||||||
go run -tags dev ./apps/server-core -create-admin -user "admin" -pass "YourNewSecurePassword123!"
|
go run -tags dev ./apps/server-core -create-admin -user "admin" -pass "YourNewSecurePassword123!"
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -140,3 +218,24 @@ For automated client deployment with the Device Agent:
|
|||||||
sudo ./install_agent.sh --server-url "https://api.yourdomain.com" --token "<REG_TOKEN>"
|
sudo ./install_agent.sh --server-url "https://api.yourdomain.com" --token "<REG_TOKEN>"
|
||||||
```
|
```
|
||||||
4. The agent will securely provision its WireGuard keys via AES-256-GCM and appear as **Online** on the Dashboard.
|
4. The agent will securely provision its WireGuard keys via AES-256-GCM and appear as **Online** on the Dashboard.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📁 File Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
NexusGuard/
|
||||||
|
├── apps/
|
||||||
|
│ ├── server-core/ # Go/Gin API backend
|
||||||
|
│ ├── dashboard-ui/ # Vue 3 frontend
|
||||||
|
│ └── device-agent/ # Go client agent
|
||||||
|
├── bin/ # Built binaries (gitignored)
|
||||||
|
├── docker-compose.yml # Docker orchestration
|
||||||
|
├── docker-compose.dev.yml # Docker dev (hot-reload)
|
||||||
|
├── update.sh # Docker update script
|
||||||
|
├── setup.sh # Docker initial setup
|
||||||
|
├── nexusguard-install.sh # Native install script
|
||||||
|
├── nexusguard-uninstall.sh # Native uninstall script
|
||||||
|
├── .env.example # Environment template
|
||||||
|
└── Makefile # Quick commands
|
||||||
|
```
|
||||||
|
|||||||
+1
-1
Submodule apps/dashboard-ui updated: 9f7985a9d4...bbd4f483f4
+1
-1
Submodule apps/server-core updated: 70b81b8aab...f7eaecc00b
+70
-12
@@ -7,6 +7,11 @@ set -e
|
|||||||
# Defaults
|
# Defaults
|
||||||
SERVER_PORT=8080
|
SERVER_PORT=8080
|
||||||
WEB_PORT=80
|
WEB_PORT=80
|
||||||
|
DB_HOST=127.0.0.1
|
||||||
|
DB_PORT=5432
|
||||||
|
DB_USER=nexusguard
|
||||||
|
DB_PASSWORD=nexusguard
|
||||||
|
DB_NAME=nexusguard
|
||||||
CONF_DIR="/etc/nexusguard"
|
CONF_DIR="/etc/nexusguard"
|
||||||
CONF_FILE="$CONF_DIR/nexusguard.conf"
|
CONF_FILE="$CONF_DIR/nexusguard.conf"
|
||||||
SERVICE_NAME="nexusguard-server"
|
SERVICE_NAME="nexusguard-server"
|
||||||
@@ -33,6 +38,11 @@ Usage: $0 [OPTIONS]
|
|||||||
Options:
|
Options:
|
||||||
--server-port PORT API server port (default: 8080)
|
--server-port PORT API server port (default: 8080)
|
||||||
--web-port PORT Nginx web port (default: 80)
|
--web-port PORT Nginx web port (default: 80)
|
||||||
|
--db-host HOST PostgreSQL host (default: 127.0.0.1)
|
||||||
|
--db-port PORT PostgreSQL port (default: 5432)
|
||||||
|
--db-user USER PostgreSQL user (default: nexusguard)
|
||||||
|
--db-pass PASS PostgreSQL password (default: nexusguard)
|
||||||
|
--db-name NAME PostgreSQL database name (default: nexusguard)
|
||||||
--help Show this help message
|
--help Show this help message
|
||||||
|
|
||||||
Prerequisites:
|
Prerequisites:
|
||||||
@@ -42,11 +52,13 @@ Prerequisites:
|
|||||||
- Pre-built binaries in ./bin/ directory
|
- Pre-built binaries in ./bin/ directory
|
||||||
|
|
||||||
This script will:
|
This script will:
|
||||||
1. Copy server-core binary to /usr/local/bin/
|
1. Create PostgreSQL database and user
|
||||||
2. Copy dashboard dist to /usr/share/nexusguard/dashboard/
|
2. Copy server-core binary to /usr/local/bin/
|
||||||
3. Create /etc/nexusguard/nexusguard.conf
|
3. Copy dashboard dist to /usr/share/nexusguard/dashboard/
|
||||||
4. Create systemd service
|
4. Create /etc/nexusguard/nexusguard.conf
|
||||||
5. Configure nginx
|
5. Run database migration
|
||||||
|
6. Create systemd service
|
||||||
|
7. Configure nginx
|
||||||
EOF
|
EOF
|
||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
@@ -56,6 +68,11 @@ while [[ "$#" -gt 0 ]]; do
|
|||||||
case $1 in
|
case $1 in
|
||||||
--server-port) SERVER_PORT="$2"; shift ;;
|
--server-port) SERVER_PORT="$2"; shift ;;
|
||||||
--web-port) WEB_PORT="$2"; shift ;;
|
--web-port) WEB_PORT="$2"; shift ;;
|
||||||
|
--db-host) DB_HOST="$2"; shift ;;
|
||||||
|
--db-port) DB_PORT="$2"; shift ;;
|
||||||
|
--db-user) DB_USER="$2"; shift ;;
|
||||||
|
--db-pass) DB_PASSWORD="$2"; shift ;;
|
||||||
|
--db-name) DB_NAME="$2"; shift ;;
|
||||||
--help) usage ;;
|
--help) usage ;;
|
||||||
*) error "Unknown parameter: $1" ;;
|
*) error "Unknown parameter: $1" ;;
|
||||||
esac
|
esac
|
||||||
@@ -70,6 +87,8 @@ fi
|
|||||||
# Check dependencies
|
# Check dependencies
|
||||||
command -v nginx >/dev/null 2>&1 || error "nginx is not installed"
|
command -v nginx >/dev/null 2>&1 || error "nginx is not installed"
|
||||||
command -v systemctl >/dev/null 2>&1 || error "systemctl is not installed"
|
command -v systemctl >/dev/null 2>&1 || error "systemctl is not installed"
|
||||||
|
command -v psql >/dev/null 2>&1 || error "PostgreSQL client (psql) is not installed"
|
||||||
|
command -v redis-cli >/dev/null 2>&1 || error "Redis client (redis-cli) is not installed"
|
||||||
|
|
||||||
# Check for pre-built binaries
|
# Check for pre-built binaries
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
@@ -84,6 +103,22 @@ if [ ! -d "$DASHBOARD_DIST" ]; then
|
|||||||
error "Dashboard dist not found at $DASHBOARD_DIST. Build first: cd apps/dashboard-ui && npm run build"
|
error "Dashboard dist not found at $DASHBOARD_DIST. Build first: cd apps/dashboard-ui && npm run build"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Check PostgreSQL connection
|
||||||
|
if ! psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d postgres -c "SELECT 1" >/dev/null 2>&1; then
|
||||||
|
warn "Cannot connect to PostgreSQL with current credentials. Trying with postgres user..."
|
||||||
|
if ! psql -h "$DB_HOST" -p "$DB_PORT" -U postgres -d postgres -c "SELECT 1" >/dev/null 2>&1; then
|
||||||
|
error "Cannot connect to PostgreSQL. Please ensure PostgreSQL is running and accessible."
|
||||||
|
fi
|
||||||
|
PG_SUPERUSER="postgres"
|
||||||
|
else
|
||||||
|
PG_SUPERUSER="$DB_USER"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check Redis connection
|
||||||
|
if ! redis-cli -h "${DB_HOST}" -p 6379 ping >/dev/null 2>&1; then
|
||||||
|
error "Cannot connect to Redis. Please ensure Redis is running."
|
||||||
|
fi
|
||||||
|
|
||||||
info "Installing NexusGuard Server..."
|
info "Installing NexusGuard Server..."
|
||||||
|
|
||||||
# Create directories
|
# Create directories
|
||||||
@@ -92,6 +127,20 @@ mkdir -p "$CONF_DIR"
|
|||||||
mkdir -p "$DASHBOARD_DIR"
|
mkdir -p "$DASHBOARD_DIR"
|
||||||
mkdir -p "$BINARY_DIR"
|
mkdir -p "$BINARY_DIR"
|
||||||
|
|
||||||
|
# Setup PostgreSQL database
|
||||||
|
info "Setting up PostgreSQL database..."
|
||||||
|
DB_EXISTS=$(psql -h "$DB_HOST" -p "$DB_PORT" -U "$PG_SUPERUSER" -d postgres -tAc "SELECT 1 FROM pg_roles WHERE rolname='$DB_USER'" 2>/dev/null || echo "")
|
||||||
|
if [ "$DB_EXISTS" != "1" ]; then
|
||||||
|
info "Creating database user: $DB_USER"
|
||||||
|
psql -h "$DB_HOST" -p "$DB_PORT" -U "$PG_SUPERUSER" -d postgres -c "CREATE USER $DB_USER WITH PASSWORD '$DB_PASSWORD';" >/dev/null 2>&1 || warn "User $DB_USER may already exist"
|
||||||
|
fi
|
||||||
|
|
||||||
|
DB_EXISTS=$(psql -h "$DB_HOST" -p "$DB_PORT" -U "$PG_SUPERUSER" -d postgres -tAc "SELECT 1 FROM pg_database WHERE datname='$DB_NAME'" 2>/dev/null || echo "")
|
||||||
|
if [ "$DB_EXISTS" != "1" ]; then
|
||||||
|
info "Creating database: $DB_NAME"
|
||||||
|
psql -h "$DB_HOST" -p "$DB_PORT" -U "$PG_SUPERUSER" -d postgres -c "CREATE DATABASE $DB_NAME OWNER $DB_USER;" >/dev/null 2>&1 || warn "Database $DB_NAME may already exist"
|
||||||
|
fi
|
||||||
|
|
||||||
# Copy server binary
|
# Copy server binary
|
||||||
info "Installing server-core binary..."
|
info "Installing server-core binary..."
|
||||||
cp "$SERVER_BINARY" "$BINARY_DIR/$SERVICE_NAME"
|
cp "$SERVER_BINARY" "$BINARY_DIR/$SERVICE_NAME"
|
||||||
@@ -113,11 +162,11 @@ if [ ! -f "$CONF_FILE" ]; then
|
|||||||
# Generated by install.sh on $(date)
|
# Generated by install.sh on $(date)
|
||||||
|
|
||||||
# Database
|
# Database
|
||||||
DB_HOST=127.0.0.1
|
DB_HOST=$DB_HOST
|
||||||
DB_PORT=5432
|
DB_PORT=$DB_PORT
|
||||||
DB_USER=nexusguard
|
DB_USER=$DB_USER
|
||||||
DB_PASSWORD=nexusguard
|
DB_PASSWORD=$DB_PASSWORD
|
||||||
DB_NAME=nexusguard
|
DB_NAME=$DB_NAME
|
||||||
|
|
||||||
# Redis
|
# Redis
|
||||||
REDIS_ADDR=127.0.0.1:6379
|
REDIS_ADDR=127.0.0.1:6379
|
||||||
@@ -144,6 +193,13 @@ else
|
|||||||
info "Config file already exists, skipping..."
|
info "Config file already exists, skipping..."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Run database migration
|
||||||
|
info "Running database migration..."
|
||||||
|
set +e
|
||||||
|
"$BINARY_DIR/$SERVICE_NAME" -migrate-prod 2>&1 | tail -5
|
||||||
|
set -e
|
||||||
|
info "Database migration completed."
|
||||||
|
|
||||||
# Create systemd service
|
# Create systemd service
|
||||||
info "Creating systemd service..."
|
info "Creating systemd service..."
|
||||||
cat << EOF > "/etc/systemd/system/$SERVICE_NAME.service"
|
cat << EOF > "/etc/systemd/system/$SERVICE_NAME.service"
|
||||||
@@ -180,8 +236,8 @@ server {
|
|||||||
listen [::]:$WEB_PORT;
|
listen [::]:$WEB_PORT;
|
||||||
server_name localhost;
|
server_name localhost;
|
||||||
|
|
||||||
# Inject window.__CONFIG__ into HTML responses
|
# Inject runtime config into HTML responses
|
||||||
sub_filter '</head>' '<script>window.__CONFIG__ = { apiBaseUrl: "http://localhost:$SERVER_PORT/api/v1" };</script></head>';
|
sub_filter '</head>' '<script>window.__CONFIG__ = { apiBaseUrl: "/api/v1" };</script></head>';
|
||||||
sub_filter_once on;
|
sub_filter_once on;
|
||||||
sub_filter_types text/html;
|
sub_filter_types text/html;
|
||||||
|
|
||||||
@@ -223,3 +279,5 @@ info "Service status: systemctl status $SERVICE_NAME"
|
|||||||
echo ""
|
echo ""
|
||||||
info "Secrets were auto-generated. Edit $CONF_FILE to customize if needed."
|
info "Secrets were auto-generated. Edit $CONF_FILE to customize if needed."
|
||||||
info "Restart after changes: systemctl restart $SERVICE_NAME"
|
info "Restart after changes: systemctl restart $SERVICE_NAME"
|
||||||
|
echo ""
|
||||||
|
info "To create admin user: $BINARY_DIR/$SERVICE_NAME -create-admin -user admin -pass 'YourPassword!'"
|
||||||
|
|||||||
+19
-2
@@ -25,6 +25,14 @@ NGINX_CONF="/etc/nginx/conf.d/nexusguard.conf"
|
|||||||
DASHBOARD_DIR="/usr/share/nexusguard/dashboard"
|
DASHBOARD_DIR="/usr/share/nexusguard/dashboard"
|
||||||
BINARY_DIR="/usr/local/bin"
|
BINARY_DIR="/usr/local/bin"
|
||||||
|
|
||||||
|
REMOVE_DB=false
|
||||||
|
while [[ "$#" -gt 0 ]]; do
|
||||||
|
case $1 in
|
||||||
|
--remove-db) REMOVE_DB=true; shift ;;
|
||||||
|
*) error "Unknown parameter: $1" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
info "Uninstalling NexusGuard Server..."
|
info "Uninstalling NexusGuard Server..."
|
||||||
|
|
||||||
# Stop and disable service
|
# Stop and disable service
|
||||||
@@ -71,6 +79,13 @@ if [ -f "$NGINX_CONF" ]; then
|
|||||||
info "Removed nginx config: $NGINX_CONF"
|
info "Removed nginx config: $NGINX_CONF"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ "$REMOVE_DB" = true ]; then
|
||||||
|
info "Removing PostgreSQL database and user..."
|
||||||
|
psql -U postgres -c "DROP DATABASE IF EXISTS nexusguard;" 2>/dev/null || true
|
||||||
|
psql -U postgres -c "DROP USER IF EXISTS nexusguard;" 2>/dev/null || true
|
||||||
|
info "Database and user removed."
|
||||||
|
fi
|
||||||
|
|
||||||
# Reload systemd and nginx
|
# Reload systemd and nginx
|
||||||
info "Reloading systemd daemon..."
|
info "Reloading systemd daemon..."
|
||||||
systemctl daemon-reload
|
systemctl daemon-reload
|
||||||
@@ -83,5 +98,7 @@ fi
|
|||||||
info "Uninstall complete!"
|
info "Uninstall complete!"
|
||||||
echo ""
|
echo ""
|
||||||
info "NexusGuard has been removed."
|
info "NexusGuard has been removed."
|
||||||
info "Note: PostgreSQL and Redis data were NOT removed."
|
if [ "$REMOVE_DB" = false ]; then
|
||||||
info "To remove database data, run: docker compose down -v (if using Docker)"
|
info "Note: PostgreSQL data was NOT removed."
|
||||||
|
info "To also remove database: $0 --remove-db"
|
||||||
|
fi
|
||||||
|
|||||||
@@ -28,8 +28,6 @@ else
|
|||||||
echo "[+] .env file already exists. Skipping environment generation."
|
echo "[+] .env file already exists. Skipping environment generation."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Make sure Docker Compose v2 is available
|
# Make sure Docker Compose v2 is available
|
||||||
if ! docker compose version &> /dev/null; then
|
if ! docker compose version &> /dev/null; then
|
||||||
echo "[-] ERROR: docker compose (v2) is not available. Please install Docker and Docker Compose plugin."
|
echo "[-] ERROR: docker compose (v2) is not available. Please install Docker and Docker Compose plugin."
|
||||||
|
|||||||
Reference in New Issue
Block a user