describe what changed
This commit is contained in:
parent
fbd10a9cfd
commit
d04e5bcc10
15 changed files with 3426 additions and 0 deletions
146
email_template_style.md
Normal file
146
email_template_style.md
Normal file
|
|
@ -0,0 +1,146 @@
|
||||||
|
# KingDezigns Email Template Style Guide
|
||||||
|
|
||||||
|
Last Updated: 2026-05-26
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
All automated HTML emails in the KingDezigns infrastructure follow a consistent visual style.
|
||||||
|
Reference this document when building new notification emails for any service.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Design Principles
|
||||||
|
- Dark header (`#0f172a`) with white text — always includes hostname and timestamp
|
||||||
|
- Color-coded status banner below header (green / amber / red)
|
||||||
|
- White card body with `border-radius:10px`, `box-shadow`, `border:1px solid #e5e7eb`
|
||||||
|
- Stat/metric values displayed as large bold figures in `#f9fafb` pill cards
|
||||||
|
- Monospace `pre` blocks for raw output — dark background `#1e293b`, light text `#e2e8f0`
|
||||||
|
- Dark footer (`#0f172a`) with "KingDezigns Infrastructure" branding
|
||||||
|
- Max width: 720px, centered, outer background `#f1f5f9`
|
||||||
|
- Font stack: `-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Severity Colors
|
||||||
|
|
||||||
|
| Severity | Background | Text | Use When |
|
||||||
|
|----------|-----------|-------|----------|
|
||||||
|
| HEALTHY / OK | `#1a7f4b` | white | All clear |
|
||||||
|
| WARNING | `#b45309` | white | Attention needed |
|
||||||
|
| CRITICAL | `#b91c1c` | white | Immediate action required |
|
||||||
|
|
||||||
|
Row background tints:
|
||||||
|
- OK: `#f0fdf4`
|
||||||
|
- WARNING: `#fffbeb`
|
||||||
|
- CRITICAL: `#fff1f2`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Header Block
|
||||||
|
```html
|
||||||
|
<tr><td style="background:#0f172a;border-radius:10px 10px 0 0;padding:28px 32px;">
|
||||||
|
<table width="100%" cellspacing="0" cellpadding="0"><tr>
|
||||||
|
<td>
|
||||||
|
<div style="font-size:11px;color:#94a3b8;letter-spacing:1px;text-transform:uppercase;">SERVICE NAME</div>
|
||||||
|
<div style="font-size:26px;font-weight:800;color:white;margin-top:4px;">ICON HOSTNAME</div>
|
||||||
|
<div style="font-size:13px;color:#94a3b8;margin-top:4px;">TIMESTAMP | CONTEXT INFO</div>
|
||||||
|
</td>
|
||||||
|
<td align="right">
|
||||||
|
<div style="background:STATUS_COLOR;color:white;padding:10px 20px;border-radius:8px;font-size:14px;font-weight:700;">STATUS BADGE</div>
|
||||||
|
</td>
|
||||||
|
</tr></table>
|
||||||
|
</td></tr>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Status Banner Block
|
||||||
|
```html
|
||||||
|
<tr><td style="background:STATUS_COLOR;padding:12px 32px;">
|
||||||
|
<span style="color:white;font-size:14px;font-weight:600;">ICON STATUS MESSAGE</span>
|
||||||
|
</td></tr>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Stat Card Row
|
||||||
|
```html
|
||||||
|
<td style="width:16%;padding:8px 12px;background:#f9fafb;border-radius:6px;text-align:center;">
|
||||||
|
<div style="font-size:11px;color:#9ca3af;text-transform:uppercase;letter-spacing:.5px;">LABEL</div>
|
||||||
|
<div style="font-size:20px;font-weight:700;color:#111827;margin-top:2px;">VALUE</div>
|
||||||
|
</td>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Info/Detail Block
|
||||||
|
```html
|
||||||
|
<div style="margin-top:16px;padding:12px 14px;background:#f8fafc;border-radius:6px;border:1px solid #e5e7eb;">
|
||||||
|
<span style="font-size:12px;font-weight:600;color:#374151;text-transform:uppercase;letter-spacing:.5px;">LABEL</span>
|
||||||
|
<span style="margin-left:10px;font-size:13px;color:#374151;">VALUE</span>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Error/Warning Block
|
||||||
|
```html
|
||||||
|
<div style="margin-top:10px;padding:10px 14px;background:#fff1f2;border-left:4px solid #b91c1c;border-radius:4px;">
|
||||||
|
<div style="font-size:11px;font-weight:700;color:#b91c1c;text-transform:uppercase;letter-spacing:.5px;margin-bottom:6px;">⚠ TITLE</div>
|
||||||
|
<pre style="margin:0;font-family:monospace;font-size:12px;color:#7f1d1d;white-space:pre-wrap;">CONTENT</pre>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Monospace Raw Output Block
|
||||||
|
```html
|
||||||
|
<pre style="margin-top:8px;background:#1e293b;color:#e2e8f0;padding:14px;border-radius:6px;font-size:12px;line-height:1.6;overflow-x:auto;white-space:pre;">RAW OUTPUT</pre>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Summary Table Block
|
||||||
|
```html
|
||||||
|
<div style="background:white;border-radius:10px;border:1px solid #e5e7eb;padding:18px 22px;">
|
||||||
|
<div style="font-size:13px;font-weight:700;color:#374151;margin-bottom:12px;text-transform:uppercase;letter-spacing:.5px;">📋 Report Summary</div>
|
||||||
|
<table width="100%" cellspacing="0" cellpadding="0">
|
||||||
|
<tr>
|
||||||
|
<td style="font-size:13px;color:#6b7280;padding-bottom:6px;">LABEL</td>
|
||||||
|
<td style="font-size:13px;color:#111827;font-weight:600;padding-bottom:6px;">VALUE</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Footer Block
|
||||||
|
```html
|
||||||
|
<tr><td style="background:#0f172a;border-radius:0 0 10px 10px;padding:16px 32px;text-align:center;">
|
||||||
|
<span style="font-size:11px;color:#64748b;">SERVICE NAME | HOSTNAME | KingDezigns Infrastructure</span>
|
||||||
|
</td></tr>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## SMTP Configuration (Zoho)
|
||||||
|
- Server: `smtppro.zoho.com`
|
||||||
|
- Port: `465`
|
||||||
|
- Encryption: `tls` / `ssltls`
|
||||||
|
- Auth: `login`
|
||||||
|
- Sender: `rufus.king@kingdezigns.com`
|
||||||
|
- Sender Name: `Home Assistant`
|
||||||
|
- Recipient: `rufus.king@kingdezigns.com`
|
||||||
|
- Credentials: stored in HA `secrets.yaml` as `kd_username` / `kd_password`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Reference Implementation
|
||||||
|
See `nas08_zfs_report.sh` for the full reference implementation of this style.
|
||||||
|
All future email notifications should match this visual language.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# ✔️ End of File
|
||||||
178
firewall_policies.md
Normal file
178
firewall_policies.md
Normal file
|
|
@ -0,0 +1,178 @@
|
||||||
|
# Firewall Policies — KingDezigns Network
|
||||||
|
Last Updated: 2026-05-24
|
||||||
|
|
||||||
|
This document contains the **complete firewall policy set** for all VLANs in the KingDezigns network.
|
||||||
|
Rules are grouped by VLAN and presented in a clean, AI‑friendly table format.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🌐 Global Firewall Rules (Affect All VLANs)
|
||||||
|
|
||||||
|
| Rule ID | Name | Action | Protocol | Source | Destination | Port | Notes |
|
||||||
|
|--------|-------|---------|----------|---------|--------------|--------|--------|
|
||||||
|
| 20000 | Allow Established / Related | Accept | All | Any | Any | Any | Required for normal TCP/UDP flows |
|
||||||
|
| 20001 | DNS → Pi‑hole | Accept | TCP/UDP | All VLANs | Pi‑hole (192.168.150.35) | 53 | All VLANs use Pi‑hole DNS |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🌍 External Access Architecture
|
||||||
|
|
||||||
|
All inbound internet traffic enters the network through a single ingress point:
|
||||||
|
|
||||||
|
```
|
||||||
|
Internet → NPM on HAS (192.168.150.30:80/443) → Backend Services (NAS08/NAS16)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Nginx Proxy Manager (NPM)** runs as a Home Assistant add-on on HAS and terminates all external HTTPS connections.
|
||||||
|
It forwards requests to backend servers inside VLAN 50 using internal IPs.
|
||||||
|
|
||||||
|
Because all proxied traffic originates from HAS (192.168.150.30), backend servers are configured to extract real client IPs from the `X-Forwarded-For` header:
|
||||||
|
|
||||||
|
- **nginx on NAS16** — `/etc/nginx/conf.d/real_ip.conf` sets `set_real_ip_from 192.168.150.30`
|
||||||
|
- **Apache on NAS16** — `/etc/apache2/conf-available/real_ip.conf` sets `RemoteIPTrustedProxy 192.168.150.30`
|
||||||
|
- **Fail2Ban on NAS16** — `ignoreip` includes `192.168.150.0/24` to prevent HAS from being banned
|
||||||
|
|
||||||
|
This ensures real attacker IPs are logged and banned, not the proxy IP.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🔧 VLAN 1 — Infrastructure (192.168.100.0/24)
|
||||||
|
|
||||||
|
## Inbound Rules
|
||||||
|
| Rule ID | Action | Source | Destination | Notes |
|
||||||
|
|--------|---------|---------|--------------|--------|
|
||||||
|
| 20008 | Drop | VLAN 30 (IoT) | VLAN 1 | IoT cannot reach Infrastructure |
|
||||||
|
| 20009 | Drop | VLAN 50 (Lab) | VLAN 1 | Lab cannot reach Infrastructure |
|
||||||
|
|
||||||
|
## Outbound Rules
|
||||||
|
Outbound access for VLAN 1 is handled by UCG Max auto-generated rules (60000-series), allowing Infrastructure to reach all internal VLANs.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🔧 VLAN 10 — Management (192.168.110.0/24)
|
||||||
|
|
||||||
|
## Inbound Rules
|
||||||
|
| Rule ID | Action | Source | Destination | Notes |
|
||||||
|
|--------|---------|---------|--------------|--------|
|
||||||
|
| 20002 | Accept | VLAN 10 | All VLANs | Management can reach all internal VLANs |
|
||||||
|
| 20003 | Accept | VLAN 20 | VLAN 10 | Trusted → All VLANs Except Trusted |
|
||||||
|
|
||||||
|
## Outbound Rules
|
||||||
|
*(No explicit outbound rules — UCG Max 60000-series and default policy applies.)*
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🔧 VLAN 20 — Trusted Devices (192.168.120.0/24)
|
||||||
|
|
||||||
|
## Inbound Rules
|
||||||
|
| Rule ID | Action | Source | Destination | Notes |
|
||||||
|
|--------|---------|---------|--------------|--------|
|
||||||
|
| 20007 | Drop | VLAN 30 (IoT) | VLAN 20 | IoT cannot reach Trusted |
|
||||||
|
| 20010 | Drop | VLAN 50 (Lab) | VLAN 20 | Lab cannot reach Trusted |
|
||||||
|
|
||||||
|
## Outbound Rules
|
||||||
|
| Rule ID | Action | Source | Destination | Notes |
|
||||||
|
|--------|---------|---------|--------------|--------|
|
||||||
|
| 20003 | Accept | VLAN 20 | All VLANs Except 20 | Trusted can reach all other VLANs |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🔧 VLAN 30 — IoT (192.168.130.0/23)
|
||||||
|
|
||||||
|
## Inbound Rules
|
||||||
|
| Rule ID | Action | Source | Destination | Notes |
|
||||||
|
|--------|---------|---------|--------------|--------|
|
||||||
|
| 20005 | Accept | Home Assistant (192.168.150.30) | VLAN 30 | HA → IoT Control |
|
||||||
|
| 20011 | Drop | VLAN 50 (Lab) | VLAN 30 | Lab cannot reach IoT |
|
||||||
|
|
||||||
|
## Outbound Rules
|
||||||
|
| Rule ID | Action | Source | Destination | Port | Notes |
|
||||||
|
|--------|---------|---------|--------------|--------|--------|
|
||||||
|
| 20004 | Accept | VLAN 30 | 192.168.150.30 | 8123/TCP/UDP | IoT → Home Assistant |
|
||||||
|
| 20006 | Accept | VLAN 30 | 192.168.100.1 | 5540/TCP | IoT → UCG Max Matter controller |
|
||||||
|
| 20007 | Drop | VLAN 30 | VLAN 20 | Any | IoT cannot reach Trusted |
|
||||||
|
| 20008 | Drop | VLAN 30 | VLAN 1 | Any | IoT cannot reach Infrastructure |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🔧 VLAN 40 — Guest (192.168.140.0/24)
|
||||||
|
|
||||||
|
## Inbound Rules
|
||||||
|
| Rule ID | Action | Source | Destination | Notes |
|
||||||
|
|--------|---------|---------|--------------|--------|
|
||||||
|
| 20012 | Drop | VLAN 50 (Lab) | VLAN 40 | Lab cannot reach Guest |
|
||||||
|
|
||||||
|
## Outbound Rules
|
||||||
|
*(No explicit outbound rules — default policy applies.)*
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🔧 VLAN 50 — Lab / Servers (192.168.150.0/24)
|
||||||
|
|
||||||
|
## Inbound Rules
|
||||||
|
| Rule ID | Action | Source | Destination | Notes |
|
||||||
|
|--------|---------|---------|--------------|--------|
|
||||||
|
| 20004 | Accept | VLAN 30 | 192.168.150.30 | IoT → Home Assistant (port 8123) |
|
||||||
|
|
||||||
|
## Outbound Rules
|
||||||
|
| Rule ID | Action | Source | Destination | Notes |
|
||||||
|
|--------|---------|---------|--------------|--------|
|
||||||
|
| 20009 | Drop | VLAN 50 | VLAN 1 | Lab cannot reach Infrastructure |
|
||||||
|
| 20010 | Drop | VLAN 50 | VLAN 20 | Lab cannot reach Trusted |
|
||||||
|
| 20011 | Drop | VLAN 50 | VLAN 30 | Lab cannot reach IoT (except HA exception below) |
|
||||||
|
| 20012 | Drop | VLAN 50 | VLAN 40 | Lab cannot reach Guest |
|
||||||
|
| 20013 | Drop | VLAN 50 | All VLANs Except 50 | Global Final Drop |
|
||||||
|
|
||||||
|
## VLAN 50 Exceptions
|
||||||
|
| Rule ID | Action | Source | Destination | Port | Notes |
|
||||||
|
|--------|---------|---------|--------------|--------|--------|
|
||||||
|
| 20005 | Accept | 192.168.150.30 (HAS) | VLAN 30 | Any | Home Assistant → IoT control |
|
||||||
|
| — | Accept | 192.168.150.30 (NPM) | 192.168.150.35 | Various | NPM proxy → NAS08 services |
|
||||||
|
| — | Accept | 192.168.150.30 (NPM) | 192.168.150.40 | Various | NPM proxy → NAS16 services |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🔧 UCG Max Auto-Generated Rules (60000-series)
|
||||||
|
|
||||||
|
These rules are automatically created by the UCG Max when networks are provisioned.
|
||||||
|
They allow intra-VLAN and general outbound traffic per subnet. Rule order places these after all 20000-series rules.
|
||||||
|
|
||||||
|
| Rule ID | Direction | Action | Source | Destination | Notes |
|
||||||
|
|--------|-----------|--------|--------|-------------|-------|
|
||||||
|
| 60001 | LAN In | Accept | 192.168.120.0/24 | Any | VLAN 20 inbound traffic |
|
||||||
|
| 60002 | LAN In | Accept | 192.168.130.0/23 | Any | VLAN 30 inbound traffic |
|
||||||
|
| 60003 | LAN In | Accept | 192.168.150.0/24 | Any | VLAN 50 inbound traffic |
|
||||||
|
| 60004 | LAN In | Accept | 192.168.100.0/24 | Any | VLAN 1 inbound traffic |
|
||||||
|
| 60005 | LAN In | Accept | 192.168.110.0/24 | Any | VLAN 10 inbound traffic |
|
||||||
|
| 60001 | LAN Out | Accept | Any | 192.168.120.0/24 | VLAN 20 outbound traffic |
|
||||||
|
| 60002 | LAN Out | Accept | Any | 192.168.130.0/23 | VLAN 30 outbound traffic |
|
||||||
|
| 60003 | LAN Out | Accept | Any | 192.168.150.0/24 | VLAN 50 outbound traffic |
|
||||||
|
| 60004 | LAN Out | Accept | Any | 192.168.100.0/24 | VLAN 1 outbound traffic |
|
||||||
|
| 60005 | LAN Out | Accept | Any | 192.168.110.0/24 | VLAN 10 outbound traffic |
|
||||||
|
|
||||||
|
> Note: 20000-series rules execute first. The 60000-series rules handle remaining traffic including VLAN 1 (Infrastructure) outbound access to all VLANs.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🧠 Summary for AI Systems
|
||||||
|
|
||||||
|
- All VLANs → Pi‑hole DNS allowed
|
||||||
|
- All VLANs → Established/Related allowed
|
||||||
|
- VLAN 1 outbound access to all VLANs handled by UCG Max 60000-series rules
|
||||||
|
- VLAN 10 (Management) can reach all VLANs (Rule 20002)
|
||||||
|
- VLAN 20 can reach all VLANs except itself
|
||||||
|
- VLAN 30 can only reach Home Assistant (8123), UCG Max Matter controller (5540), and DNS
|
||||||
|
- VLAN 30 client isolation was previously enabled — removed to allow Matter/Thread device pairing
|
||||||
|
- VLAN 40 is isolated except for DNS
|
||||||
|
- VLAN 50 cannot initiate to any VLAN except IoT (HA exception) and intra-VLAN 50 traffic
|
||||||
|
- External internet traffic enters exclusively via NPM on HAS (192.168.150.30)
|
||||||
|
- Real client IPs are forwarded via X-Forwarded-For from NPM to all backend servers
|
||||||
|
- Fail2Ban on NAS16 ignores 192.168.150.0/24 to prevent proxy IP banning
|
||||||
|
- Matter/Thread pairing requires IoT → UCG Max (192.168.100.1:5540/TCP) — Rule 20006
|
||||||
|
- Aqara M100 Thread Border Router has static IP reservation at 192.168.130.30 (VLAN 30)
|
||||||
|
|
||||||
|
This file is the **single source of truth** for firewall logic.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# ✔️ End of File
|
||||||
198
network_index.md
Normal file
198
network_index.md
Normal file
|
|
@ -0,0 +1,198 @@
|
||||||
|
# KingDezigns Network Documentation Index
|
||||||
|
Last Updated: 2026-07-25
|
||||||
|
|
||||||
|
This index provides a structured overview of all VLANs, servers, and firewall policies in the KingDezigns network.
|
||||||
|
Each section links to its own dedicated Markdown file for clarity and modularity.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 📁 VLAN Documentation
|
||||||
|
|
||||||
|
## 🔧 Core VLANs
|
||||||
|
- [VLAN 1 — Infrastructure](vlan1_infrastructure.md)
|
||||||
|
- [VLAN 10 — Management](vlan10_management.md)
|
||||||
|
|
||||||
|
## 🧑💻 Trusted User VLANs
|
||||||
|
- [VLAN 20 — Trusted Devices](vlan20_trusted.md)
|
||||||
|
|
||||||
|
## 🏠 Smart Home & Guest VLANs
|
||||||
|
- [VLAN 30 — IoT](vlan30_iot.md)
|
||||||
|
- [VLAN 40 — Guest](vlan40_guest.md)
|
||||||
|
|
||||||
|
## 🧪 Server & Lab VLAN
|
||||||
|
- [VLAN 50 — Lab / Servers](vlan50_lab.md)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🖥️ Server Documentation
|
||||||
|
|
||||||
|
## Core Services
|
||||||
|
- [Home Assistant Server](server_homeassistant.md)
|
||||||
|
- [NAS08 — Pi-hole, Nextcloud (+ ONLYOFFICE/Collabora), Vaultwarden, STOCKPROXY](server_nas08.md)
|
||||||
|
- [NAS16 — LAMP Stack, MariaDB, Webmin](server_nas16.md)
|
||||||
|
- [PLEX32 — Plex Media Server + Tautulli](server_plex32.md)
|
||||||
|
|
||||||
|
## Network Hardware
|
||||||
|
- [UCG Gateway Max](server_ucg.md)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🔥 Firewall Policies
|
||||||
|
|
||||||
|
- [Firewall Policies Overview](firewall_policies.md)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🛡️ Security Stack
|
||||||
|
|
||||||
|
## Intrusion Prevention
|
||||||
|
- **CrowdSec** — installed on HAS as a native HA add-on
|
||||||
|
- Agent reads NPM, HA, and SSH logs via journald
|
||||||
|
- 60 active detection scenarios
|
||||||
|
- Community blocklist updates every 2 hours
|
||||||
|
- Firewall Bouncer enforces bans at nftables level
|
||||||
|
- Email alerts on every ban decision
|
||||||
|
- All LAN VLANs whitelisted — internal IPs can never be banned
|
||||||
|
- See [Home Assistant Server](server_homeassistant.md) for full configuration details
|
||||||
|
|
||||||
|
## Perimeter Defense (per server)
|
||||||
|
- **Fail2Ban** — NAS16 (active), PLEX32 (active), NAS08 (recommended)
|
||||||
|
- `ignoreip` includes `192.168.150.0/24` to prevent HAS proxy IP from being banned
|
||||||
|
- Real IP forwarding configured on NAS16 (nginx + Apache) and NAS08
|
||||||
|
|
||||||
|
## DNS-level Protection
|
||||||
|
- **Pi-hole** — NAS08 (192.168.150.35)
|
||||||
|
- Blocks ads, trackers, and malicious domains for all VLANs
|
||||||
|
- All VLANs forced to use Pi-hole via global firewall rule 20001
|
||||||
|
- **Local DNS overrides required** for any internally-hosted service accessed by its public hostname from within the LAN (e.g. `cloud.kingdezigns.com` → `192.168.150.30`), to avoid NAT hairpin failures. See `server_nas08.md` ONLYOFFICE section for a documented example and fix.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🌐 Network Architecture Overview
|
||||||
|
|
||||||
|
This documentation set is designed around:
|
||||||
|
|
||||||
|
- Clear segmentation
|
||||||
|
- Explicit inter-VLAN access
|
||||||
|
- Isolation of untrusted devices
|
||||||
|
- Preservation of Home Assistant functionality
|
||||||
|
- AI-friendly structure and formatting
|
||||||
|
- Layered security — DNS filtering, intrusion prevention, firewall enforcement
|
||||||
|
|
||||||
|
## Security Layer Model
|
||||||
|
```
|
||||||
|
Internet
|
||||||
|
↓
|
||||||
|
UCG Max — firewall, VLAN segmentation, geo-blocking (future)
|
||||||
|
↓
|
||||||
|
CrowdSec Firewall Bouncer — nftables ban enforcement
|
||||||
|
↓
|
||||||
|
NPM on HAS — single ingress, SSL termination
|
||||||
|
↓
|
||||||
|
CrowdSec Agent — log analysis, attack detection
|
||||||
|
↓
|
||||||
|
Backend Services (NAS08, NAS16, PLEX32)
|
||||||
|
↓
|
||||||
|
Fail2Ban — last-line brute force protection
|
||||||
|
↑
|
||||||
|
Pi-hole — DNS-level ad/tracker/malware blocking (all VLANs)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🔑 SSH Key Authentication Map
|
||||||
|
|
||||||
|
SSH key authentication is configured between the following machines — no passwords required:
|
||||||
|
|
||||||
|
| From | To | Purpose |
|
||||||
|
|------|----|---------|
|
||||||
|
| KingDezigns001 | PLEX32 (192.168.150.45) | Remote launcher script |
|
||||||
|
| KingDezigns001 | NAS08 (192.168.150.35) | Direct SSH access |
|
||||||
|
| KingDezigns001 | NAS16 (192.168.150.40) | Direct SSH access |
|
||||||
|
| PLEX32 | NAS08 (192.168.150.35) | Backup script disk stats via SSH |
|
||||||
|
|
||||||
|
Key type: ED25519. Keys generated per machine — not shared.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🖥️ KingDezigns001 — Admin Workstation Tools
|
||||||
|
|
||||||
|
KingDezigns001 is the primary Linux administrative workstation on VLAN 20 (Trusted).
|
||||||
|
|
||||||
|
## Remote Launcher
|
||||||
|
A menu-driven launcher script provides one-click access to run scripts on PLEX32:
|
||||||
|
|
||||||
|
- **Script:** `~/scripts/plex32_launcher.sh`
|
||||||
|
- **Desktop shortcut:** `~/Desktop/PLEX32-Launcher.desktop`
|
||||||
|
- **Terminal:** gnome-terminal
|
||||||
|
|
||||||
|
### Menu Options
|
||||||
|
| Option | Runs on | Script |
|
||||||
|
|--------|---------|--------|
|
||||||
|
| 1) Update Check | PLEX32 | `/usr/scripts/plex32/plex32_update_check.sh` |
|
||||||
|
| 2) Health Report | PLEX32 | `/usr/scripts/plex32/plex32_health_report.sh` |
|
||||||
|
| 3) Plex32 Backup | PLEX32 | `/usr/scripts/plex32/plex32_backup.sh` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🧠 Notes for AI Systems
|
||||||
|
|
||||||
|
- Each file is self-contained and structured consistently.
|
||||||
|
- Section headers follow a predictable pattern for easy parsing.
|
||||||
|
- No duplicated firewall rules — all rules live in `firewall_policies.md`.
|
||||||
|
- CrowdSec configuration lives entirely on HAS — see `server_homeassistant.md`.
|
||||||
|
- VLAN files contain:
|
||||||
|
- Purpose
|
||||||
|
- Access types
|
||||||
|
- Subnet
|
||||||
|
- Expected devices
|
||||||
|
- Security rules
|
||||||
|
- AI summary
|
||||||
|
- Plex Media Server migrated from NAS08 to PLEX32 (dedicated Dell Wyse 5070) on 2026-06-18 — see `server_plex32.md`.
|
||||||
|
- PLEX32 now runs Plex + Tautulli with Intel Quick Sync hardware transcoding — optimized 2026-06-20.
|
||||||
|
- KingDezigns001 has SSH keys to all VLAN 50 servers — passwordless access for all admin tasks.
|
||||||
|
- PLEX32 has SSH key to NAS08 — required for backup script to fetch disk stats.
|
||||||
|
- **NAS08 Nextcloud update check** runs daily at 7AM — `/usr/scripts/omv/nextcloud_update_check.sh` — emails HTML report with copy-paste `occ` commands. Never use the browser UI for Nextcloud app updates (causes Apache segfault → maintenance mode deadlock).
|
||||||
|
- **NAS08 Nextcloud update check — core-update false negative fixed (2026-07-25):** the script previously checked app updates only (`occ app:update`) and had no code path for Nextcloud core/server releases, so it silently missed a core update (34.0.1 → 34.0.2) and emailed a false "up to date" report. Fixed by adding a core check via `occ update:check`, correcting the emailed Compose commands to the real path (`/kingdezignsnas/Docker/Compose/nextcloud/`, root-only, non-default filenames requiring `-f nextcloud.yml -f compose.override.yml`), and fixing a bash quoting bug that made emailed multi-line commands unreadable. Also documented: the official Nextcloud Docker image auto-upgrades on container restart via its own entrypoint — checking version status immediately after `up -d` can race that process and show a stale version for ~30 seconds. Full detail in `server_nas08.md`.
|
||||||
|
- **NAS08 Nextcloud Office editing** uses ONLYOFFICE Document Server (free Community Edition) as of 2026-07-18. Only one Office integration app should ever be enabled at a time (exception: the Collabora trial below, run as a time-boxed disable/enable swap, never simultaneous). Requires a Pi-hole local DNS override for `cloud.kingdezigns.com`, `ALLOW_PRIVATE_IP_ADDRESS=true` on the container, and matching JWT secrets between Nextcloud and the container. Full details and troubleshooting history in `server_nas08.md`.
|
||||||
|
- **NAS08 Collabora Online trial (2026-07-21, ongoing):** A second Office editor, Collabora Online (CODE), was deployed as a standalone Docker container (`collabora`, its own OMV Compose project "Collabora Office") for a head-to-head reliability trial against ONLYOFFICE — triggered by confirmed ONLYOFFICE bugs (conditional formatting crashing on formula cells; silent reverts to hours-old document versions). Only one Office app is ever enabled in Nextcloud at a time — currently `richdocuments`/Collabora is enabled, `onlyoffice` is disabled but still installed for easy rollback. Public URL `https://collabora.kingdezigns.com/`, requires its own Pi-hole local DNS override and a WOPI allow-list (`192.168.150.35`). First real-document test succeeded with a notably fast load time. Full config, setup troubleshooting, and rollback steps in `server_nas08.md`.
|
||||||
|
- **NAS08 Collabora stock/fund price macro integration (2026-07-22, working):** The ONLYOFFICE `FUNDPRICE`/`FUNDPRICE_HIST`/`STOCKPRICE`/`STOCKTIME` custom functions were ported to Collabora as a LibreOffice Basic module (`StockFunctions.bas`), calling the same STOCKPROXY backend with no backend changes required. Two `coolwsd.xml` server-config changes were required — macro execution enabling and a `net.lok_allow` hostname allowlist entry for `stocks.kingdezigns.com` — plus a fix to the previously non-functional `stocks.kingdezigns.com` Pi-hole DNS override. Confirmed working with a live price pull as of 2026-07-22. Full troubleshooting detail, exact config edits, and remaining follow-up items (recreating the full ~50-fund table, conditional-formatting re-test, recalc performance) in `server_nas08.md`.
|
||||||
|
- **NAS08 systemd-resolved DNS bug** (fixed 2026-07-18): a stray global `DNS=` override in `/etc/systemd/resolved.conf` caused duplicate/incorrect DNS answers for internal hostnames network-wide on that host. Any future "works from browser but fails from a container/script on NAS08" symptom should check `resolvectl status` for stray global DNS servers first.
|
||||||
|
- **NAS08 STOCKPROXY service (2026-07-21):** Self-hosted Flask API, Docker container `stockproxy` (`~/docker/stockproxy/`), port 5005, public URL `https://stocks.kingdezigns.com/` proxied via NPM on HAS (see Proxy Hosts table in `server_homeassistant.md`). Supplies current + historical mutual fund prices to ONLYOFFICE custom functions (`FUNDPRICE`, `FUNDPRICE_HIST`) via Yahoo Finance, scraped server-side to dodge the browser CORS block that rules out calling Yahoo directly from a spreadsheet macro. Finnhub was evaluated first but dropped from this service — confirmed no mutual fund NAV coverage on the free tier. Current-price cache: 15 min in-memory. Historical-price cache: permanent, SQLite. All endpoints require a shared-secret `key` param (Vaultwarden). Built to support the "HSA Investiments Choices" tab in `Rufus Retirement Account Tracking 2026.xlsx`. `stocks.kingdezigns.com` A record added to the daily Dreamhost DDNS refresh script. Full config and known limitations in `server_nas08.md`.
|
||||||
|
- **NAS08 RANK.EQ Err:522 circular reference fix (2026-07-23, working):** The
|
||||||
|
"HSA Investiments Choices" fund-ranking formula broke with a circular-reference error on
|
||||||
|
any sheet edit (worked fine on load) because it depended on ~50 cells fed by live
|
||||||
|
`FUNDPRICE`/`FUNDPRICE_HIST` network calls. Fixed with a button-triggered LibreOffice
|
||||||
|
Basic macro that snapshots the live price columns into static value-only columns via
|
||||||
|
`setDataArray()`, with percent-change and rank formulas rebuilt to read from the static
|
||||||
|
snapshot instead of the live columns. Full root-cause analysis and macro in
|
||||||
|
`server_nas08.md`.
|
||||||
|
- **NAS08 Collabora Finnhub removal (2026-07-23, working):** `STOCKPRICE`/`STOCKTIME`
|
||||||
|
(Finnhub-backed equity functions) errored due to a missing `net.lok_allow` entry for
|
||||||
|
Finnhub. Instead of allowlisting Finnhub, it was removed entirely — `FUNDPRICE` (STOCKPROXY)
|
||||||
|
now covers equity tickers too, and a new `FUNDTIME` function replaces `STOCKTIME`, returning
|
||||||
|
STOCKPROXY's `resolved_date` (date only, not a time-of-day timestamp — accepted tradeoff).
|
||||||
|
No `coolwsd.xml` changes required. Full detail in `server_nas08.md`.
|
||||||
|
- **Synaplan AI integration** (added 2026-07-18, not yet functional): Nextcloud connector app installed, but the required self-hosted Synaplan backend stack (PHP/MariaDB/Qdrant/optional Ollama) has not been deployed. Treat as a future project, not a bug — see `server_nas08.md` for details before troubleshooting.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 📌 Future Expansion
|
||||||
|
|
||||||
|
Additional files may be added for:
|
||||||
|
|
||||||
|
- Device inventories
|
||||||
|
- Application-specific firewall rules
|
||||||
|
- Backup and recovery procedures
|
||||||
|
- Monitoring and alerting configuration
|
||||||
|
- CrowdSec Console dashboard enrollment
|
||||||
|
- Geo-blocking configuration on UCG Max
|
||||||
|
- Authelia / forward authentication layer
|
||||||
|
- Expand remote launcher to cover NAS08 and NAS16 scripts
|
||||||
|
- **Synaplan self-hosted AI stack deployment** (PHP backend, MariaDB, Qdrant, optional Ollama) — scope resource requirements and deployment plan when ready
|
||||||
|
- **Collabora vs. ONLYOFFICE trial decision** (started 2026-07-21) — once a winner is chosen, update `server_nas08.md` and this index to reflect the final state (remove trial framing, decommission or keep the losing container, update firewall/NPM docs if the losing editor's proxy host is removed)
|
||||||
|
- **STOCKPROXY hardening** — not yet stress-tested at full ~50-ticker scale for Yahoo-side rate limiting; revisit if widespread simultaneous lookup failures are observed
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# ✔️ End of Index
|
||||||
153
onlyoffice_stock_tracking.md
Normal file
153
onlyoffice_stock_tracking.md
Normal file
|
|
@ -0,0 +1,153 @@
|
||||||
|
# ONLYOFFICE Stock/Fund Tracking — "Rufus Retirement Account Tracking 2026.xlsx"
|
||||||
|
|
||||||
|
Last Updated: 2026-07-21
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧩 Overview
|
||||||
|
This workbook tracks live and historical prices for ~50 mutual funds (HSA investment
|
||||||
|
choices) plus a smaller set of regular equities (Dashboard tab), replacing a prior Google
|
||||||
|
Sheets `GOOGLEFINANCE()`-based workflow. Since ONLYOFFICE has no equivalent live-data
|
||||||
|
formula, price data is supplied via ONLYOFFICE **custom functions** (JavaScript, run in
|
||||||
|
the browser) — some calling Finnhub directly, some calling the self-hosted STOCKPROXY
|
||||||
|
service (see `server_stockproxy.md`).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📑 Tabs Involved
|
||||||
|
| Tab | Purpose |
|
||||||
|
|---|---|
|
||||||
|
| Dashboard | Regular equities — live price via Finnhub (`STOCKPROXY` not needed) |
|
||||||
|
| HSA Investiments Choices | ~50 mutual funds — current + historical price, ranked by return |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔑 Key Cells — "HSA Investiments Choices" tab
|
||||||
|
| Cell | Contents |
|
||||||
|
|---|---|
|
||||||
|
| `B1` | Prior-year marker date |
|
||||||
|
| `B2` | `=TODAY()` |
|
||||||
|
| `B3` | **Resolved calc/anchor date** — rolling lookback (currently ~11 months back), computed from B1/B2/B4, with manual override via B12 ("Yes"/"No") + B13 |
|
||||||
|
| `B4` | Number of lookback months (currently 11) |
|
||||||
|
| `B12` / `B13` | Manual override toggle + override date (currently unused, set to "No") |
|
||||||
|
|
||||||
|
Wide ticker table: rows for **Rate**, **$ Increase**, **Price** (current), **Price History**
|
||||||
|
(anchor-date price), **Fund**, **Ticker**, **Rating** — cascaded across ~50 columns, one per
|
||||||
|
fund.
|
||||||
|
|
||||||
|
Ranking table (top of sheet): **Rank / $ Increase / Ticker / Fund / Price / Rating**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧮 Custom Functions in Use
|
||||||
|
|
||||||
|
Full code archived separately — see:
|
||||||
|
- `onlyoffice_macro_stockprice_finnhub.js` — `STOCKPRICE(ticker)` / `STOCKTIME(ticker)`
|
||||||
|
- `onlyoffice_macro_fundprice_proxy.js` — `FUNDPRICE(ticker)` / `FUNDPRICE_HIST(ticker, dateStr)`
|
||||||
|
- `onlyoffice_macro_autostart_recalc.js` — delayed full-recalc Autostart macro (partial fix, see Known Issues)
|
||||||
|
|
||||||
|
| Function | Data Source | Used On | Notes |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `STOCKPRICE(ticker)` | Finnhub (direct) | Dashboard | Live quote — equities only, **not** mutual funds |
|
||||||
|
| `STOCKTIME(ticker)` | Finnhub (direct) | Dashboard | Exchange-reported quote timestamp |
|
||||||
|
| `FUNDPRICE(ticker)` | STOCKPROXY `/current` | HSA Investiments Choices | Current mutual fund price |
|
||||||
|
| `FUNDPRICE_HIST(ticker, dateStr)` | STOCKPROXY `/historical` | HSA Investiments Choices | Historical price on/before a date; `dateStr` must be passed as text via `TEXT($B$3,"yyyy-mm-dd")` |
|
||||||
|
|
||||||
|
Both custom function sets require their own placeholder credentials to be filled in
|
||||||
|
(Finnhub API key; STOCKPROXY shared secret) — real values live in Vaultwarden, never
|
||||||
|
committed to these docs in plaintext.
|
||||||
|
|
||||||
|
To recreate: **View → Macros → Custom Functions → +**, paste the relevant file's contents,
|
||||||
|
replace the placeholder credentials, Save.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚠️ Known Issues (status as of last session)
|
||||||
|
|
||||||
|
### 1. `#NAME?` / `#BUSY` on file open — **UNRESOLVED**
|
||||||
|
Custom function cells show errors on open until manually clicked into + Enter pressed.
|
||||||
|
|
||||||
|
- **Tried:** Autostart macro (`onlyoffice_macro_autostart_recalc.js`) forcing
|
||||||
|
`Api.RecalculateAllFormulas()` 3 seconds after open.
|
||||||
|
- **Result:** Only partially effective — a screenshot showed 2 of 34 `Price` cells resolved
|
||||||
|
correctly after the fix, the rest stayed `#NAME?`, while the `Price History` column
|
||||||
|
resolved for all rows. Asymmetry between the two columns not yet explained.
|
||||||
|
- **Next steps if resuming:** confirm exact formula text in a failing cell (rule out typos
|
||||||
|
from copy-paste across 50 columns); investigate what a user-added "Refresh Sheet" button
|
||||||
|
(seen in a screenshot, cause/origin not yet confirmed with user) does — may indicate a
|
||||||
|
separate macro-poke mechanism exists alongside the live formulas; consider longer
|
||||||
|
Autostart delay or investigate whether `#NAME?` is a parse-time error that a value-only
|
||||||
|
recalculation cannot fix (may require literally re-entering formula text, not just
|
||||||
|
recalculating).
|
||||||
|
|
||||||
|
### 2. Ctrl+D fill-down not supported — **CONFIRMED, NOT A BUG**
|
||||||
|
Longstanding ONLYOFFICE feature gap (multiple open feature requests upstream).
|
||||||
|
**Workarounds:** drag the fill handle; copy/paste; or install the community
|
||||||
|
"onlyoffice-fill-down" plugin (github.com/une4s/onlyoffice-fill-down) — not yet installed.
|
||||||
|
|
||||||
|
### 3. Conditional formatting + formula cells crashes ONLYOFFICE — **CONFIRMED KNOWN BUG**
|
||||||
|
Multiple open upstream GitHub issues (including one from May 2026) describe the editor
|
||||||
|
crashing/erroring when applying or editing conditional formatting on cells containing
|
||||||
|
formulas. This is the issue that triggered the Collabora comparison project below.
|
||||||
|
|
||||||
|
### 4. Silent data loss / revert to hours-old version — **CONFIRMED SERIOUS, ONGOING RISK**
|
||||||
|
Long-documented, recurring ONLYOFFICE↔Nextcloud bug class: document silently reverts to an
|
||||||
|
old saved state, sometimes losing hours of work, typically linked to stale browser
|
||||||
|
tabs/sessions or autosave/connectivity edge cases. **Not a one-off — confirmed via multiple
|
||||||
|
upstream bug reports spanning years, including as recently as June 2026.**
|
||||||
|
|
||||||
|
**Mitigations discussed (not all yet implemented):**
|
||||||
|
- Check Nextcloud's file **Versions** tab to recover lost work when this happens
|
||||||
|
- Enable **"Keep intermediate versions when editing" (forcesave)** in the Nextcloud
|
||||||
|
ONLYOFFICE admin settings — creates more frequent real restore points
|
||||||
|
- Always close other tabs/sessions of the same file before editing
|
||||||
|
- Watch for the "all changes saved" indicator before navigating away
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔀 Collabora Online Side-by-Side Comparison — IN PROGRESS
|
||||||
|
|
||||||
|
**Decision:** Rather than pick ONLYOFFICE vs. Collabora based on reputation, run both
|
||||||
|
against the same tracking logic and compare reliability directly. Explicitly **not**
|
||||||
|
a factor: the Nextcloud/ONLYOFFICE corporate/licensing dispute (Euro-Office fork,
|
||||||
|
partnership suspension, March 2026) — user stated reliability is the only criterion.
|
||||||
|
|
||||||
|
**Status: setup not yet started** — next step when resuming is deploying the Collabora
|
||||||
|
Docker container.
|
||||||
|
|
||||||
|
### Roadmap
|
||||||
|
1. Deploy **Collabora Online (CODE)** as a Docker container — recommended on **NAS16**
|
||||||
|
(not NAS08) to avoid resource contention with Nextcloud/ONLYOFFICE/Pi-hole/Vaultwarden/
|
||||||
|
STOCKPROXY already running there.
|
||||||
|
2. Expose via NPM with its own subdomain (e.g. `collabora.kingdezigns.com`), SSL via
|
||||||
|
Let's Encrypt — same pattern as `stocks.kingdezigns.com`.
|
||||||
|
3. Install the Collabora Nextcloud connector app (`richdocuments`) alongside the existing
|
||||||
|
ONLYOFFICE app. **Confirmed both can coexist** — default double-click opens whichever
|
||||||
|
app is set as default; right-click → "Open with" picks the other.
|
||||||
|
4. Make a **separate copy** of the tracking spreadsheet for Collabora — do not share one
|
||||||
|
live file between both rendering engines simultaneously.
|
||||||
|
5. Rebuild `FUNDPRICE`/`FUNDPRICE_HIST` logic as **LibreOffice Basic or Python macros**
|
||||||
|
(Collabora's macro system is entirely different from ONLYOFFICE's JS-based one — full
|
||||||
|
rewrite of the glue code required). **STOCKPROXY itself needs no changes** — it's a
|
||||||
|
plain HTTPS/JSON API, callable identically from either editor.
|
||||||
|
6. Recreate the same conditional formatting that crashes ONLYOFFICE and specifically
|
||||||
|
stress-test that exact scenario on Collabora.
|
||||||
|
7. Also re-test on Collabora: file-open recalculation behavior, and general
|
||||||
|
session/reliability behavior (the data-loss concern above).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧠 Summary for AI Systems
|
||||||
|
- This workbook uses ONLYOFFICE custom functions (not native formulas) to pull live/
|
||||||
|
historical prices, since ONLYOFFICE has no `STOCKHISTORY()`-equivalent.
|
||||||
|
- Two data paths: Finnhub direct (equities, Dashboard tab) and STOCKPROXY (mutual funds,
|
||||||
|
HSA tab) — see `server_stockproxy.md` for the backend service.
|
||||||
|
- Several confirmed ONLYOFFICE reliability issues are actively being weighed against
|
||||||
|
Collabora Online as an alternative — see the Collabora section above for current status.
|
||||||
|
- Real credentials (Finnhub API key, STOCKPROXY shared secret) are never stored in these
|
||||||
|
docs — Vaultwarden is the source of truth, matching the rest of the KingDezigns
|
||||||
|
documentation convention.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# ✔️ End of File
|
||||||
305
server_homeassistant.md
Normal file
305
server_homeassistant.md
Normal file
|
|
@ -0,0 +1,305 @@
|
||||||
|
# Home Assistant Server (HAS)
|
||||||
|
Device Type: **Raspberry Pi 5 — 8GB**
|
||||||
|
Hostname: **homeassistant**
|
||||||
|
IP Address: **192.168.150.30**
|
||||||
|
VLAN: **50 — Lab / Servers**
|
||||||
|
|
||||||
|
Last Updated: 2026-07-21
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧩 Role & Purpose
|
||||||
|
The Home Assistant Server serves **three distinct roles** in the KingDezigns network:
|
||||||
|
|
||||||
|
1. **Central smart‑home automation controller** — manages device integrations, automations, discovery protocols, and orchestrates communication between IoT devices and internal services.
|
||||||
|
|
||||||
|
2. **Network-wide reverse proxy** — runs Nginx Proxy Manager (NPM) as a Home Assistant add-on, acting as the single external entry point for all publicly accessible internal services.
|
||||||
|
|
||||||
|
3. **Network-wide intrusion prevention** — runs CrowdSec and CrowdSec Firewall Bouncer as Home Assistant add-ons, providing real-time threat detection, community-sourced IP blocking, and nftables-level enforcement at the network perimeter.
|
||||||
|
|
||||||
|
This system is the **single point of coordination** for VLAN 30 (IoT), the **single ingress point** for all external web traffic, and the **primary intrusion prevention layer** for the KingDezigns network.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🖥️ Hardware
|
||||||
|
- Raspberry Pi 5 (8GB RAM)
|
||||||
|
- High‑performance microSD or SSD (recommended)
|
||||||
|
- Gigabit Ethernet connection
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🌐 Network Placement
|
||||||
|
- VLAN: **50 — Lab / Servers**
|
||||||
|
- IP: **192.168.150.30**
|
||||||
|
- Access Type: LAN / Cable
|
||||||
|
|
||||||
|
This placement ensures:
|
||||||
|
- Isolation from trusted user devices
|
||||||
|
- Controlled access to IoT devices
|
||||||
|
- Direct access to Pi‑hole DNS
|
||||||
|
- Reduced attack surface
|
||||||
|
- Central proxy position for all VLAN 50 services
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚙️ Primary Functions
|
||||||
|
|
||||||
|
### **Home Automation**
|
||||||
|
- Home Assistant core platform
|
||||||
|
- Automation orchestration
|
||||||
|
- Device discovery
|
||||||
|
- Alarm integrations
|
||||||
|
- IoT control
|
||||||
|
- ESPHome, HomeKit, WiZ, Chromecast, AirPlay, and other integrations
|
||||||
|
|
||||||
|
### **Reverse Proxy (Nginx Proxy Manager)**
|
||||||
|
- **Add-on:** Nginx Proxy Manager (NPM)
|
||||||
|
- **Admin UI:** `http://192.168.150.30:81`
|
||||||
|
- **Function:** Terminates all external HTTPS traffic and proxies to internal services
|
||||||
|
- **SSL:** Let's Encrypt certificates per proxy host
|
||||||
|
- **Real IP forwarding:** Passes `X-Forwarded-For` and `X-Real-IP` headers to all backends
|
||||||
|
|
||||||
|
#### Current Proxy Hosts
|
||||||
|
| Destination | Notes |
|
||||||
|
|---|---|
|
||||||
|
| 192.168.150.40:80 | NAS16 Apache virtual hosts (multiple) |
|
||||||
|
| 192.168.150.40:8080 | NAS16 service |
|
||||||
|
| 192.168.150.40:10000 | Webmin |
|
||||||
|
| 192.168.150.40:3670 | NAS16 service |
|
||||||
|
| 192.168.150.35:8080 | NAS08 service |
|
||||||
|
| 192.168.150.35:8081 | NAS08 service |
|
||||||
|
| 192.168.150.35:8082 | NAS08 service |
|
||||||
|
| 192.168.150.35:8083 | NAS08 service |
|
||||||
|
| 192.168.150.35:3670 | NAS08 service |
|
||||||
|
| 192.168.150.35:32400 | Plex |
|
||||||
|
| 192.168.150.30:8123 | Home Assistant |
|
||||||
|
| 192.168.150.35:5005 | STOCKPROXY (self-hosted stock/fund price API — `stocks.kingdezigns.com`, see `server_nas08.md`) |
|
||||||
|
|
||||||
|
All proxy hosts are publicly accessible and SSL-terminated via Let's Encrypt.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Intrusion Prevention (CrowdSec)**
|
||||||
|
- **Add-on:** CrowdSec (Agent + Local API)
|
||||||
|
- **Add-on:** CrowdSec Firewall Bouncer
|
||||||
|
- **Add-on Repository:** `https://github.com/crowdsecurity/home-assistant-addons`
|
||||||
|
- **LAPI Port:** `8080` — exposed on host network (required for NAS16 notifier access)
|
||||||
|
- **CrowdSec version:** v1.7.8
|
||||||
|
|
||||||
|
#### Architecture
|
||||||
|
```
|
||||||
|
Internet → UCG Max → NPM (192.168.150.30:80/443)
|
||||||
|
↓
|
||||||
|
CrowdSec Firewall Bouncer (nftables)
|
||||||
|
↓
|
||||||
|
CrowdSec Agent (log analysis)
|
||||||
|
↓
|
||||||
|
Backend Services
|
||||||
|
↓
|
||||||
|
NAS16 polls LAPI stream every 5 min
|
||||||
|
→ immediate email (local attacks)
|
||||||
|
→ midnight digest (CAPI cloud bans)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### How It Works
|
||||||
|
- CrowdSec Agent reads logs from NPM, Home Assistant, and SSH via journald
|
||||||
|
- Detected attacks create ban decisions enforced by the Firewall Bouncer at the nftables level
|
||||||
|
- The community blocklist pulls known malicious IPs every 2 hours from the global CrowdSec network
|
||||||
|
- Banned IPs are blocked before traffic ever reaches NPM or backend services
|
||||||
|
- **Email notifications are handled externally by NAS16** — not by CrowdSec's native notification system
|
||||||
|
- Native CrowdSec email notifications are **disabled** in profiles.yaml
|
||||||
|
|
||||||
|
#### Active Collections
|
||||||
|
| Collection | Protects Against |
|
||||||
|
|---|---|
|
||||||
|
| `crowdsecurity/nginx-proxy-manager` | NPM log-based attack detection |
|
||||||
|
| `crowdsecurity/home-assistant` | HA brute force login attempts |
|
||||||
|
| `crowdsecurity/http-cve` | 40+ known CVE exploit attempts |
|
||||||
|
|
||||||
|
#### Active Scenarios (60 total, key ones)
|
||||||
|
- HTTP brute force, probing, path traversal, SQLi, XSS
|
||||||
|
- Bad user agents, crawler detection
|
||||||
|
- WordPress scan, admin interface probing
|
||||||
|
- SSH brute force (slow, fast, time-based)
|
||||||
|
- CVE-2024-9474, CVE-2024-0012, CVE-2023-49103, and many more
|
||||||
|
|
||||||
|
#### Key Configuration Files
|
||||||
|
| File | Path | Purpose |
|
||||||
|
|---|---|---|
|
||||||
|
| Acquisition config | CrowdSec add-on Configuration tab | journalctl sources and labels |
|
||||||
|
| profiles.yaml | `/config/.storage/crowdsec/config/profiles.yaml` | Ban decisions only — notifications disabled |
|
||||||
|
| LAN whitelist | `/config/.storage/crowdsec/config/postoverflows/s01-whitelist/kingdezigns-lan-whitelist.yaml` | Prevents all LAN IPs from being banned |
|
||||||
|
|
||||||
|
#### profiles.yaml (current — notifications disabled)
|
||||||
|
```yaml
|
||||||
|
name: default_ip_remediation
|
||||||
|
filters:
|
||||||
|
- Alert.Remediation == true && Alert.GetScope() == "Ip"
|
||||||
|
decisions:
|
||||||
|
- type: ban
|
||||||
|
duration: 4h
|
||||||
|
on_success: break
|
||||||
|
---
|
||||||
|
name: default_range_remediation
|
||||||
|
filters:
|
||||||
|
- Alert.Remediation == true && Alert.GetScope() == "Range"
|
||||||
|
decisions:
|
||||||
|
- type: ban
|
||||||
|
duration: 4h
|
||||||
|
on_success: break
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Acquisition Configuration
|
||||||
|
```yaml
|
||||||
|
acquisition: |
|
||||||
|
---
|
||||||
|
source: journalctl
|
||||||
|
journalctl_filter:
|
||||||
|
- "--directory=/var/log/journal/"
|
||||||
|
labels:
|
||||||
|
type: syslog
|
||||||
|
---
|
||||||
|
source: journalctl
|
||||||
|
journalctl_filter:
|
||||||
|
- "--directory=/var/log/journal/"
|
||||||
|
- "SYSLOG_IDENTIFIER=addon_a0d7b954_nginxproxymanager"
|
||||||
|
labels:
|
||||||
|
type: nginx-proxy-manager
|
||||||
|
disable_lapi: false
|
||||||
|
collections:
|
||||||
|
- crowdsecurity/home-assistant
|
||||||
|
- crowdsecurity/nginx-proxy-manager
|
||||||
|
- crowdsecurity/http-cve
|
||||||
|
parsers_to_disable:
|
||||||
|
- crowdsecurity/whitelists
|
||||||
|
```
|
||||||
|
|
||||||
|
#### LAN Whitelist — Protected Subnets
|
||||||
|
All internal VLANs are whitelisted at the postoverflow stage — LAN IPs can never be banned:
|
||||||
|
- `192.168.100.0/24` — VLAN 1 Infrastructure
|
||||||
|
- `192.168.110.0/24` — VLAN 10 Management
|
||||||
|
- `192.168.120.0/24` — VLAN 20 Trusted
|
||||||
|
- `192.168.130.0/23` — VLAN 30 IoT
|
||||||
|
- `192.168.140.0/24` — VLAN 40 Guest
|
||||||
|
- `192.168.150.0/24` — VLAN 50 Lab/Servers
|
||||||
|
- `127.0.0.1/8` — localhost
|
||||||
|
- `::1` — IPv6 localhost
|
||||||
|
|
||||||
|
#### Registered Bouncers
|
||||||
|
| Name | Purpose |
|
||||||
|
|---|---|
|
||||||
|
| `firewall-bouncer` | nftables enforcement — do not remove |
|
||||||
|
| `homeassistant-dashboard` | HA dashboard integration — do not remove |
|
||||||
|
| `NAS16-notifier` | NAS16 LAPI polling for external email notifications |
|
||||||
|
|
||||||
|
#### Notifications
|
||||||
|
Native CrowdSec email notifications are **disabled**. All alerting is handled by NAS16:
|
||||||
|
- **Immediate red alert** — sent within 5 minutes of any local `crowdsec` origin detection
|
||||||
|
- **Daily midnight digest** — summary of all CAPI community blocklist bans for the day
|
||||||
|
- See `server_nas16.md` for full notification script details
|
||||||
|
|
||||||
|
#### Important: LAPI Port Exposure
|
||||||
|
Port 8080 must remain exposed on the host network interface for NAS16 to reach the LAPI stream endpoint. This is configured in the CrowdSec add-on Network settings (Show disabled ports → enable 8080/tcp → map to host port 8080).
|
||||||
|
|
||||||
|
#### Important: config.yaml User/Group
|
||||||
|
```yaml
|
||||||
|
# /config/.storage/crowdsec/config/config.yaml
|
||||||
|
user: root
|
||||||
|
group: root
|
||||||
|
```
|
||||||
|
Required even though native notifications are disabled — reverting breaks the add-on.
|
||||||
|
|
||||||
|
#### Useful Commands (run from CrowdSec OPEN WEB UI terminal)
|
||||||
|
```bash
|
||||||
|
cscli decisions list # View active bans
|
||||||
|
cscli decisions add --ip x.x.x.x --duration 4h --reason "manual" # Manual ban
|
||||||
|
cscli decisions delete --ip x.x.x.x # Remove a ban
|
||||||
|
cscli decisions delete --range x.x.x.0/24 # Remove entire range
|
||||||
|
cscli metrics # View parsing and detection metrics
|
||||||
|
cscli bouncers list # Verify bouncers connected
|
||||||
|
cscli parsers list # List active parsers
|
||||||
|
cscli postoverflows list # Verify LAN whitelist active
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔒 Required Firewall Behavior
|
||||||
|
|
||||||
|
### **Inbound to Home Assistant**
|
||||||
|
- IoT → Home Assistant
|
||||||
|
- VLAN 30 → 192.168.150.30:8123 (TCP)
|
||||||
|
- Trusted / Management → Home Assistant
|
||||||
|
- Allowed via VLAN 1 and VLAN 20 inbound rules
|
||||||
|
- External traffic → NPM
|
||||||
|
- Port 80/443 must be forwarded to 192.168.150.30 via UniFi port forwarding
|
||||||
|
|
||||||
|
### **Outbound from Home Assistant**
|
||||||
|
- Home Assistant → IoT
|
||||||
|
- Full TCP/UDP access to VLAN 30 (Rule 20008)
|
||||||
|
- Home Assistant → DNS
|
||||||
|
- Local Pi‑hole (192.168.150.35)
|
||||||
|
- NPM → Internal services
|
||||||
|
- 192.168.150.30 → 192.168.150.35 (NAS08 services)
|
||||||
|
- 192.168.150.30 → 192.168.150.40 (NAS16 services)
|
||||||
|
|
||||||
|
### **Discovery Requirements**
|
||||||
|
- mDNS reflection
|
||||||
|
- Multicast
|
||||||
|
- UDP discovery
|
||||||
|
- IGMP snooping enabled on VLAN 30 & 50
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📡 Required Network Features
|
||||||
|
- **mDNS enabled**
|
||||||
|
- **mDNS reflection across VLANs 1, 20, 30, 50**
|
||||||
|
- **IGMP Snooping enabled** (VLAN 30 & 50)
|
||||||
|
- **Multicast allowed**
|
||||||
|
- **UDP discovery allowed**
|
||||||
|
- **Port forwarding:** External 80/443 → 192.168.150.30 (for NPM)
|
||||||
|
|
||||||
|
These are essential for:
|
||||||
|
- WiZ bulbs
|
||||||
|
- Chromecast
|
||||||
|
- AirPlay
|
||||||
|
- HomeKit
|
||||||
|
- ESPHome
|
||||||
|
- General smart‑device discovery
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚠️ Important Operational Notes
|
||||||
|
- All proxied traffic forwarded to backend servers (NAS08, NAS16) originates from 192.168.150.30.
|
||||||
|
- Backend servers must have real IP forwarding configured to log actual client IPs.
|
||||||
|
- NPM passes `X-Forwarded-For` headers by default — no Advanced tab configuration required per host.
|
||||||
|
- Fail2Ban on backend servers must include 192.168.150.0/24 in `ignoreip` to prevent HAS from being banned due to proxied scanner traffic.
|
||||||
|
- CrowdSec Firewall Bouncer blocks at nftables level — bans are enforced before traffic reaches NPM.
|
||||||
|
- CrowdSec LAPI port 8080 must remain exposed on host network for NAS16 notifier to function.
|
||||||
|
- Native CrowdSec email notifications are disabled — all alerting handled by NAS16 scripts.
|
||||||
|
- The LAN whitelist postoverflow ensures no internal IP can ever be banned — critical for remote VPN recovery.
|
||||||
|
- CrowdSec Watchdog is enabled — it will auto-restart after system reboots.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧠 Summary for AI Systems
|
||||||
|
- HAS = **automation hub + network reverse proxy + intrusion prevention** located in VLAN 50.
|
||||||
|
- Runs Home Assistant core, Nginx Proxy Manager (port 81), CrowdSec Agent + LAPI (port 8080), and CrowdSec Firewall Bouncer.
|
||||||
|
- NPM is the single external ingress point for all internal web services.
|
||||||
|
- CrowdSec is the single intrusion prevention layer — blocks at nftables before NPM.
|
||||||
|
- NPM logs are read via journald using SYSLOG_IDENTIFIER `addon_a0d7b954_nginxproxymanager`.
|
||||||
|
- 60 active detection scenarios covering HTTP attacks, CVEs, brute force, and SSH.
|
||||||
|
- Community blocklist updates every 2 hours from CrowdSec Central API.
|
||||||
|
- **Native CrowdSec email notifications are disabled.** All alerting handled by NAS16 scripts.
|
||||||
|
- LAPI port 8080 is exposed on host network — required for NAS16 notifier polling.
|
||||||
|
- Three registered bouncers: firewall-bouncer, homeassistant-dashboard, NAS16-notifier.
|
||||||
|
- All 6 KingDezigns VLANs are whitelisted — LAN IPs can never be banned.
|
||||||
|
- Must receive TCP 8123 from IoT VLAN 30.
|
||||||
|
- Must be able to initiate TCP/UDP to VLAN 30 for device control.
|
||||||
|
- Must be able to reach NAS08 (192.168.150.35) and NAS16 (192.168.150.40) for proxy forwarding.
|
||||||
|
- Requires multicast, mDNS, and UDP discovery across VLANs.
|
||||||
|
- Uses Pi‑hole in VLAN 50 for DNS.
|
||||||
|
- All proxied traffic to backends appears to originate from 192.168.150.30.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# ✔️ End of File
|
||||||
1018
server_nas08.md
Normal file
1018
server_nas08.md
Normal file
File diff suppressed because it is too large
Load diff
346
server_nas16.md
Normal file
346
server_nas16.md
Normal file
|
|
@ -0,0 +1,346 @@
|
||||||
|
# NAS16 — LAMP Stack & Database Server
|
||||||
|
Device Type: **Raspberry Pi**
|
||||||
|
Hostname: **NAS16**
|
||||||
|
IP Address: **192.168.150.40**
|
||||||
|
VLAN: **50 — Lab / Servers**
|
||||||
|
|
||||||
|
Last Updated: 2026-06-24
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧩 Role & Purpose
|
||||||
|
NAS16 is the **dedicated LAMP stack and database server** for the KingDezigns network.
|
||||||
|
It runs **OpenMediaVault (OMV)** as its base OS, which manages nginx as the web GUI frontend.
|
||||||
|
It provides backend services, web hosting, and database support for internal applications, development environments, and externally accessible virtual host websites.
|
||||||
|
|
||||||
|
In addition to its LAMP role, NAS16 hosts the **CrowdSec external notification system** — a pair of scripts that poll the CrowdSec LAPI on HAS and deliver split email alerts based on ban origin.
|
||||||
|
|
||||||
|
This system is designed for:
|
||||||
|
- Web application hosting (internal and external)
|
||||||
|
- MariaDB database services
|
||||||
|
- Internal development and testing
|
||||||
|
- Lightweight administrative tools (Webmin via OMV)
|
||||||
|
- External virtual host websites proxied through HAS (NPM)
|
||||||
|
- CrowdSec email notification delivery (local attack alerts + CAPI daily digest)
|
||||||
|
|
||||||
|
NAS16 operates entirely within VLAN 50 and benefits from the strict containment rules that prevent lateral movement into trusted networks.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🖥️ Hardware
|
||||||
|
- Raspberry Pi (model unspecified)
|
||||||
|
- SSD storage (see drive inventory below)
|
||||||
|
- Gigabit Ethernet
|
||||||
|
|
||||||
|
### **Drive Inventory**
|
||||||
|
| Device | Model | Capacity | Role |
|
||||||
|
|--------|-------|----------|------|
|
||||||
|
| /dev/sda | Unknown (standard SMART attrs) | ~256GB | OS / system drive |
|
||||||
|
|
||||||
|
> Note: Drive model unconfirmed — uses standard SMART attribute names (Wear_Leveling_Count, Reallocated_Sector_Ct, Current_Pending_Sector, Offline_Uncorrectable). Power_Cycle_Count of 7,079 at 891 power-on hours noted — likely reflects frequent reboots during setup. Monitor over time.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🌐 Network Placement
|
||||||
|
- VLAN: **50 — Lab / Servers**
|
||||||
|
- IP: **192.168.150.40**
|
||||||
|
- Access Type: LAN / Cable
|
||||||
|
|
||||||
|
This placement ensures:
|
||||||
|
- Isolation from trusted user devices
|
||||||
|
- Controlled access to sensitive database services
|
||||||
|
- Local access to Pi‑hole DNS
|
||||||
|
- Reduced attack surface
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📦 Primary Functions
|
||||||
|
|
||||||
|
### **Core Services**
|
||||||
|
- **OpenMediaVault (OMV)** — base OS and NAS management UI
|
||||||
|
- **LAMP Stack**
|
||||||
|
- Linux
|
||||||
|
- Apache (serves internal and external virtual host websites)
|
||||||
|
- MariaDB
|
||||||
|
- PHP
|
||||||
|
- **Webmin** (administrative interface, managed via OMV)
|
||||||
|
|
||||||
|
### **Additional Roles**
|
||||||
|
- Internal web hosting
|
||||||
|
- External virtual host websites (proxied via NPM on HAS)
|
||||||
|
- Database backend for internal applications
|
||||||
|
- Development and testing environment
|
||||||
|
- **CrowdSec external notification system** (see below)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🌍 External Access Architecture
|
||||||
|
|
||||||
|
NAS16 hosts multiple public-facing websites served by Apache.
|
||||||
|
External traffic reaches NAS16 via the following proxy chain:
|
||||||
|
|
||||||
|
```
|
||||||
|
Internet → NPM on HAS (192.168.150.30:80/443) → nginx on NAS16 (OMV frontend) → Apache (virtual hosts)
|
||||||
|
```
|
||||||
|
|
||||||
|
### **Real IP Forwarding**
|
||||||
|
Because all proxied traffic arrives at NAS16 from HAS's IP (192.168.150.30), both nginx and Apache are configured to extract and log the real client IP from the `X-Forwarded-For` header passed by NPM.
|
||||||
|
|
||||||
|
**nginx** — `/etc/nginx/conf.d/real_ip.conf`:
|
||||||
|
```nginx
|
||||||
|
set_real_ip_from 192.168.150.30;
|
||||||
|
real_ip_header X-Forwarded-For;
|
||||||
|
real_ip_recursive on;
|
||||||
|
```
|
||||||
|
|
||||||
|
**Apache** — `/etc/apache2/conf-available/real_ip.conf`:
|
||||||
|
```apache
|
||||||
|
RemoteIPHeader X-Forwarded-For
|
||||||
|
RemoteIPTrustedProxy 192.168.150.30
|
||||||
|
```
|
||||||
|
|
||||||
|
Apache module enabled: `remoteip`
|
||||||
|
Config enabled: `real_ip`
|
||||||
|
|
||||||
|
This ensures Fail2Ban sees and bans real attacker IPs, not HAS's proxy IP.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔔 CrowdSec External Notification System
|
||||||
|
|
||||||
|
NAS16 is the sole email notification handler for CrowdSec. Native CrowdSec notifications are disabled on HAS. NAS16 polls the CrowdSec LAPI stream endpoint and routes decisions by origin.
|
||||||
|
|
||||||
|
### **Why NAS16**
|
||||||
|
- Offloads notification work from HAS (which runs HA, NPM, CrowdSec Agent + Bouncer)
|
||||||
|
- NAS16 has the most headroom of any Pi in the fleet (16GB RAM, consistently underutilized)
|
||||||
|
- Fits cleanly into existing OMV Scheduled Jobs infrastructure
|
||||||
|
|
||||||
|
### **Architecture**
|
||||||
|
```
|
||||||
|
CrowdSec LAPI on HAS (192.168.150.30:8080)
|
||||||
|
↓
|
||||||
|
NAS16 polls /v1/decisions/stream every 5 min
|
||||||
|
↓
|
||||||
|
origin = crowdsec? origin = CAPI?
|
||||||
|
↓ ↓
|
||||||
|
Append to local_pending.json Append to capi_digest.json
|
||||||
|
↓ ↓
|
||||||
|
Every 4 hours: Midnight: send digest
|
||||||
|
send batched digest email + clear log
|
||||||
|
email + clear log
|
||||||
|
```
|
||||||
|
|
||||||
|
### **Scripts**
|
||||||
|
| Script | Path | Purpose |
|
||||||
|
|--------|------|---------|
|
||||||
|
| cs_notifier.sh | `/usr/scripts/crowdsec/cs_notifier.sh` | Polls LAPI stream every 5 min, routes decisions by origin into pending log files (no emails sent) |
|
||||||
|
| cs_local_digest.sh | `/usr/scripts/crowdsec/cs_local_digest.sh` | Reads local_pending.json, sends batched local-attack digest every 4 hours, clears log |
|
||||||
|
| cs_digest.sh | `/usr/scripts/crowdsec/cs_digest.sh` | Reads CAPI digest log, builds summary email, sends at midnight, clears log |
|
||||||
|
|
||||||
|
### **Key Design Details**
|
||||||
|
- Uses `/v1/decisions/stream?startup=true` on first run to initialize cursor silently (no emails for existing decisions)
|
||||||
|
- Uses `/v1/decisions/stream?startup=false` on all subsequent runs — LAPI maintains cursor server-side per API key
|
||||||
|
- First run flag: `/var/log/crowdsec-notifier/stream_initialized.flag`
|
||||||
|
- Local pending log: `/var/log/crowdsec-notifier/local_pending.json` (one JSON decision per line, cleared every 4 hours after digest send)
|
||||||
|
- CAPI digest log: `/var/log/crowdsec-notifier/capi_digest.json` (one JSON decision per line, cleared at midnight after digest send)
|
||||||
|
- Notifier log: `/var/log/crowdsec-notifier/notifier.log`
|
||||||
|
- All email sending uses inline Python with `timeout=15` on SMTP_SSL to prevent hangs
|
||||||
|
- Digest scripts use a single Python call to process all decisions — handles large batches efficiently
|
||||||
|
- **IMPORTANT:** Python heredocs (`python3 << PYEOF`) do NOT read from a preceding pipe — the heredoc itself becomes stdin. Data must be passed as an inline shell variable inside the heredoc (e.g. `snapshot = """$SNAPSHOT"""`), not piped in.
|
||||||
|
|
||||||
|
### **Email Notifications**
|
||||||
|
| Type | Trigger | Style | Content |
|
||||||
|
|------|---------|-------|---------|
|
||||||
|
| Local attack digest | Every 4 hours (cron: `0 0,4,8,12,16,20 * * *`) — skipped if zero bans | Red / CRITICAL | Stat cards (ban count, origin, CAPI today) + table of all banned IPs with scenario, type, duration, scope, detected time, and CTI/WHOIS/AbuseIPDB links |
|
||||||
|
| CAPI daily digest | Midnight cron | Amber / WARNING (or green if zero bans) | Total ban count, top 10 scenarios, first 20 sample IPs |
|
||||||
|
|
||||||
|
> **Note:** Local attack alerting was changed from immediate per-IP emails (one email per ban, dozens-to-hundreds/week) to a 4-hour batched digest to reduce notification volume while preserving full visibility into attack activity.
|
||||||
|
|
||||||
|
### **CrowdSec API Key**
|
||||||
|
- Bouncer name: `NAS16-notifier`
|
||||||
|
- Credentials stored in Vaultwarden under `CrowdSec NAS16-notifier`
|
||||||
|
- LAPI endpoint: `http://192.168.150.30:8080`
|
||||||
|
|
||||||
|
### **LAPI Port Requirement**
|
||||||
|
Port 8080 must be exposed on HAS's host network interface. Configured in the CrowdSec add-on Network settings. If HAS is rebuilt or the add-on is reinstalled, re-enable port 8080 mapping.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🗂️ Shared Permissions — NFS + rsync Backup
|
||||||
|
|
||||||
|
NAS16 receives rsync backups from NAS08 via `nas08_to_nas16_sync.sh` every 2 days. To ensure rsync can write files on the destination without errors, NAS16 uses the same `ncshare` group configuration as NAS08.
|
||||||
|
|
||||||
|
### **Group Configuration**
|
||||||
|
| Item | Value |
|
||||||
|
|------|-------|
|
||||||
|
| Group name | `ncshare` |
|
||||||
|
| GID | `1001` |
|
||||||
|
| Members | `www-data`, `rufusking` |
|
||||||
|
|
||||||
|
> GID **must match NAS08** (1001) — rsync syncs permissions across both systems and they must be consistent.
|
||||||
|
|
||||||
|
Verify with:
|
||||||
|
```bash
|
||||||
|
getent group ncshare
|
||||||
|
```
|
||||||
|
|
||||||
|
### **Directory Permissions**
|
||||||
|
Applied to `/export/kingdezignsnas-16/Public` (and all subdirectories recursively):
|
||||||
|
```bash
|
||||||
|
sudo chown -R www-data:ncshare /export/kingdezignsnas-16/Public
|
||||||
|
sudo chmod -R 2770 /export/kingdezignsnas-16/Public
|
||||||
|
sudo setfacl -R -m g:ncshare:rwx /export/kingdezignsnas-16/Public
|
||||||
|
sudo setfacl -R -d -m g:ncshare:rwx /export/kingdezignsnas-16/Public
|
||||||
|
```
|
||||||
|
|
||||||
|
- `2770` (setgid) ensures new items inherit the `ncshare` group
|
||||||
|
- Default ACLs (`-d`) ensure all new files/folders created by rsync inherit `rwx` for `ncshare`
|
||||||
|
|
||||||
|
> **Note:** You should not need to run these commands manually. The sync script checks and self-corrects destination ownership before every run. These are documented here as reference only.
|
||||||
|
|
||||||
|
### **Backup Script**
|
||||||
|
The sync runs on NAS16 via OMV Scheduled Jobs:
|
||||||
|
```bash
|
||||||
|
/usr/scripts/nas/nas08_to_nas16_sync.sh
|
||||||
|
```
|
||||||
|
- Source: `/mnt/kingdezigns08/Public/` (NAS08 mounted via NFS)
|
||||||
|
- Destination: `/export/kingdezignsnas-16/Public/`
|
||||||
|
- Schedule: Every 2 days at 2:30 AM
|
||||||
|
|
||||||
|
### **rsync Flags — NFS all_squash Compatibility**
|
||||||
|
The sync script uses the following rsync flags to work correctly over NFS `all_squash`:
|
||||||
|
|
||||||
|
```
|
||||||
|
--archive Recursive, preserve symlinks, owner, group, devices
|
||||||
|
--no-perms Skip chmod — NFS all_squash prevents non-owner chmod
|
||||||
|
--omit-dir-times Skip directory utimes — NFS all_squash prevents utimes on dirs not owned by www-data
|
||||||
|
--update Skip files that are newer on destination
|
||||||
|
```
|
||||||
|
|
||||||
|
- **File timestamps are fully preserved** — `--omit-dir-times` only skips directory mtimes, not file mtimes
|
||||||
|
- **Directory timestamps are intentionally skipped** — directory mtimes are not meaningful for backup purposes
|
||||||
|
- **Permissions are not synced** — destination ACLs (`ncshare` group, `2770`) control access instead
|
||||||
|
|
||||||
|
### **Permission Precheck (Automatic)**
|
||||||
|
Before every sync run, the script checks that the destination root is owned by `www-data:ncshare`. If it is not, it automatically runs `chown`, `chmod`, and `setfacl` to correct it before rsync starts. This is logged and flagged in the email report with an amber warning notice if it fires.
|
||||||
|
|
||||||
|
A clean run looks like:
|
||||||
|
```
|
||||||
|
[TIMESTAMP] Destination ownership OK (www-data:ncshare).
|
||||||
|
[TIMESTAMP] ===== NAS08 → NAS16 Sync Started =====
|
||||||
|
[TIMESTAMP] ===== Sync Completed Successfully =====
|
||||||
|
Done — Status: SUCCESS | Transferred: N file(s) | Duration: Xm Xs
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔒 Required Firewall Behavior
|
||||||
|
|
||||||
|
### **Inbound to NAS16**
|
||||||
|
- Allowed from VLAN 1 (Infrastructure)
|
||||||
|
- Allowed from VLAN 20 (Trusted)
|
||||||
|
- Allowed from VLAN 50 (local VLAN)
|
||||||
|
- Proxied external traffic arrives from HAS (192.168.150.30) via NPM
|
||||||
|
- IoT and Guest access depend on default policy
|
||||||
|
- No explicit inbound blocks except those applied to VLAN 50 as a whole
|
||||||
|
|
||||||
|
### **Outbound from NAS16**
|
||||||
|
- Subject to VLAN 50's global final drop:
|
||||||
|
- Cannot initiate to VLANs 1, 10, 20, 30, 40
|
||||||
|
- Allowed exceptions:
|
||||||
|
- DNS responses
|
||||||
|
- Local VLAN 50 traffic (including LAPI calls to HAS at 192.168.150.30:8080)
|
||||||
|
|
||||||
|
### **Critical Requirement**
|
||||||
|
- Must remain reachable from trusted administrative devices for management and database access.
|
||||||
|
- Must remain reachable from HAS (192.168.150.30) for proxied external traffic.
|
||||||
|
- Must be able to reach HAS LAPI at 192.168.150.30:8080 for CrowdSec notification polling.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔐 Security Measures
|
||||||
|
- **Fail2Ban enabled** (via OMV Fail2Ban plugin)
|
||||||
|
- **Fail2Ban ignoreip** includes `192.168.150.0/24` — prevents HAS proxy IP from being banned
|
||||||
|
- **Real IP forwarding** configured in nginx and Apache — ensures real attacker IPs are logged and banned
|
||||||
|
- Webmin access restricted to trusted VLANs
|
||||||
|
- Database ports not exposed outside VLAN 50
|
||||||
|
- VLAN‑level containment prevents lateral movement
|
||||||
|
|
||||||
|
### **Fail2Ban Configuration**
|
||||||
|
`/etc/fail2ban/jail.local`:
|
||||||
|
```ini
|
||||||
|
[DEFAULT]
|
||||||
|
ignoreip = 127.0.0.1/8 ::1 192.168.150.0/24
|
||||||
|
```
|
||||||
|
|
||||||
|
This ensures internal VLAN 50 devices (including HAS) are never banned regardless of proxied traffic volume.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🛠️ SSD Hardening & Maintenance
|
||||||
|
|
||||||
|
### **TRIM**
|
||||||
|
- TRIM support confirmed on all drives (`DISC-GRAN: 4K`, `DISC-MAX: 4G`)
|
||||||
|
- systemd `fstrim.timer` **disabled** — replaced by OMV Scheduled Job
|
||||||
|
- Weekly TRIM script: `/usr/scripts/omv/fstrim-report.sh`
|
||||||
|
- Scheduled: **Wednesday at 1:30 AM** via OMV Scheduled Jobs
|
||||||
|
- Script runs `fstrim -av`, gathers SMART health data, sends HTML email report, saves dated log to `/var/log/fstrim/`
|
||||||
|
- Log retention: 90 days
|
||||||
|
|
||||||
|
### **noatime**
|
||||||
|
- All filesystems mounted with `noatime` — confirmed via `findmnt`
|
||||||
|
- Managed automatically by the `openmediavault-flashmemory` plugin
|
||||||
|
- No manual configuration required
|
||||||
|
|
||||||
|
### **openmediavault-flashmemory Plugin**
|
||||||
|
- Installed and active
|
||||||
|
- Automatically handles: `noatime`, tmpfs for `/var/log` and `/tmp`, swap disabled
|
||||||
|
- Significantly reduces unnecessary SSD write amplification
|
||||||
|
|
||||||
|
### **SMART Monitoring**
|
||||||
|
- Monitored weekly as part of the TRIM report script
|
||||||
|
- Drive uses standard SMART attribute names — no vendor-specific mapping required
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📅 Scheduled Jobs (OMV)
|
||||||
|
|
||||||
|
| Schedule | Script | Tag |
|
||||||
|
|----------|--------|-----|
|
||||||
|
| Every 3 days at 2:00 AM | `/usr/scripts/omv/nas16-backup.sh` | NAS16 Backup |
|
||||||
|
| Every 2 days at 2:30 AM | `bash /usr/scripts/nas/nas08_to_nas16_sync.sh` | NAS Drive Backup |
|
||||||
|
| Daily at 12:00 AM | `/usr/scripts/zfs/nas16_zfs_report.sh` | ZFS Status Report |
|
||||||
|
| Sunday at 3:00 AM | `/usr/scripts/zfs/nas16_zfs_scrub.sh` | ZFS Scrub |
|
||||||
|
| Every 15 minutes | `/usr/scripts/ddns/ddns_update.sh` | DDNS Update |
|
||||||
|
| Wednesday at 1:30 AM | `/usr/scripts/omv/fstrim-report.sh` | TRIM Report |
|
||||||
|
| Every 5 minutes | `/usr/scripts/crowdsec/cs_notifier.sh` | CrowdSec Local Notifier |
|
||||||
|
| Every 4 hours (0:00, 4:00, 8:00, 12:00, 16:00, 20:00) | `/usr/scripts/crowdsec/cs_local_digest.sh` | CrowdSec Local Attack Digest |
|
||||||
|
| Daily at 12:00 AM | `/usr/scripts/crowdsec/cs_digest.sh` | CrowdSec CAPI Digest |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧠 Summary for AI Systems
|
||||||
|
- NAS16 = **OMV-based LAMP + database server + CrowdSec notifier** in VLAN 50.
|
||||||
|
- Inbound allowed from VLAN 1, VLAN 20, local VLAN 50, and HAS proxy (192.168.150.30).
|
||||||
|
- Outbound blocked to all VLANs except local + DNS responses.
|
||||||
|
- Hosts Apache (virtual hosts), MariaDB, PHP, Webmin, and OMV management UI.
|
||||||
|
- External traffic is proxied through NPM on HAS — real IPs forwarded via X-Forwarded-For.
|
||||||
|
- nginx and Apache both configured to log real client IPs, not proxy IP.
|
||||||
|
- Fail2Ban ignoreip covers VLAN 50 to prevent HAS from being banned.
|
||||||
|
- Protected by VLAN 50's strict containment rules.
|
||||||
|
- SSD hardening active: TRIM (weekly Wednesday 1:30AM), noatime (flashmemory plugin), SMART monitoring via weekly HTML email report.
|
||||||
|
- High Power_Cycle_Count (7,079) relative to power-on hours (891) — monitor trend over time.
|
||||||
|
- **Hosts CrowdSec notification scripts** — polls HAS LAPI stream at 192.168.150.30:8080 every 5 minutes.
|
||||||
|
- Local attack decisions are batched and sent as one digest email every 4 hours (skipped if zero bans) — no longer one email per ban.
|
||||||
|
- CAPI cloud ban digest sent daily at midnight — single Python call handles 10,000+ decisions efficiently.
|
||||||
|
- CrowdSec API key stored in Vaultwarden under `CrowdSec NAS16-notifier`.
|
||||||
|
- **Gotcha:** when piping data into `python3 -` with a heredoc, the heredoc replaces stdin — pass data as an inline variable instead.
|
||||||
|
- **Shared permissions:** `ncshare` group (GID 1001) shared by `www-data` and `rufusking` — must match NAS08 GID for rsync compatibility.
|
||||||
|
- Default ACLs on `/export/kingdezignsnas-16/Public` ensure all rsync-written files inherit `ncshare` group permissions.
|
||||||
|
- **NAS08→NAS16 sync script self-heals destination permissions on every run** — checks for `www-data:ncshare` ownership, runs `chown`/`chmod`/`setfacl` automatically if wrong. Flagged in email subject and body if it fires.
|
||||||
|
- Sync script uses `--no-perms` and `--omit-dir-times` for NFS `all_squash` compatibility — all individual file timestamps are fully preserved; only directory timestamps are skipped (intentional, not meaningful for backup).
|
||||||
|
- **Do not manually run chown/chmod/setfacl on the sync destination** — the script handles this automatically.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# ✔️ End of File
|
||||||
468
server_plex32.md
Normal file
468
server_plex32.md
Normal file
|
|
@ -0,0 +1,468 @@
|
||||||
|
# PLEX32 — Plex Media Server
|
||||||
|
Device Type: **Dell Wyse 5070 Thin Client**
|
||||||
|
Hostname: **plex32**
|
||||||
|
IP Address: **192.168.150.45**
|
||||||
|
VLAN: **50 — Lab / Servers**
|
||||||
|
|
||||||
|
Last Updated: 2026-07-12
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧩 Role & Purpose
|
||||||
|
PLEX32 is the **dedicated Plex Media Server** for the KingDezigns network.
|
||||||
|
It replaced Plex on NAS08, migrating the service to a more capable x86 machine that supports advanced Plex Pass features including **Sonic Radio** — an AI-driven music playlist and discovery feature that requires CPU capabilities not available on Raspberry Pi hardware.
|
||||||
|
|
||||||
|
All media files remain stored on NAS08 and are accessed via NFS mounts. PLEX32 handles only transcoding and Plex server logic — it does not store media locally.
|
||||||
|
|
||||||
|
This device is the **single Plex Media Server** for the KingDezigns network and is publicly accessible via `plex.kingdezigns.com` through NPM on HAS.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🖥️ Hardware
|
||||||
|
- Dell Wyse 5070 Thin Client
|
||||||
|
- Intel Celeron J4105 — 1.50GHz (4 cores) — Intel Quick Sync supported
|
||||||
|
- 8GB RAM
|
||||||
|
- 32GB eMMC (OS drive — no SMART support, health monitored via filesystem)
|
||||||
|
- Gigabit Ethernet
|
||||||
|
|
||||||
|
### **Storage**
|
||||||
|
| Device | Type | Capacity | Role |
|
||||||
|
|--------|------|----------|------|
|
||||||
|
| mmcblk0 | eMMC | 29.1GB | OS / system drive |
|
||||||
|
| /mnt/plex/config | NFS (NAS08) | — | Plex config backup destination only — not used by container |
|
||||||
|
| /mnt/plex/transcode | NFS (NAS08) | — | Transcode scratch (local at /opt/plex/transcode) |
|
||||||
|
| /mnt/plex/media | NFS (NAS08) | 1.8TB | Media library |
|
||||||
|
|
||||||
|
> Note: Plex config and transcode directories are stored **locally** at `/opt/plex/` — not on NFS. The NFS config mount (`/mnt/plex/config`) is used as the backup destination by `plex32_backup.sh`. Only the media library is actively used by the container.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🌐 Network Placement
|
||||||
|
- VLAN: **50 — Lab / Servers**
|
||||||
|
- IP: **192.168.150.45**
|
||||||
|
- Access Type: LAN / Cable
|
||||||
|
|
||||||
|
This placement ensures:
|
||||||
|
- Isolation from trusted user devices
|
||||||
|
- Access to NAS08 NFS shares over local VLAN 50
|
||||||
|
- Direct access to Pi‑hole DNS
|
||||||
|
- Reduced attack surface
|
||||||
|
- Accessible via NPM reverse proxy on HAS
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📦 Primary Functions
|
||||||
|
|
||||||
|
### **Core Services**
|
||||||
|
- **Plex Media Server** (Docker — linuxserver/plex:latest)
|
||||||
|
- **Tautulli** (Docker — linuxserver/tautulli:latest) — playback history, monitoring, and alerts
|
||||||
|
|
||||||
|
### **Plex Libraries**
|
||||||
|
| Library | Path in Container | Source on NAS08 |
|
||||||
|
|---------|------------------|-----------------|
|
||||||
|
| Music | /media/03 - Music | /export/kingdezigns-public/03 - Music |
|
||||||
|
| Videos | /media/04 - Videos/Movies | /export/kingdezigns-public/04 - Videos/Movies |
|
||||||
|
| Photos | /media/02 - Photos | /export/kingdezigns-public/02 - Photos |
|
||||||
|
|
||||||
|
### **Plex Pass**
|
||||||
|
- **Lifetime Plex Pass** — confirmed active on this server
|
||||||
|
- Enables: Sonic Radio, hardware transcoding (Intel Quick Sync), mobile sync, offline downloads
|
||||||
|
|
||||||
|
### **Library Codec Profile**
|
||||||
|
| Codec | Count | Notes |
|
||||||
|
|-------|-------|-------|
|
||||||
|
| HEVC Main 10 | ~90 | 10-bit HDR — Direct Streams on Roku, hardware transcode via Quick Sync if needed |
|
||||||
|
| H.264 High | 29 | Direct Play on all clients |
|
||||||
|
| Audio | 119 AAC | 100% AAC — never forces audio transcode |
|
||||||
|
| Subtitles | 1168 SRT + 279 PGS | PGS only burns in if manually selected — Subtitle Mode set to Manually Selected |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🐳 Docker Configuration
|
||||||
|
|
||||||
|
### **Compose File Location**
|
||||||
|
```
|
||||||
|
~/docker/plex/docker-compose.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
### **Compose Contents**
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
plex:
|
||||||
|
image: lscr.io/linuxserver/plex:latest
|
||||||
|
container_name: plex
|
||||||
|
network_mode: host
|
||||||
|
environment:
|
||||||
|
- PUID=1000
|
||||||
|
- PGID=1001
|
||||||
|
- TZ=America/New_York
|
||||||
|
- VERSION=docker
|
||||||
|
devices:
|
||||||
|
- /dev/dri:/dev/dri
|
||||||
|
group_add:
|
||||||
|
- "44"
|
||||||
|
- "993"
|
||||||
|
volumes:
|
||||||
|
- /opt/plex/config:/config
|
||||||
|
- /opt/plex/transcode:/transcode
|
||||||
|
- /mnt/plex/media:/media
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
tautulli:
|
||||||
|
image: lscr.io/linuxserver/tautulli:latest
|
||||||
|
container_name: tautulli
|
||||||
|
environment:
|
||||||
|
- PUID=1000
|
||||||
|
- PGID=1001
|
||||||
|
- TZ=America/New_York
|
||||||
|
volumes:
|
||||||
|
- /opt/tautulli/config:/config
|
||||||
|
ports:
|
||||||
|
- 8181:8181
|
||||||
|
restart: unless-stopped
|
||||||
|
```
|
||||||
|
|
||||||
|
> **devices + group_add:** Required for Intel Quick Sync hardware transcoding. The container needs `/dev/dri` device access plus supplementary group membership for `video` (GID 44) and `render` (GID 993). Without `group_add`, Plex silently falls back to software transcoding even with hardware acceleration enabled in settings.
|
||||||
|
|
||||||
|
### **Key Docker Commands**
|
||||||
|
```bash
|
||||||
|
# Start all services
|
||||||
|
cd ~/docker/plex && docker compose up -d
|
||||||
|
|
||||||
|
# Stop all services
|
||||||
|
cd ~/docker/plex && docker compose down
|
||||||
|
|
||||||
|
# Update Plex
|
||||||
|
cd ~/docker/plex && docker compose pull && docker compose up -d
|
||||||
|
|
||||||
|
# View Plex logs
|
||||||
|
docker logs plex --tail 50
|
||||||
|
|
||||||
|
# View Tautulli logs
|
||||||
|
docker logs tautulli --tail 50
|
||||||
|
|
||||||
|
# Check container status
|
||||||
|
docker ps
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎬 Hardware Transcoding — Intel Quick Sync
|
||||||
|
|
||||||
|
The J4105 supports Intel Quick Sync via `/dev/dri`. Both decode and encode are offloaded to the GPU.
|
||||||
|
|
||||||
|
### **Verification**
|
||||||
|
Check GPU access from inside the container:
|
||||||
|
```bash
|
||||||
|
docker exec -it plex id
|
||||||
|
# Should show groups 44 (video) and 993 (render/group01b4) in output
|
||||||
|
docker exec -it plex ls -la /dev/dri
|
||||||
|
# Should show card0 and renderD128
|
||||||
|
```
|
||||||
|
|
||||||
|
Verify during active transcode — Plex Dashboard should show:
|
||||||
|
```
|
||||||
|
4K (HEVC Main 10) (hw)
|
||||||
|
SD (HEVC) — Transcode (hw)
|
||||||
|
```
|
||||||
|
|
||||||
|
The `(hw)` suffix on both lines confirms Quick Sync is handling decode and encode.
|
||||||
|
|
||||||
|
### **Plex Settings**
|
||||||
|
- Settings → Transcoder → **Use hardware acceleration when available** ✅
|
||||||
|
- Settings → Transcoder → **Use hardware-accelerated video encoding** ✅
|
||||||
|
- Settings → Transcoder → **Transcoder temporary directory:** `/transcode`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 Tautulli
|
||||||
|
|
||||||
|
Tautulli provides playback history, live session monitoring, and email alerts.
|
||||||
|
|
||||||
|
- **Web UI:** `http://192.168.150.45:8181`
|
||||||
|
- **Config:** `/opt/tautulli/config`
|
||||||
|
- **Connected to:** Plex at `192.168.150.45:32400`
|
||||||
|
|
||||||
|
### **Active Notifications**
|
||||||
|
| Trigger | Destination | Purpose |
|
||||||
|
|---------|-------------|---------|
|
||||||
|
| Plex Server Down | rufus.king@kingdezigns.com | Alert when Plex stops responding |
|
||||||
|
| Plex Server Back Up | rufus.king@kingdezigns.com | Confirmation when Plex recovers |
|
||||||
|
|
||||||
|
### **SMTP Configuration**
|
||||||
|
Uses same Zoho SMTP credentials as all other KingDezigns email alerts:
|
||||||
|
- Server: `smtppro.zoho.com` / Port: `465` / TLS enabled
|
||||||
|
- From: `rufus.king@kingdezigns.com`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📁 NFS Mounts
|
||||||
|
|
||||||
|
Configured in `/etc/fstab` — mounts automatically on boot:
|
||||||
|
|
||||||
|
```
|
||||||
|
192.168.150.35:/export/kingdezigns-all/Docker/plex/config /mnt/plex/config nfs defaults,_netdev 0 0
|
||||||
|
192.168.150.35:/export/kingdezigns-all/Docker/plex/transcode /mnt/plex/transcode nfs defaults,_netdev 0 0
|
||||||
|
192.168.150.35:/export/kingdezigns-public /mnt/plex/media nfs defaults,_netdev 0 0
|
||||||
|
```
|
||||||
|
|
||||||
|
> Note: `/mnt/plex/config` is used by `plex32_backup.sh` as the backup destination — not by the Plex container. `/mnt/plex/transcode` exists in fstab but Plex uses the local `/opt/plex/transcode` directory instead.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🌍 External Access
|
||||||
|
|
||||||
|
- **Domain:** `plex.kingdezigns.com`
|
||||||
|
- **Proxy:** NPM on HAS (192.168.150.30) → 192.168.150.45:32400
|
||||||
|
- **SSL:** Let's Encrypt via NPM
|
||||||
|
- **Port:** 32400 (Plex default)
|
||||||
|
- **Port forwarding:** UCG Max forwards external 32400 → 192.168.150.45
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔒 Required Firewall Behavior
|
||||||
|
|
||||||
|
### **Inbound to PLEX32**
|
||||||
|
- Allowed from VLAN 1 (Infrastructure) and VLAN 20 (Trusted) — global rules
|
||||||
|
- Allowed from VLAN 50 (local VLAN)
|
||||||
|
- External Plex traffic arrives via NPM on HAS (192.168.150.30)
|
||||||
|
|
||||||
|
### **Outbound from PLEX32**
|
||||||
|
- Subject to VLAN 50's global final drop
|
||||||
|
- Cannot initiate to VLANs 1, 10, 20, 30, 40
|
||||||
|
- Allowed: local VLAN 50 traffic (NFS to NAS08, DNS to Pi-hole, SSH to NAS08 for backup)
|
||||||
|
|
||||||
|
### **Critical Requirements**
|
||||||
|
- Must reach NAS08 (192.168.150.35) on NFS ports for media library and backup destination
|
||||||
|
- Must be reachable from HAS (192.168.150.30) for proxied external traffic
|
||||||
|
- Port 32400 must be forwarded on UCG Max for direct Plex remote access
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔐 Security Measures
|
||||||
|
- **Fail2Ban enabled** — `ignoreip` includes `127.0.0.1/8`, `::1`, `192.168.150.0/24`
|
||||||
|
- Docker-based service isolation
|
||||||
|
- VLAN-level containment
|
||||||
|
- No outbound access to other VLANs
|
||||||
|
|
||||||
|
### **Fail2Ban Configuration**
|
||||||
|
`/etc/fail2ban/jail.local`:
|
||||||
|
```ini
|
||||||
|
[DEFAULT]
|
||||||
|
ignoreip = 127.0.0.1/8 ::1 192.168.150.0/24
|
||||||
|
```
|
||||||
|
|
||||||
|
### **System Timezone**
|
||||||
|
- Timezone corrected to `America/New_York` on 2026-06-21 — was previously `Etc/UTC`
|
||||||
|
- The UTC default caused cron jobs to fire 4 hours early (e.g. 2 AM UTC = 10 PM EDT)
|
||||||
|
- Always verify timezone after fresh installs: `timedatectl | grep "Time zone"`
|
||||||
|
- Fix: `sudo timedatectl set-timezone America/New_York`
|
||||||
|
|
||||||
|
### **sudo Without Password**
|
||||||
|
`/etc/sudoers.d/rufusking-nopasswd`:
|
||||||
|
```
|
||||||
|
rufusking ALL=(ALL) NOPASSWD: /usr/bin/apt-get update, /usr/bin/fail2ban-client status, /usr/bin/fail2ban-client status sshd, /sbin/reboot
|
||||||
|
```
|
||||||
|
Required by update check script (`apt-get update`), health report script (`fail2ban-client`), and remote reboot script (`reboot`).
|
||||||
|
|
||||||
|
### **SSH Key Authentication**
|
||||||
|
PLEX32 has an SSH key configured to NAS08 — required for the backup script to fetch accurate disk stats without a password prompt:
|
||||||
|
```bash
|
||||||
|
# Key location on PLEX32
|
||||||
|
~/.ssh/id_ed25519
|
||||||
|
|
||||||
|
# Test
|
||||||
|
ssh rufusking@192.168.150.35 "echo NAS08 OK"
|
||||||
|
```
|
||||||
|
|
||||||
|
### **AC Power Recovery (Auto Power-On After Outage)**
|
||||||
|
Configured **2026-06-30** after a power outage left PLEX32 powered off (manual power button press required to bring it back up).
|
||||||
|
|
||||||
|
Dell exposes AC Power Recovery as a writable SMBIOS token — this means it can be set **remotely from within Linux**, without ever entering BIOS setup.
|
||||||
|
|
||||||
|
**Tooling:**
|
||||||
|
```bash
|
||||||
|
sudo apt-get install -y libsmbios-bin smbios-utils
|
||||||
|
```
|
||||||
|
|
||||||
|
**Relevant tokens (mutually exclusive — only one should be `true`):**
|
||||||
|
| Token | Setting | Desired State |
|
||||||
|
|-------|---------|----------------|
|
||||||
|
| `0x00a1` | AC Power Recovery Mode (Off) — stays off | `false` |
|
||||||
|
| `0x00a2` | AC Power Recovery Mode (Last) — restores prior state | `false` |
|
||||||
|
| `0x00a3` | AC Power Recovery Mode (On) — powers on automatically | `true` ✅ |
|
||||||
|
|
||||||
|
**Command used to set it:**
|
||||||
|
```bash
|
||||||
|
sudo smbios-token-ctl --activate --token-id=0x00a3
|
||||||
|
```
|
||||||
|
|
||||||
|
**Verify current state:**
|
||||||
|
```bash
|
||||||
|
sudo smbios-token-ctl --dump-tokens | grep -i -A2 "AC Power Recovery"
|
||||||
|
```
|
||||||
|
|
||||||
|
> Note: `smbios-token-ctl --dump-tokens` throws a harmless `StopIteration` traceback after printing all tokens (hits a malformed token entry near the end of the table) — this does not affect the accuracy of the data already printed, including the AC Power Recovery tokens.
|
||||||
|
|
||||||
|
**Result:** PLEX32 will now power back on automatically as soon as AC power is restored after an outage — no physical power button press required. (HAS already had equivalent behavior configured.)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🗂️ Shared Permissions
|
||||||
|
|
||||||
|
PLEX32 uses the same `ncshare` group as NAS08 and NAS16 for consistency across the network.
|
||||||
|
|
||||||
|
| Item | Value |
|
||||||
|
|------|-------|
|
||||||
|
| Group name | `ncshare` |
|
||||||
|
| GID | `1001` |
|
||||||
|
| Members | `rufusking` |
|
||||||
|
|
||||||
|
Verify with:
|
||||||
|
```bash
|
||||||
|
getent group ncshare
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 💾 Config Backup
|
||||||
|
|
||||||
|
Plex and Tautulli configs are backed up to NAS08 every 3 days via `plex32_backup.sh`.
|
||||||
|
|
||||||
|
### **Backup Script**
|
||||||
|
- **Location:** `/usr/scripts/plex32/plex32_backup.sh`
|
||||||
|
- **Method:** tar locally to `/tmp/`, then single `cp` to NFS (rsync avoided — too slow over NFS for Plex's thousands of small metadata files)
|
||||||
|
- **Plex destination (NAS08):** `/export/kingdezigns-all/Docker/plex/config/backups/plex/plex-config-YYYY-MM-DD.tar.gz`
|
||||||
|
- **Tautulli destination (NAS08):** `/export/kingdezigns-all/Docker/plex/config/backups/tautulli/tautulli-config-YYYY-MM-DD.tar.gz`
|
||||||
|
- **Retention:** 3 copies of each, older ones auto-deleted
|
||||||
|
- **Excludes:** Cache, Logs, Crash Reports
|
||||||
|
- **Email:** HTML report sent on completion — SUCCESS / PARTIAL / FAILED
|
||||||
|
- **SMTP password:** `/etc/plex32-smtp-pass` (chmod 600, owned by rufusking)
|
||||||
|
- **Log:** `/var/log/plex32-backup/backup-YYYYMMDD.log` (90 day retention)
|
||||||
|
|
||||||
|
### **Restore Procedure (run on plex32)**
|
||||||
|
```bash
|
||||||
|
# 1. Stop containers
|
||||||
|
cd ~/docker/plex && docker compose down
|
||||||
|
|
||||||
|
# 2. Copy archive from NAS08
|
||||||
|
cp /mnt/plex/config/backups/plex/plex-config-YYYY-MM-DD.tar.gz /tmp/
|
||||||
|
|
||||||
|
# 3. Clear current config
|
||||||
|
sudo rm -rf /opt/plex/config/Library
|
||||||
|
|
||||||
|
# 4. Extract backup
|
||||||
|
sudo tar -xzf /tmp/plex-config-YYYY-MM-DD.tar.gz -C /opt/plex
|
||||||
|
sudo chown -R rufusking:ncshare /opt/plex/config
|
||||||
|
|
||||||
|
# 5. Restart containers
|
||||||
|
cd ~/docker/plex && docker compose up -d
|
||||||
|
|
||||||
|
# 6. Verify
|
||||||
|
docker ps
|
||||||
|
# Both plex and tautulli should show Up
|
||||||
|
# Open http://192.168.150.45:32400/web and confirm library and watch history intact
|
||||||
|
|
||||||
|
# 7. Cleanup
|
||||||
|
rm /tmp/plex-config-YYYY-MM-DD.tar.gz
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🖥️ Remote Launcher (KingDezigns001)
|
||||||
|
|
||||||
|
A launcher script on KingDezigns001 provides a menu-driven interface to run PLEX32 scripts remotely via SSH.
|
||||||
|
|
||||||
|
- **Launcher script:** `~/scripts/plex32_launcher.sh`
|
||||||
|
- **Desktop shortcut:** `~/Desktop/PLEX32-Launcher.desktop`
|
||||||
|
- **SSH:** Passwordless — ED25519 key from KingDezigns001 installed on PLEX32
|
||||||
|
|
||||||
|
### **Menu Options**
|
||||||
|
| Option | Script |
|
||||||
|
|--------|--------|
|
||||||
|
| 1) Update Check | `/usr/scripts/plex32/plex32_update_check.sh` |
|
||||||
|
| 2) Health Report | `/usr/scripts/plex32/plex32_health_report.sh` |
|
||||||
|
| 3) Plex32 Backup | `/usr/scripts/plex32/plex32_backup.sh` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📅 Scheduled Jobs (cron)
|
||||||
|
|
||||||
|
| Schedule | Script | Purpose |
|
||||||
|
|----------|--------|---------|
|
||||||
|
| Daily at 7:00 AM | `/usr/scripts/plex32/plex32_update_check.sh` | Check for OS, Plex, Docker, Fail2Ban updates — email report |
|
||||||
|
| Daily at 7:05 AM | `/usr/scripts/plex32/plex32_health_report.sh` | Server health report — disk, NFS, memory, CPU, container status |
|
||||||
|
| Every 3 days at 2:00 AM | `/usr/scripts/plex32/plex32_backup.sh` | Archive Plex and Tautulli configs to NAS08 — email report |
|
||||||
|
|
||||||
|
View cron jobs:
|
||||||
|
```bash
|
||||||
|
sudo crontab -l
|
||||||
|
```
|
||||||
|
|
||||||
|
> Note: All three PLEX32 scheduled jobs run via **root's crontab**, not `rufusking`'s.
|
||||||
|
|
||||||
|
### **plex32_update_check.sh — Docker Pull Fix (2026-07-12)**
|
||||||
|
The daily update check was intermittently reporting `Plex Media Server = Check failed — could not reach registry` even though `lscr.io` was reachable and disk space was healthy (8.6GB free of 26GB).
|
||||||
|
|
||||||
|
**Root cause:** The script's `docker pull` step runs under root's cron environment, which uses a minimal default `PATH` that didn't reliably match the interactive `rufusking` shell environment. The script also silently discarded the actual `docker pull` error output, so the true failure reason was never visible in the log or email — every failure was mislabeled with the same generic "could not reach registry" text regardless of cause.
|
||||||
|
|
||||||
|
**Fix applied:**
|
||||||
|
- Added an explicit `export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin` at the top of the script so behavior is consistent under cron regardless of invoking user/environment.
|
||||||
|
- The script now logs the full `docker pull` output/exit code to `/var/log/plex32-updates/` on failure, and includes it as a red error block in the email report, instead of showing a generic message.
|
||||||
|
|
||||||
|
Resolved — manual `sudo` run completed cleanly after the fix, and the failure message no longer appears.
|
||||||
|
|
||||||
|
### **plex32_health_report.sh — Issues List Word-Wrapping Fix (2026-07-12)**
|
||||||
|
The "⚠ Issues Detected" block in the daily health report email was rendering each word of an issue message on its own line (e.g. "WARNING: NAS08 — Plex Config is getting full" appeared as one word per line) instead of as a single readable sentence.
|
||||||
|
|
||||||
|
**Root cause:** The script joined multiple issue messages into one string and then split them back apart using `IFS='. ' read -ra ISSUE_LIST`. This does not split on the two-character sequence `". "` as intended — `IFS` treats every character it contains as its own independent delimiter, so both `.` and every space in the text were treated as separate breaks, shattering each sentence into individual words.
|
||||||
|
|
||||||
|
**Fix applied:**
|
||||||
|
- Issue messages are now joined with actual newline characters instead of `". "` when assembled into `ALL_ISSUES`.
|
||||||
|
- The splitting logic was replaced with a `while IFS= read -r issue; do ... done <<< "$ALL_ISSUES"` loop, which reads one full issue line at a time instead of relying on ambiguous multi-character `IFS` splitting.
|
||||||
|
|
||||||
|
Resolved — verified with a manual run; each issue now renders as one complete sentence in the "Issues Detected" section of the email.
|
||||||
|
|
||||||
|
### **Email Reports**
|
||||||
|
| Report | Trigger Colors | Content |
|
||||||
|
|--------|---------------|---------|
|
||||||
|
| Update Check | 🟢 Green (current) / 🔵 Blue (updates available) / 🟠 Orange (check failed) | Component versions, available updates, ready-to-run commands |
|
||||||
|
| Health Report | 🟢 Green (healthy) / 🟠 Orange (warning) / 🔴 Red (critical) | Disk usage, NFS mount status, memory, CPU load, container status, Fail2Ban, reboot flag |
|
||||||
|
| Config Backup | 🟢 Green (success) / 🟡 Amber (partial) / 🔴 Red (failed) | Archive sizes, durations, copies retained, container status, restore instructions |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧠 Summary for AI Systems
|
||||||
|
- PLEX32 = **dedicated Plex Media Server + Tautulli** on VLAN 50 at 192.168.150.45.
|
||||||
|
- Runs on Dell Wyse 5070 (Celeron J4105, 8GB RAM, 32GB eMMC).
|
||||||
|
- Plex and Tautulli run as Docker containers via `~/docker/plex/docker-compose.yml`.
|
||||||
|
- **Intel Quick Sync hardware transcoding active** — requires `/dev/dri` device passthrough and `group_add: ["44","993"]` in compose. Without group_add, Plex silently falls back to software transcoding.
|
||||||
|
- **Lifetime Plex Pass** active — Sonic Radio, hardware transcoding, all Plex Pass features enabled.
|
||||||
|
- Config and transcode stored **locally** at `/opt/plex/` — not on NFS.
|
||||||
|
- Media library mounted from NAS08 via NFS at `/mnt/plex/media`.
|
||||||
|
- `/mnt/plex/config` NFS mount used as backup destination only — not by Plex container.
|
||||||
|
- Library is ~75% HEVC Main 10, ~25% H.264, 100% AAC audio — audio never transcodes.
|
||||||
|
- Roku TV (Hisense 55R8BX) Direct Streams video, converts AAC→AC3 for audio (lightweight, expected).
|
||||||
|
- Subtitle Mode set to Manually Selected — prevents accidental PGS burn-in transcode.
|
||||||
|
- Publicly accessible via `plex.kingdezigns.com` — proxied through NPM on HAS.
|
||||||
|
- Port 32400 forwarded on UCG Max for direct Plex remote access.
|
||||||
|
- Tautulli on port 8181 — Plex down/up email alerts active.
|
||||||
|
- Fail2Ban active — VLAN 50 subnet whitelisted in ignoreip.
|
||||||
|
- sudo NOPASSWD configured for apt-get update, fail2ban-client, and reboot — required by automated and remote reboot scripts.
|
||||||
|
- **System timezone:** `America/New_York (EDT, -0400)` — corrected from `Etc/UTC` on 2026-06-21. UTC default causes cron jobs to fire 4 hours early. Always verify after fresh installs.
|
||||||
|
- SSH key from PLEX32 → NAS08 configured — required for backup script disk stats.
|
||||||
|
- **NAS08 root → PLEX32 SSH key configured** — required for remote reboot script (`plex32_reboot.sh` on NAS08).
|
||||||
|
- SSH key from KingDezigns001 → PLEX32 configured — enables passwordless remote launcher.
|
||||||
|
- **AC Power Recovery set to "On"** (2026-06-30) via SMBIOS token `0x00a3` using `smbios-token-ctl` — PLEX32 now auto powers-on after AC power is restored following an outage. Configured remotely via SSH, no BIOS access required. Tool: `libsmbios-bin` / `smbios-utils`.
|
||||||
|
- Config backup runs every 3 days at 2AM — tar + NFS copy, 3 copies retained, HTML email report.
|
||||||
|
- `ncshare` group (GID 1001) configured for network-wide permission consistency.
|
||||||
|
- eMMC has no SMART support — health monitored via daily health report email.
|
||||||
|
- No swap configured — 7.6GB RAM, consistently low utilization.
|
||||||
|
- Plex on NAS08 is **permanently disabled** (restart: no in compose).
|
||||||
|
- Migrated from NAS08 on 2026-06-18 — full library, watch history, and playlists preserved.
|
||||||
|
- **`plex32_update_check.sh` fixed 2026-07-12** — added explicit `PATH` export to fix intermittent `docker pull` failures under root's cron environment; script now logs real `docker pull` error output on failure instead of a generic "could not reach registry" message. All three PLEX32 scheduled jobs run under root's crontab.
|
||||||
|
- **`plex32_health_report.sh` fixed 2026-07-12** — fixed the "Issues Detected" email block rendering each word on its own line, caused by a multi-character `IFS='. '` split; issues are now newline-delimited and read back with a `while read` loop.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# ✔️ End of File
|
||||||
120
server_ucg.md
Normal file
120
server_ucg.md
Normal file
|
|
@ -0,0 +1,120 @@
|
||||||
|
# UCG Gateway Max — Network Gateway & Firewall
|
||||||
|
Device Type: **UniFi Cloud Gateway Max (UCG Max)**
|
||||||
|
Hostname: **KD-UCG-Max**
|
||||||
|
IP Address: **192.168.100.1**
|
||||||
|
VLAN: **1 — Infrastructure**
|
||||||
|
|
||||||
|
Last Updated: 2026-05-25
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧩 Role & Purpose
|
||||||
|
The UCG Max is the **primary network gateway, firewall, and UniFi controller** for the KingDezigns network.
|
||||||
|
It manages all inter-VLAN routing, firewall policies, DHCP, DNS forwarding, and UniFi device adoption.
|
||||||
|
|
||||||
|
It is the **single point of ingress and egress** for all internet traffic and the central controller for all UniFi network hardware.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🖥️ Hardware
|
||||||
|
- UniFi Cloud Gateway Max
|
||||||
|
- Built-in UniFi Network application (self-hosted on device)
|
||||||
|
- Gigabit WAN + LAN ports
|
||||||
|
- 2.5G uplink support
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🌐 Network Placement
|
||||||
|
- VLAN: **1 — Infrastructure**
|
||||||
|
- IP: **192.168.100.1**
|
||||||
|
- Access Type: LAN / Cable
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚙️ Primary Functions
|
||||||
|
- Internet gateway and NAT
|
||||||
|
- Inter-VLAN firewall enforcement
|
||||||
|
- DHCP server for all VLANs
|
||||||
|
- DNS forwarding to Pi-hole (192.168.150.35)
|
||||||
|
- UniFi Network controller (device adoption, configuration)
|
||||||
|
- Matter/Thread controller (port 5540)
|
||||||
|
- Port forwarding — external 80/443 → NPM on HAS (192.168.150.30)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔐 SSH Access
|
||||||
|
|
||||||
|
- **SSH command:** `ssh root@192.168.100.1`
|
||||||
|
- **Credentials:** Stored in **Vaultwarden** under entry `UCG Gateway SSH`
|
||||||
|
|
||||||
|
> Note: The UCG web UI (`https://192.168.100.1`) uses your Ubiquiti SSO account with MFA. SSH uses the local root account with a separate password. These are two different credential sets.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 💾 Backup
|
||||||
|
|
||||||
|
The UCG Max uses **Ubiquiti Cloud Backup** as its backup solution. This is the intended and only fully supported method for complete system restore on the UCG Max.
|
||||||
|
|
||||||
|
### **What is backed up**
|
||||||
|
- Full UniFi OS configuration including all applications, VLANs, firewall rules, SSIDs, and device adoption records
|
||||||
|
|
||||||
|
### **Backup schedule**
|
||||||
|
- Automatic weekly backup to Ubiquiti Cloud
|
||||||
|
- Additional backup generated automatically prior to each major firmware update
|
||||||
|
|
||||||
|
### **Restore process**
|
||||||
|
- Log in to **account.ui.com**
|
||||||
|
- Navigate to **Backups**
|
||||||
|
- Select the desired backup and restore to device
|
||||||
|
|
||||||
|
### **Manual backup**
|
||||||
|
A manual backup can be triggered and downloaded locally at any time:
|
||||||
|
1. Open `https://192.168.100.1`
|
||||||
|
2. Go to **Settings → Control Plane → Backups**
|
||||||
|
3. Click **Generate** then **Download**
|
||||||
|
4. Save the `.unifi` file to a safe location
|
||||||
|
|
||||||
|
> Note: The manual `.unifi` file is generated on demand only and is never stored persistently on the UCG disk. Local automated backup of this file is not supported by the UCG Max without third-party tooling.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔒 Firewall Overview
|
||||||
|
All firewall rules are documented in [firewall_policies.md](firewall_policies.md).
|
||||||
|
Key rules managed by the UCG:
|
||||||
|
|
||||||
|
- Global DNS → Pi-hole (all VLANs)
|
||||||
|
- Global Established/Related allow
|
||||||
|
- VLAN 50 outbound block (lab containment)
|
||||||
|
- IoT → Home Assistant only (port 8123)
|
||||||
|
- Matter/Thread → UCG controller (port 5540)
|
||||||
|
- Port forwarding: external 80/443 → 192.168.150.30 (NPM on HAS)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📡 Port Forwarding
|
||||||
|
| External | Internal | Destination | Purpose |
|
||||||
|
|----------|----------|-------------|---------|
|
||||||
|
| 80/TCP | 80/TCP | 192.168.150.30 | NPM HTTP |
|
||||||
|
| 443/TCP | 443/TCP | 192.168.150.30 | NPM HTTPS |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚠️ Important Operational Notes
|
||||||
|
- MFA is required for web UI login (Ubiquiti SSO) — TOTP authenticator app required
|
||||||
|
- SSH uses the local root account — not affected by MFA
|
||||||
|
- SSH authorized_keys and files written to the base filesystem may not survive firmware updates — verify SSH access after major updates
|
||||||
|
- Cloud backup is the only full one-file restore solution for the UCG Max
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧠 Summary for AI Systems
|
||||||
|
- UCG Max = **primary gateway, firewall, and UniFi controller** on VLAN 1 at 192.168.100.1.
|
||||||
|
- SSH access via local root account — credentials in Vaultwarden under `UCG Gateway SSH`.
|
||||||
|
- Full system backup handled by Ubiquiti Cloud — weekly automatic, restorable from account.ui.com.
|
||||||
|
- Manual `.unifi` backup can be downloaded via GUI but is never stored on disk automatically.
|
||||||
|
- Firewall rules, port forwarding, DHCP, and DNS forwarding all managed here.
|
||||||
|
- Matter/Thread controller runs on port 5540 (192.168.100.1).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# ✔️ End of File
|
||||||
67
vlan10_management.md
Normal file
67
vlan10_management.md
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
# VLAN 10 — Management Network
|
||||||
|
Subnet: **192.168.110.0/24**
|
||||||
|
|
||||||
|
Last Updated: 2026-05-21
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧩 What This Network Is
|
||||||
|
VLAN 10 is a **dedicated management network** intended for administrative access, secure configuration tasks, and future wired management devices.
|
||||||
|
Although currently unused, it is fully prepared to serve as an expansion network for administrative workstations or as a **fallback network** if other VLANs become unavailable.
|
||||||
|
|
||||||
|
This VLAN is considered **fully trusted**, but intentionally kept minimal until needed.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📡 Access Types
|
||||||
|
- LAN / Cable
|
||||||
|
- WiFi
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🌐 Subnet
|
||||||
|
- **192.168.110.0/24**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🖥️ Expected Devices
|
||||||
|
- *(None at this time — reserved for future administrative use)*
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔒 Security Rules for VLAN 10
|
||||||
|
|
||||||
|
### **Outbound (VLAN 10 → Others)**
|
||||||
|
- No explicit outbound rules beyond:
|
||||||
|
- Global **Established/Related** allow
|
||||||
|
- Global **DNS → Pi‑hole** allow
|
||||||
|
- Other outbound behavior depends on the default LAN policy.
|
||||||
|
|
||||||
|
### **Inbound (Others → VLAN 10)**
|
||||||
|
- **Allowed:**
|
||||||
|
- VLAN 1 (Infrastructure) → VLAN 10
|
||||||
|
- VLAN 20 (Trusted) → VLAN 10
|
||||||
|
- **Not explicitly blocked:**
|
||||||
|
- VLAN 30 (IoT)
|
||||||
|
- VLAN 40 (Guest)
|
||||||
|
- VLAN 50 (Lab)
|
||||||
|
*(These depend on default policy.)*
|
||||||
|
|
||||||
|
### **Net Effect**
|
||||||
|
- Management (VLAN 1) and Trusted (VLAN 20) can reach VLAN 10.
|
||||||
|
- No explicit isolation from IoT, Guest, or Lab — governed by default policy.
|
||||||
|
- Outbound traffic is mostly unrestricted unless default policy blocks it.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧠 Summary for AI Systems
|
||||||
|
- VLAN 10 = **trusted internal management network**, currently unused.
|
||||||
|
- No explicit outbound permissions except DNS + established/related.
|
||||||
|
- Reachable from VLAN 1 and VLAN 20.
|
||||||
|
- No explicit blocks from IoT, Guest, or Lab — default policy applies.
|
||||||
|
- Functions as a **neutral, low‑activity VLAN** ready for future administrative expansion.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# ✔️ End of File
|
||||||
|
|
||||||
79
vlan1_infrastructure.md
Normal file
79
vlan1_infrastructure.md
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
# VLAN 1 — Infrastructure / Default Network
|
||||||
|
Subnet: **192.168.100.0/24**
|
||||||
|
|
||||||
|
Last Updated: 2026-05-21
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧩 What This Network Is
|
||||||
|
VLAN 1 is the **primary infrastructure network** for the KingDezigns environment.
|
||||||
|
It hosts core systems, gateway services, UniFi management, and essential network hardware.
|
||||||
|
This VLAN is treated as a **semi‑trusted zone**, allowing broad internal communication while still blocking access from lower‑trust networks such as IoT and Lab.
|
||||||
|
|
||||||
|
This network remains active during ongoing migration and should not be aggressively restricted until all infrastructure is fully relocated.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📡 Access Types
|
||||||
|
- LAN / Cable
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🌐 Subnet
|
||||||
|
- **192.168.100.0/24**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🖥️ Expected Devices
|
||||||
|
- Infrastructure devices
|
||||||
|
- Core services
|
||||||
|
- UniFi gateway management
|
||||||
|
- Switches & access points
|
||||||
|
- Emergency recovery access
|
||||||
|
- At least one wired management workstation
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔒 Security Rules for VLAN 1
|
||||||
|
|
||||||
|
### **Outbound (VLAN 1 → Others)**
|
||||||
|
- VLAN 1 can initiate connections to **all internal VLANs**
|
||||||
|
(VLAN 1, 10, 20, 30, 40, 50).
|
||||||
|
|
||||||
|
### **Inbound (Others → VLAN 1)**
|
||||||
|
- **Allowed:**
|
||||||
|
- VLAN 20 (Trusted) → VLAN 1
|
||||||
|
- **Blocked:**
|
||||||
|
- VLAN 30 (IoT) → VLAN 1
|
||||||
|
- VLAN 50 (Lab/Servers) → VLAN 1
|
||||||
|
- **Undefined (depends on default policy):**
|
||||||
|
- VLAN 40 (Guest) → VLAN 1
|
||||||
|
|
||||||
|
### **Net Effect**
|
||||||
|
- VLAN 1 can reach every internal VLAN.
|
||||||
|
- Trusted devices may reach VLAN 1.
|
||||||
|
- IoT and Lab cannot initiate into VLAN 1.
|
||||||
|
- Guest access depends on global default rules.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚠️ Important Notes
|
||||||
|
- Infrastructure remains on VLAN 1 during migration.
|
||||||
|
- Avoid strict firewall enforcement until migration is complete.
|
||||||
|
- Maintain at least one wired management workstation for safety.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧠 Summary for AI Systems
|
||||||
|
- VLAN 1 = **infrastructure + management zone**, semi‑trusted.
|
||||||
|
- Can initiate connections to all VLANs.
|
||||||
|
- Trusted VLAN 20 may initiate into VLAN 1.
|
||||||
|
- IoT VLAN 30 and Lab VLAN 50 are blocked from initiating into VLAN 1.
|
||||||
|
- Guest VLAN 40 behavior depends on default policy.
|
||||||
|
- All VLANs may send DNS to Pi‑hole in VLAN 50.
|
||||||
|
- VLAN 1 is a reachable core network but protected from lower‑trust zones.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# ✔️ End of File
|
||||||
|
|
||||||
74
vlan20_trusted.md
Normal file
74
vlan20_trusted.md
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
# VLAN 20 — Trusted Devices
|
||||||
|
Subnet: **192.168.120.0/24**
|
||||||
|
|
||||||
|
Last Updated: 2026-05-21
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧩 What This Network Is
|
||||||
|
VLAN 20 is the **primary trusted user network** for day‑to‑day administrative and productivity devices.
|
||||||
|
It is designed for laptops, desktops, phones, and tablets used by authorized users who require reliable access to internal systems.
|
||||||
|
|
||||||
|
This VLAN provides a **secure but flexible environment**, allowing trusted devices to access internal services while remaining isolated from lower‑trust networks such as IoT, Guest, and Lab.
|
||||||
|
|
||||||
|
It is the main operational network for users who need consistent access to internal tools, servers, and management interfaces.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📡 Access Types
|
||||||
|
- LAN / Cable
|
||||||
|
- WiFi
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🌐 Subnet
|
||||||
|
- **192.168.120.0/24**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🖥️ Expected Devices
|
||||||
|
- Linux desktops
|
||||||
|
- Trusted laptops
|
||||||
|
- Mobile devices
|
||||||
|
- Administrative systems
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔒 Security Rules for VLAN 20
|
||||||
|
|
||||||
|
### **Outbound (VLAN 20 → Others)**
|
||||||
|
- VLAN 20 can initiate connections to **all internal VLANs except itself**:
|
||||||
|
- VLAN 1 — Infrastructure
|
||||||
|
- VLAN 10 — Management
|
||||||
|
- VLAN 30 — IoT
|
||||||
|
- VLAN 40 — Guest
|
||||||
|
- VLAN 50 — Lab
|
||||||
|
|
||||||
|
### **Inbound (Others → VLAN 20)**
|
||||||
|
- **Blocked:**
|
||||||
|
- VLAN 30 (IoT) → VLAN 20
|
||||||
|
- VLAN 50 (Lab/Servers) → VLAN 20
|
||||||
|
- **Allowed:**
|
||||||
|
- VLAN 1 (Infrastructure) → VLAN 20
|
||||||
|
- **Undefined (depends on default policy):**
|
||||||
|
- VLAN 40 (Guest) → VLAN 20
|
||||||
|
|
||||||
|
### **Net Effect**
|
||||||
|
- Trusted devices can reach every other VLAN.
|
||||||
|
- IoT and Lab cannot initiate into VLAN 20.
|
||||||
|
- Management (VLAN 1) can reach VLAN 20.
|
||||||
|
- Guest access depends on global default rules.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧠 Summary for AI Systems
|
||||||
|
- VLAN 20 = **high‑trust user network** with broad outbound access.
|
||||||
|
- Can initiate connections to all other VLANs.
|
||||||
|
- Blocked from IoT and Lab inbound.
|
||||||
|
- Reachable from VLAN 1; Guest behavior depends on default policy.
|
||||||
|
- Acts as a **trusted control network** with strong protection from lower‑trust zones.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# ✔️ End of File
|
||||||
|
|
||||||
113
vlan30_iot.md
Normal file
113
vlan30_iot.md
Normal file
|
|
@ -0,0 +1,113 @@
|
||||||
|
# VLAN 30 — IoT Network
|
||||||
|
Subnet: **192.168.130.0/23**
|
||||||
|
|
||||||
|
Last Updated: 2026-05-24
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧩 What This Network Is
|
||||||
|
VLAN 30 is the **dedicated smart‑home and automation network** for all IoT and consumer smart devices.
|
||||||
|
It is intentionally isolated from trusted networks to reduce security risk while still supporting full functionality for Home Assistant and other automation systems.
|
||||||
|
|
||||||
|
This VLAN is designed for devices such as WiZ bulbs, TVs, smart plugs, cameras, sensors, and other automation hardware that require internet access or controller communication but should not interact with trusted user devices.
|
||||||
|
|
||||||
|
The network provides a **controlled, low‑trust environment** with carefully scoped access to Home Assistant and DNS services.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📡 Access Types
|
||||||
|
- LAN / Cable
|
||||||
|
- WiFi
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🌐 Subnet
|
||||||
|
- **192.168.130.0/23**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🖥️ Expected Devices
|
||||||
|
- Lights
|
||||||
|
- Switches
|
||||||
|
- Outlets
|
||||||
|
- Blinds
|
||||||
|
- TV & streaming devices
|
||||||
|
- Alarm systems
|
||||||
|
- HVAC controllers
|
||||||
|
- Fans
|
||||||
|
- Voice assistants
|
||||||
|
- VOIP phones
|
||||||
|
- Vacuums
|
||||||
|
- Door locks
|
||||||
|
- Garage door openers
|
||||||
|
- Smoke detectors
|
||||||
|
|
||||||
|
## 📌 Notable Devices
|
||||||
|
| Device | IP | Role |
|
||||||
|
|--------|-----|------|
|
||||||
|
| Aqara M100 | 192.168.130.30 (static reservation) | Thread Border Router / Matter hub |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔒 Security Rules for VLAN 30
|
||||||
|
|
||||||
|
### **Outbound (VLAN 30 → Others)**
|
||||||
|
- **Allowed:**
|
||||||
|
- IoT → Home Assistant (192.168.150.30:8123, TCP/UDP)
|
||||||
|
- IoT → Pi‑hole DNS (192.168.150.35, TCP/UDP 53)
|
||||||
|
- IoT → UCG Max Matter controller (192.168.100.1:5540, TCP)
|
||||||
|
- **Blocked:**
|
||||||
|
- IoT → VLAN 20 (Trusted)
|
||||||
|
- IoT → VLAN 1 (Infrastructure) — except Matter controller port above
|
||||||
|
- **Default‑Policy Dependent:**
|
||||||
|
- IoT → VLAN 10 (Management)
|
||||||
|
- IoT → VLAN 40 (Guest)
|
||||||
|
|
||||||
|
### **Inbound (Others → VLAN 30)**
|
||||||
|
- **Allowed:**
|
||||||
|
- VLAN 1 (Infrastructure) → VLAN 30
|
||||||
|
- VLAN 20 (Trusted) → VLAN 30
|
||||||
|
- Home Assistant (192.168.150.30) → VLAN 30 (TCP/UDP, any port)
|
||||||
|
- **Blocked:**
|
||||||
|
- VLAN 50 (Lab/Servers) → VLAN 30
|
||||||
|
|
||||||
|
### **Net Effect**
|
||||||
|
- IoT devices can communicate with Home Assistant and DNS.
|
||||||
|
- IoT cannot reach Trusted or Infrastructure networks.
|
||||||
|
- IoT may reach Management or Guest depending on default policy.
|
||||||
|
- Management, Trusted, and Home Assistant can initiate into IoT.
|
||||||
|
- Lab cannot reach IoT.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚙️ Important Configuration
|
||||||
|
- **mDNS reflection enabled** (VLANs 1, 10, 20, 30, 50)
|
||||||
|
- **IGMP Snooping enabled**
|
||||||
|
- **Multicast/discovery traffic required** for many integrations
|
||||||
|
- **Client Isolation must be disabled** — required for Matter/Thread device pairing and intra-VLAN device communication
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔍 Discovery Protocols Expected
|
||||||
|
- mDNS
|
||||||
|
- Multicast
|
||||||
|
- UDP discovery
|
||||||
|
- Home Assistant auto‑discovery
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧠 Summary for AI Systems
|
||||||
|
- VLAN 30 = **untrusted IoT zone**, tightly restricted.
|
||||||
|
- Outbound allowed only to:
|
||||||
|
- Home Assistant (8123/TCP/UDP)
|
||||||
|
- Pi-hole DNS
|
||||||
|
- UCG Max Matter controller (192.168.100.1:5540/TCP)
|
||||||
|
- Blocked from initiating to VLAN 20 and VLAN 1 (except Matter controller port 5540).
|
||||||
|
- May reach VLAN 10 or VLAN 40 depending on default policy.
|
||||||
|
- Inbound allowed from VLAN 1, VLAN 20, and Home Assistant.
|
||||||
|
- Designed to contain IoT devices while preserving automation functionality.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# ✔️ End of File
|
||||||
|
|
||||||
75
vlan40_guest.md
Normal file
75
vlan40_guest.md
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
# VLAN 40 — Guest Network
|
||||||
|
Subnet: **192.168.140.0/24**
|
||||||
|
|
||||||
|
Last Updated: 2026-05-21
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧩 What This Network Is
|
||||||
|
VLAN 40 is the **dedicated guest WiFi network** for temporary visitors and untrusted personal devices.
|
||||||
|
It provides safe, isolated internet access without exposing internal systems, trusted devices, or infrastructure resources.
|
||||||
|
|
||||||
|
This VLAN is intentionally designed as a **high‑isolation, low‑trust environment**, ensuring that guest traffic cannot interfere with administrative, IoT, or server networks while still offering convenient connectivity.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📡 Access Types
|
||||||
|
- WiFi only
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🌐 Subnet
|
||||||
|
- **192.168.140.0/24**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🖥️ Expected Devices
|
||||||
|
- Guest phones
|
||||||
|
- Guest laptops
|
||||||
|
- Visitor tablets
|
||||||
|
- Temporary personal devices
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔒 Security Rules for VLAN 40
|
||||||
|
|
||||||
|
### **Outbound (VLAN 40 → Others)**
|
||||||
|
- **Allowed:**
|
||||||
|
- DNS → Pi‑hole (192.168.150.35)
|
||||||
|
- **Default‑Policy Dependent:**
|
||||||
|
- Guest → VLAN 1
|
||||||
|
- Guest → VLAN 10
|
||||||
|
- Guest → VLAN 20
|
||||||
|
- Guest → VLAN 30
|
||||||
|
- Guest → VLAN 50
|
||||||
|
*(No explicit allow/deny rules beyond DNS.)*
|
||||||
|
|
||||||
|
### **Inbound (Others → VLAN 40)**
|
||||||
|
- **Allowed:**
|
||||||
|
- VLAN 1 (Infrastructure) → VLAN 40
|
||||||
|
- VLAN 20 (Trusted) → VLAN 40
|
||||||
|
- **Blocked:**
|
||||||
|
- VLAN 50 (Lab/Servers) → VLAN 40
|
||||||
|
- **Undefined:**
|
||||||
|
- VLAN 30 (IoT) → VLAN 40 (depends on default policy)
|
||||||
|
|
||||||
|
### **Net Effect**
|
||||||
|
- Guest devices can resolve DNS via Pi‑hole.
|
||||||
|
- Guest access to other VLANs is governed by the default LAN policy.
|
||||||
|
- Management and Trusted VLANs can reach Guest.
|
||||||
|
- Lab VLAN is explicitly blocked from reaching Guest.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧠 Summary for AI Systems
|
||||||
|
- VLAN 40 = **guest WiFi**, minimal privileges.
|
||||||
|
- Only guaranteed outbound access is DNS → Pi‑hole.
|
||||||
|
- Reachable from VLAN 1 and VLAN 20.
|
||||||
|
- Blocked from Lab VLAN 50 inbound.
|
||||||
|
- No explicit outbound blocks to other VLANs — default policy applies.
|
||||||
|
- Designed as a **high‑isolation, low‑trust network** for visitors.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# ✔️ End of File
|
||||||
|
|
||||||
86
vlan50_lab.md
Normal file
86
vlan50_lab.md
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
# VLAN 50 — Lab / Servers Network
|
||||||
|
Subnet: **192.168.150.0/24**
|
||||||
|
|
||||||
|
Last Updated: 2026-06-18
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧩 What This Network Is
|
||||||
|
VLAN 50 is the **dedicated server and lab environment** for the KingDezigns network.
|
||||||
|
It hosts Home Assistant, NAS systems, Pi‑hole, the Plex Media Server, and various self‑hosted services that require controlled access, stability, and isolation.
|
||||||
|
|
||||||
|
This VLAN is intentionally **tightly contained**, preventing lab systems or high‑privilege services from initiating connections into trusted or infrastructure networks.
|
||||||
|
Only specific exceptions—such as Home Assistant controlling IoT devices—are permitted.
|
||||||
|
|
||||||
|
This network functions as a **sandboxed, semi‑trusted zone** where critical services can operate safely without exposing the rest of the network to unnecessary risk.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📡 Access Types
|
||||||
|
- LAN / Cable
|
||||||
|
- WiFi
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🌐 Subnet
|
||||||
|
- **192.168.150.0/24**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🖥️ Expected Devices
|
||||||
|
- Home Assistant
|
||||||
|
- NAS08 (Pi‑hole, Nextcloud, Vaultwarden, nginx)
|
||||||
|
- NAS16 (LAMP stack, MariaDB, Webmin)
|
||||||
|
- PLEX32 (Plex Media Server — Dell Wyse 5070)
|
||||||
|
- Additional lab servers
|
||||||
|
- Test systems
|
||||||
|
- Development containers
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔒 Security Rules for VLAN 50
|
||||||
|
|
||||||
|
### **Outbound (VLAN 50 → Others)**
|
||||||
|
- **Blocked (Global Final Drop):**
|
||||||
|
VLAN 50 cannot initiate connections to:
|
||||||
|
- VLAN 1 — Infrastructure
|
||||||
|
- VLAN 10 — Management
|
||||||
|
- VLAN 20 — Trusted
|
||||||
|
- VLAN 30 — IoT
|
||||||
|
- VLAN 40 — Guest
|
||||||
|
|
||||||
|
- **Allowed Exceptions:**
|
||||||
|
- Home Assistant (192.168.150.30) → VLAN 30 (IoT), any port, TCP/UDP
|
||||||
|
- DNS → Pi‑hole (local to VLAN 50)
|
||||||
|
|
||||||
|
### **Inbound (Others → VLAN 50)**
|
||||||
|
- **Allowed:**
|
||||||
|
- VLAN 1 (Infrastructure) → VLAN 50
|
||||||
|
- VLAN 20 (Trusted) → VLAN 50
|
||||||
|
- VLAN 30 (IoT) → Home Assistant (192.168.150.30:8123)
|
||||||
|
- **Default‑Policy Dependent:**
|
||||||
|
- VLAN 10 → VLAN 50
|
||||||
|
- VLAN 40 → VLAN 50
|
||||||
|
|
||||||
|
### **Net Effect**
|
||||||
|
- Lab/Server systems are **heavily isolated** from initiating connections to other VLANs.
|
||||||
|
- Only Home Assistant is allowed to control IoT devices.
|
||||||
|
- Management and Trusted VLANs can reach Lab systems.
|
||||||
|
- All VLANs use Pi‑hole in VLAN 50 for DNS.
|
||||||
|
- IoT can reach Home Assistant only on port 8123.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧠 Summary for AI Systems
|
||||||
|
- VLAN 50 = **sandboxed server/lab zone**, semi‑trusted but highly restricted.
|
||||||
|
- Outbound traffic is blocked to all VLANs except:
|
||||||
|
- Home Assistant → IoT
|
||||||
|
- DNS → Pi‑hole
|
||||||
|
- Inbound allowed from VLAN 1 and VLAN 20.
|
||||||
|
- IoT can reach Home Assistant only on port 8123.
|
||||||
|
- Designed to contain high‑privilege services and prevent lateral movement.
|
||||||
|
- PLEX32 (192.168.150.45) added 2026-06-18 — dedicated Plex Media Server, replaced Plex on NAS08. See `server_plex32.md`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# ✔️ End of File
|
||||||
Loading…
Add table
Reference in a new issue