diff --git a/2git.ps1 b/2git.ps1 index 4afadab..a00077c 100644 --- a/2git.ps1 +++ b/2git.ps1 @@ -35,4 +35,3 @@ if ($LASTEXITCODE -ne 0) { } Write-Host "✅ Done!" -ForegroundColor Green -pause diff --git a/specs/01-requirements/01-02-architecture.md b/specs/01-requirements/01-02-architecture.md index af663a9..62c17fe 100644 --- a/specs/01-requirements/01-02-architecture.md +++ b/specs/01-requirements/01-02-architecture.md @@ -3,10 +3,10 @@ --- title: 'System Architecture' -version: 1.5.0 +version: 1.8.0 status: first-draft owner: Nattanin Peancharoen -last_updated: 2025-11-30 +last_updated: 2026-01-26 related: - specs/01-objectives.md @@ -18,13 +18,375 @@ specs/01-objectives.md - Domain: `np-dms.work`, `www.np-dms.work` - IP: 159.192.126.103 -- Server: QNAP (Model: TS-473A, RAM: 32GB, CPU: AMD Ryzen V1500B) +- Server: QNAP TS-473A, RAM: 32GB, CPU: AMD Ryzen V1500B, HDD: 4TBx4nos. RAID 5, SSD: 1TB ใช้เป็น caching, มี port 2.5Gbps 2 port +- Server: AS5304T, RAM: 16GB, CPU: Intel Celeron CPU @ 2.00GH, HDD: 6TBx3nos. RAID 5, SSD: 1TB ใช้เป็น caching, มี port 2.5Gbps 2 port +- Rotuter: TP-LINK ER7206, WAN/LAN port 1 SFP, WAN port 2, WAN/LAN 10/100/1000 port 3-6 +- Core Switch: TP-LINK TL-SG2428P, LAN port 1-24 10/100/1000, SFP port 25-28 1Gbps +- Server Switch: AMPCOM, LAN port 1-8 10/100/1000/2500, SFP+ port 9 10Gbps +- Admin Switch: TP-LINK ES205G, LAN port 1-5 10/100/1000 +- CCTV Switch: TP-LINK TL-SL1226P port 1-24 PoE+ 100Mbps, SFP port 24-25 1Gbps +- IP Phone Switch: TP-LINK TL-SG1210P port 1-8 PoE+ 100Mbps , Uplink1 10/100/1000, Uplink2 SFP 1Gbps +- Controller: TP-LINK OC200 +- Wireless Access point: TP-LINK EAP610 16 ตัว +- CCTV: HikVision (DS-7732NXI-K4) + กล้อง 6 ตัว +- IP Phone: YeaLink 8 ตัว +- Admin Desktop: Windows 11, LAN port 10/100/1000/2500 +- Printer: Kyocera CS 3554ci, LAN port 10/100/1000 - Containerization: Container Station (Docker & Docker Compose) ใช้ UI ของ Container Station เป็นหลัก ในการ configuration และการรัน docker command - Development Environment: VS Code/Cursor on Windows 11 - Data Storage: /share/dms-data บน QNAP - ข้อจำกัด: ไม่สามารถใช้ .env ในการกำหนดตัวแปรภายนอกได้ ต้องกำหนดใน docker-compose.yml เท่านั้น -## **2.2 การจัดการ Configuration (ปรับปรุง):** +## **2.2 Netwrok Configuration** + +**VLAN Networks** +| VLAN ID | Name | Purpose | Gateway/Subnet | DHCP | IP Range | DNS | Lease Time | ARP Detection | IGMP Snooping | MLD Snooping | Notes | +| ------- | ------ | --------- | --------------- | ---- | ------------------ | ------- | ---------- | ------------- | ------------- | ------------ | --------------- | +| 10 | SERVER | Interface | 192.168.10.1/24 | No | - | Custom | - | - | - | - | Static servers | +| 20 | MGMT | Interface | 192.168.20.1/24 | No | - | Custom | - | Enable | Enable | - | Management only | +| 30 | USER | Interface | 192.168.30.1/24 | Yes | 192.168.30.10-254 | Auto | 7 Days | - | Enable | - | User devices | +| 40 | CCTV | Interface | 192.168.40.1/24 | Yes | 192.168.40.100-150 | Auto | 7 Days | - | Enable | - | CCTV & NVR | +| 50 | VOICE | Interface | 192.168.50.1/24 | Yes | 192.168.50.201-250 | Auto | 7 Days | - | - | - | IP Phones | +| 60 | DMZ | Interface | 192.168.60.1/24 | No | - | 1.1.1.1 | - | - | - | - | Public services | +| 70 | GUEST | Interface | 192.168.70.1/24 | Yes | 192.168.70.200-250 | Auto | 1 Day | - | - | - | Guest | + + +**Switch Profiles** +| Profile Name | Native Network | Tagged Networks | Untagged Networks | Voice Network | Loopback Control | Usage | +| ---------------- | -------------- | --------------------- | ----------------- | ------------- | ---------------- | ----------------------- | +| 01_CORE_TRUNK | MGMT (20) | 10,30,40,50,60,70 | MGMT (20) | - | Spanning Tree | Router & switch uplinks | +| 02_MGMT_ONLY | MGMT (20) | MGMT (20) | - | - | Spanning Tree | Management only | +| 03_SERVER_ACCESS | SERVER (10) | MGMT (20) | SERVER (10) | - | Spanning Tree | QNAP / ASUSTOR | +| 04_CCTV_ACCESS | CCTV (40) | - | CCTV (40) | - | Spanning Tree | CCTV cameras | +| 05_USER_ACCESS | USER (30) | - | USER (30) | - | Spanning Tree | PC / Printer | +| 06_AP_TRUNK | MGMT (20) | USER (30), GUEST (70) | MGMT (20) | - | Spanning Tree | EAP610 Access Points | +| 07_VOICE_ACCESS | USER (30) | VOICE (50) | USER (30) | VOICE (50) | Spanning Tree | IP Phones | + + +**ER7206 Port Mapping** +| Port | Connected Device | Port | Description | +| ---- | ---------------- | ------------- | ----------- | +| 1 | - | - | - | +| 2 | WAN | - | Internet | +| 3 | SG2428P | PVID MGMT(20) | Core Switch | +| 4 | - | - | - | +| 5 | - | - | - | +| 6 | - | - | - | + +**AMPCOM Port Aggregate Setting** +| Aggregate Group ID | Type | Member port | Aggregated Port | +| ------------------ | ---- | ----------- | --------------- | +| Trunk1 | LACP | 3,4 | 3,4 | +| Trunk2 | LACP | 5,6 | 5,6 | + + +**AMPCOM Port VLAN Mapping** +| Port | Connected Device | Port vlan type | Access VLAN | Native VLAN | Trunk vlan | +| ------ | ---------------- | -------------- | ----------- | ----------- | -------------------- | +| 1 | SG2428P | Trunk | - | 20 | 10,20,30,40,50,60,70 | +| 2 | - | Trunk | - | 20 | 10,20,30,40,50,60,70 | +| 7 | - | Access | 20 | - | - | +| 8 | Admin Desktop | Access | 20 | - | - | +| Trunk1 | QNAP | Trunk | - | 10 | 10,20,30,40,50,60,70 | +| Trunk2 | ASUSTOR | Trunk | - | 10 | 10,20,30,40,50,60,70 | + + +**NAS NIC Bonding Configuration** +| Device | Bonding Mode | Member Ports | VLAN Mode | Tagged VLAN | IP Address | Gateway | Notes | +| ------- | ------------------- | ------------ | --------- | ----------- | --------------- | ------------ | ---------------------- | +| QNAP | IEEE 802.3ad (LACP) | Adapter 1, 2 | Untagged | 10 (SERVER) | 192.168.10.8/24 | 192.168.10.1 | Primary NAS for DMS | +| ASUSTOR | IEEE 802.3ad (LACP) | Port 1, 2 | Untagged | 10 (SERVER) | 192.168.10.9/24 | 192.168.10.1 | Backup / Secondary NAS | + +> **หมายเหตุ**: NAS ทั้งสองตัวใช้ LACP bonding เพื่อเพิ่ม bandwidth และ redundancy โดยต้อง config ให้ตรงกับ AMPCOM Switch (Trunk1) + + +**SG2428P Port Mapping** +| Port | Connected Device | Switch Profile | Description | +| ---- | ------------------------- | -------------------- | ------------- | +| 1 | ER7206 | 01_CORE_TRUNK | Internet | +| 2 | OC200 | 01_CORE_TRUNK | Controller | +| 3 | Ampcom 2.5G Switch Port 1 | LAG1 (01_CORE_TRUNK) | Uplink | +| 4 | - | LAG1 (01_CORE_TRUNK) | Reserved | +| 5 | EAP610-01 | 06_AP_TRUNK | Access Point | +| 6 | EAP610-02 | 06_AP_TRUNK | Access Point | +| 7 | EAP610-03 | 06_AP_TRUNK | Access Point | +| 8 | EAP610-04 | 06_AP_TRUNK | Access Point | +| 9 | EAP610-05 | 06_AP_TRUNK | Access Point | +| 10 | EAP610-06 | 06_AP_TRUNK | Access Point | +| 11 | EAP610-07 | 06_AP_TRUNK | Access Point | +| 12 | EAP610-08 | 06_AP_TRUNK | Access Point | +| 13 | EAP610-09 | 06_AP_TRUNK | Access Point | +| 14 | EAP610-10 | 06_AP_TRUNK | Access Point | +| 15 | EAP610-11 | 06_AP_TRUNK | Access Point | +| 16 | EAP610-12 | 06_AP_TRUNK | Access Point | +| 17 | EAP610-13 | 06_AP_TRUNK | Access Point | +| 18 | EAP610-14 | 06_AP_TRUNK | Access Point | +| 19 | EAP610-15 | 06_AP_TRUNK | Access Point | +| 20 | EAP610-16 | 06_AP_TRUNK | Access Point | +| 21 | Reserved | 01_CORE_TRUNK | | +| 22 | Reserved | 01_CORE_TRUNK | | +| 23 | Printer | 05_USER_ACCESS | Printer | +| 24 | ES205G | 01_CORE_TRUNK | Management PC | +| 25 | TL-SL1226P | 01_CORE_TRUNK | Uplink | +| 26 | SG1210P | 01_CORE_TRUNK | Uplink | +| 27 | Reserved | 01_CORE_TRUNK | | +| 28 | Reserved | 01_CORE_TRUNK | | + + +**ES205G Port Mapping (Admin Switch)** +| Port | Connected Device | VLAN | Description | +| ---- | ---------------- | ----------- | ----------- | +| 1 | SG2428P Port 24 | Trunk (All) | Uplink | +| 2 | Admin Desktop | MGMT (20) | Admin PC | +| 3 | Reserved | MGMT (20) | | +| 4 | Reserved | MGMT (20) | | +| 5 | Reserved | MGMT (20) | | + +> **หมายเหตุ**: ES205G เป็น Unmanaged Switch ไม่รองรับ VLAN tagging ดังนั้นทุก port จะอยู่ใน Native VLAN (20) ของ uplink + + +**TL-SL1226P Port Mapping (CCTV Switch)** +| Port | Connected Device | PoE | VLAN | Description | +| ---- | ---------------- | ---- | --------- | ----------- | +| 1 | Camera-01 | PoE+ | CCTV (40) | CCTV Camera | +| 2 | Camera-02 | PoE+ | CCTV (40) | CCTV Camera | +| 3 | Camera-03 | PoE+ | CCTV (40) | CCTV Camera | +| 4 | Camera-04 | PoE+ | CCTV (40) | CCTV Camera | +| 5 | Camera-05 | PoE+ | CCTV (40) | CCTV Camera | +| 6 | Camera-06 | PoE+ | CCTV (40) | CCTV Camera | +| 7-23 | Reserved | PoE+ | CCTV (40) | | +| 24 | HikVision NVR | - | CCTV (40) | NVR | +| 25 | SG2428P Port 25 | - | Trunk | SFP Uplink | +| 26 | Reserved | - | Trunk | SFP | + + +**SG1210P Port Mapping (IP Phone Switch)** +| Port | Connected Device | PoE | Data VLAN | Voice VLAN | Description | +| ------- | ---------------- | ---- | --------- | ---------- | ----------- | +| 1 | IP Phone-01 | PoE+ | USER (30) | VOICE (50) | IP Phone | +| 2 | IP Phone-02 | PoE+ | USER (30) | VOICE (50) | IP Phone | +| 3 | IP Phone-03 | PoE+ | USER (30) | VOICE (50) | IP Phone | +| 4 | IP Phone-04 | PoE+ | USER (30) | VOICE (50) | IP Phone | +| 5 | IP Phone-05 | PoE+ | USER (30) | VOICE (50) | IP Phone | +| 6 | IP Phone-06 | PoE+ | USER (30) | VOICE (50) | IP Phone | +| 7 | IP Phone-07 | PoE+ | USER (30) | VOICE (50) | IP Phone | +| 8 | IP Phone-08 | PoE+ | USER (30) | VOICE (50) | IP Phone | +| Uplink1 | Reserved | - | Trunk | - | RJ45 Uplink | +| Uplink2 | SG2428P Port 26 | - | Trunk | - | SFP Uplink | + +> **หมายเหตุ**: SG1210P รองรับ Voice VLAN ทำให้ IP Phone ใช้ VLAN 50 สำหรับ voice traffic และ passthrough VLAN 30 สำหรับ PC ที่ต่อผ่าน phone + + +**Static IP Allocation** +| VLAN | Device | IP Address | MAC Address | Notes | +| ---------- | --------------- | ------------------ | ----------- | ---------------- | +| SERVER(10) | QNAP | 192.168.10.8 | - | Primary NAS | +| SERVER(10) | ASUSTOR | 192.168.10.9 | - | Backup NAS | +| SERVER(10) | Docker Host | 192.168.10.10 | - | Containers | +| MGMT(20) | ER7206 | 192.168.20.1 | - | Gateway/Router | +| MGMT(20) | SG2428P | 192.168.20.2 | - | Core Switch | +| MGMT(20) | AMPCOM | 192.168.20.3 | - | Server Switch | +| MGMT(20) | TL-SL1226P | 192.168.20.4 | - | CCTV Switch | +| MGMT(20) | SG1210P | 192.168.20.5 | - | Phone Switch | +| MGMT(20) | OC200 | 192.168.20.250 | - | Omada Controller | +| MGMT(20) | Admin Desktop | 192.168.20.100 | - | Admin PC | +| USER(30) | Printer | 192.168.30.222 | - | Kyocera CS3554ci | +| CCTV(40) | NVR | 192.168.40.100 | - | HikVision NVR | +| CCTV(40) | Camera-01 to 06 | 192.168.40.101-106 | - | CCTV Cameras | +| USER(30) | Admin Desktop | 192.168.30.100 | - | Admin PC (USER) | + +**2.8 DHCP Reservation (MAC Mapping)** + +**CCTV MAC Address Mapping (VLAN 40)** +| Device Name | IP Address | MAC Address | Port (Switch) | Notes | +| ------------- | -------------- | ----------- | ------------- | ---------- | +| HikVision NVR | 192.168.40.100 | | Port 24 | Master NVR | +| Camera-01 | 192.168.40.101 | | Port 1 | | +| Camera-02 | 192.168.40.102 | | Port 2 | | +| Camera-03 | 192.168.40.103 | | Port 3 | | +| Camera-04 | 192.168.40.104 | | Port 4 | | +| Camera-05 | 192.168.40.105 | | Port 5 | | +| Camera-06 | 192.168.40.106 | | Port 6 | | + +**IP Phone MAC Address Mapping (VLAN 50)** +| Device Name | IP Address | MAC Address | Port (Switch) | Notes | +| ----------- | -------------- | ----------- | ------------- | ------- | +| IP Phone-01 | 192.168.50.201 | | Port 1 | Yealink | +| IP Phone-02 | 192.168.50.202 | | Port 2 | Yealink | +| IP Phone-03 | 192.168.50.203 | | Port 3 | Yealink | +| IP Phone-04 | 192.168.50.204 | | Port 4 | Yealink | +| IP Phone-05 | 192.168.50.205 | | Port 5 | Yealink | +| IP Phone-06 | 192.168.50.206 | | Port 6 | Yealink | +| IP Phone-07 | 192.168.50.207 | | Port 7 | Yealink | +| IP Phone-08 | 192.168.50.208 | | Port 8 | Yealink | + + +**Wireless SSID Mapping (OC200 Controller)** +| SSID Name | Band | VLAN | Security | Portal Auth | Notes | +| --------- | ------- | ---------- | --------- | ----------- | ----------------------- | +| PSLCBP3 | 2.4G/5G | USER (30) | WPA2/WPA3 | No | Staff WiFi | +| GUEST | 2.4G/5G | GUEST (70) | WPA2 | Yes | Guest WiFi with Captive | + +> **หมายเหตุ**: ทุก SSID broadcast ผ่าน EAP610 ทั้ง 16 ตัว โดยใช้ 06_AP_TRUNK profile ที่ tag VLAN 30 และ 70 + + +**Gateway ACL (ER7206 Firewall Rules)** + +*Inter-VLAN Routing Policy* +| # | Name | Source | Destination | Service | Action | Log | Notes | +| --- | ----------------- | --------------- | ---------------- | -------------- | ------ | --- | --------------------------- | +| 1 | MGMT-to-ALL | VLAN20 (MGMT) | Any | Any | Allow | No | Admin full access | +| 2 | SERVER-to-ALL | VLAN10 (SERVER) | Any | Any | Allow | No | Servers outbound access | +| 3 | USER-to-SERVER | VLAN30 (USER) | VLAN10 (SERVER) | HTTP/HTTPS/SSH | Allow | No | Users access web apps | +| 4 | USER-to-DMZ | VLAN30 (USER) | VLAN60 (DMZ) | HTTP/HTTPS | Allow | No | Users access DMZ services | +| 5 | USER-to-MGMT | VLAN30 (USER) | VLAN20 (MGMT) | Any | Deny | Yes | Block users from management | +| 6 | USER-to-CCTV | VLAN30 (USER) | VLAN40 (CCTV) | Any | Deny | Yes | Isolate CCTV | +| 7 | USER-to-VOICE | VLAN30 (USER) | VLAN50 (VOICE) | Any | Deny | No | Isolate Voice | +| 8 | USER-to-GUEST | VLAN30 (USER) | VLAN70 (GUEST) | Any | Deny | No | Isolate Guest | +| 9 | CCTV-to-INTERNET | VLAN40 (CCTV) | WAN | HTTPS (443) | Allow | No | NVR cloud backup (optional) | +| 10 | CCTV-to-ALL | VLAN40 (CCTV) | Any (except WAN) | Any | Deny | Yes | CCTV isolated | +| 11 | VOICE-to-SIP | VLAN50 (VOICE) | SIP Server IP | SIP/RTP | Allow | No | Voice to SIP trunk | +| 12 | VOICE-to-ALL | VLAN50 (VOICE) | Any | Any | Deny | No | Voice isolated | +| 13 | DMZ-to-ALL | VLAN60 (DMZ) | Any (internal) | Any | Deny | Yes | DMZ cannot reach internal | +| 14 | GUEST-to-INTERNET | VLAN70 (GUEST) | WAN | HTTP/HTTPS/DNS | Allow | No | Guest internet only | +| 15 | GUEST-to-ALL | VLAN70 (GUEST) | Any (internal) | Any | Deny | Yes | Guest isolated | +| 99 | DEFAULT-DENY | Any | Any | Any | Deny | Yes | Catch-all deny | + +*WAN Inbound Rules (Port Forwarding)* +| # | Name | WAN Port | Internal IP | Internal Port | Protocol | Notes | +| --- | --------- | -------- | ------------ | ------------- | -------- | ------------------- | +| 1 | HTTPS-NPM | 443 | 192.168.10.8 | 443 | TCP | Nginx Proxy Manager | +| 2 | HTTP-NPM | 80 | 192.168.10.8 | 80 | TCP | HTTP redirect | + +> **หมายเหตุ**: ER7206 ใช้หลักการ Default Deny - Rules ประมวลผลจากบนลงล่าง + + +**Switch ACL (SG2428P Layer 2 Rules)** + +*Port-Based Access Control* +| # | Name | Source Port | Source MAC/VLAN | Destination | Action | Notes | +| --- | --------------- | --------------- | --------------- | ------------------- | ------ | ------------------------ | +| 1 | CCTV-Isolation | Port 25 (CCTV) | VLAN 40 | VLAN 10,20,30 | Deny | CCTV cannot reach others | +| 2 | Guest-Isolation | Port 5-20 (APs) | VLAN 70 | VLAN 10,20,30,40,50 | Deny | Guest isolation | +| 3 | Voice-QoS | Port 26 (Phone) | VLAN 50 | Any | Allow | QoS priority DSCP EF | + +*Storm Control (per port)* +| Port Range | Broadcast | Multicast | Unknown Unicast | Notes | +| ---------- | --------- | --------- | --------------- | ----------------------- | +| 1-28 | 10% | 10% | 10% | Prevent broadcast storm | + +*Spanning Tree Configuration* +| Setting | Value | Notes | +| -------------------- | --------- | ------------------------------ | +| STP Mode | RSTP | Rapid Spanning Tree | +| Root Bridge Priority | 4096 | SG2428P as root | +| Port Fast | Port 5-24 | Edge ports (APs, endpoints) | +| BPDU Guard | Port 5-24 | Protect against rogue switches | + +> **หมายเหตุ**: SG2428P เป็น L2+ switch, ACL ทำได้จำกัด ให้ใช้ ER7206 เป็น primary firewall + + +**EAP ACL (Omada Controller - Wireless Rules)** + +*SSID: PSLCBP3 (Staff WiFi)* +| # | Name | Source | Destination | Service | Action | Schedule | Notes | +| --- | ------------------- | ---------- | ---------------- | -------- | ------ | -------- | ----------------- | +| 1 | Allow-DNS | Any Client | 8.8.8.8, 1.1.1.1 | DNS (53) | Allow | Always | DNS resolution | +| 2 | Allow-Server | Any Client | 192.168.10.0/24 | Any | Allow | Always | Access to servers | +| 3 | Allow-Printer | Any Client | 192.168.30.222 | 9100,631 | Allow | Always | Print services | +| 4 | Allow-Internet | Any Client | WAN | Any | Allow | Always | Internet access | +| 5 | Block-MGMT | Any Client | 192.168.20.0/24 | Any | Deny | Always | No management | +| 6 | Block-CCTV | Any Client | 192.168.40.0/24 | Any | Deny | Always | No CCTV access | +| 7 | Block-Voice | Any Client | 192.168.50.0/24 | Any | Deny | Always | No Voice access | +| 8 | Block-Client2Client | Any Client | Any Client | Any | Deny | Always | Client isolation | + +*SSID: GUEST (Guest WiFi)* +| # | Name | Source | Destination | Service | Action | Schedule | Notes | +| --- | ------------------- | ---------- | ---------------- | ---------- | ------ | -------- | ------------------ | +| 1 | Allow-DNS | Any Client | 8.8.8.8, 1.1.1.1 | DNS (53) | Allow | Always | DNS resolution | +| 2 | Allow-HTTP | Any Client | WAN | HTTP/HTTPS | Allow | Always | Web browsing | +| 3 | Block-RFC1918 | Any Client | 10.0.0.0/8 | Any | Deny | Always | No private IPs | +| 4 | Block-RFC1918-2 | Any Client | 172.16.0.0/12 | Any | Deny | Always | No private IPs | +| 5 | Block-RFC1918-3 | Any Client | 192.168.0.0/16 | Any | Deny | Always | No internal access | +| 6 | Block-Client2Client | Any Client | Any Client | Any | Deny | Always | Client isolation | + +*Rate Limiting* +| SSID | Download Limit | Upload Limit | Notes | +| ------- | -------------- | ------------ | ----------------------- | +| PSLCBP3 | Unlimited | Unlimited | Staff full speed | +| GUEST | 10 Mbps | 5 Mbps | Guest bandwidth control | + +*Captive Portal (GUEST SSID)* +| Setting | Value | Notes | +| ---------------- | --------------- | ---------------------- | +| Portal Type | Simple Password | Single shared password | +| Session Timeout | 8 Hours | Re-auth after 8 hours | +| Idle Timeout | 30 Minutes | Disconnect if idle | +| Terms of Service | Enabled | User must accept ToS | + +> **หมายเหตุ**: EAP ACL ทำงานที่ Layer 3 บน Omada Controller ช่วยลด load บน ER7206 + + +**Network Topology Diagram** +```mermaid +graph TB + subgraph Internet + WAN[("🌐 Internet
WAN")] + end + + subgraph Router["ER7206 Router"] + R[("🔲 ER7206
192.168.20.1")] + end + + subgraph CoreSwitch["SG2428P Core Switch"] + CS[("🔲 SG2428P
192.168.20.2")] + end + + subgraph ServerSwitch["AMPCOM 2.5G Switch"] + SS[("🔲 AMPCOM
192.168.20.3")] + end + + subgraph Servers["VLAN 10 - Servers"] + QNAP[("💾 QNAP
192.168.10.10")] + ASUSTOR[("💾 ASUSTOR
192.168.10.11")] + end + + subgraph AccessPoints["EAP610 x16"] + AP[("📶 WiFi APs")] + end + + subgraph OtherSwitches["Distribution"] + CCTV_SW[("🔲 TL-SL1226P
CCTV")] + PHONE_SW[("🔲 SG1210P
IP Phone")] + ADMIN_SW[("🔲 ES205G
Admin")] + end + + WAN --> R + R -->|Port 3| CS + CS -->|LAG Port 3-4| SS + SS -->|Port 3-4 LACP| QNAP + SS -->|Port 5-6 LACP| ASUSTOR + SS -->|Port 7| ADMIN_SW + CS -->|Port 5-20| AP + CS -->|SFP 25| CCTV_SW + CS -->|SFP 26| PHONE_SW + CS -->|Port 24| ADMIN_SW +``` + + +**OC200 Omada Controller Configuration** +| Setting | Value | Notes | +| --------------- | -------------------------- | ------------------------------ | +| Controller IP | 192.168.20.10 | Static IP in MGMT VLAN | +| Controller Port | 8043 (HTTPS) | Management Web UI | +| Adoption URL | https://192.168.20.10:8043 | URL for AP adoption | +| Site Name | LCBP3 | Single site configuration | +| Managed Devices | 16x EAP610 | All APs managed centrally | +| Firmware Update | Manual | Test before production rollout | +| Backup Schedule | Weekly (Sunday 2AM) | Auto backup to QNAP | + + +## **2.3 การจัดการ Configuration (ปรับปรุง):** - ใช้ docker-compose.yml สำหรับ environment variables ตามข้อจำกัดของ QNAP - Secrets Management: @@ -40,7 +402,7 @@ specs/01-objectives.md - ต้องแยก configuration ตาม environment (development, staging, production) - Docker Network: ทุก Service จะเชื่อมต่อผ่านเครือข่ายกลางชื่อ lcbp3 เพื่อให้สามารถสื่อสารกันได้ -## **2.3 Core Services:** +## **2.4 Core Services:** - Code Hosting: Gitea (Self-hosted on QNAP) @@ -102,29 +464,29 @@ specs/01-objectives.md - Search Engine: Elasticsearch - Cache: Redis -## **2.4 Business Logic & Consistency (ปรับปรุง):** +## **2.5 Business Logic & Consistency (ปรับปรุง):** -- 2.4.1 Unified Workflow Engine (หลัก): +- 2.5.1 Unified Workflow Engine (หลัก): - ระบบการเดินเอกสารทั้งหมด (Correspondence, RFA, Circulation) ต้อง ใช้ Engine กลางเดียวกัน โดยกำหนด Logic ผ่าน Workflow DSL (JSON Configuration) แทนการเขียน Hard-coded ลงในตาราง - Workflow Versioning (เพิ่ม): ระบบต้องรองรับการกำหนด Version ของ Workflow Definition โดยเอกสารที่เริ่มกระบวนการไปแล้ว (In-progress instances) จะต้องใช้ Workflow Version เดิม จนกว่าจะสิ้นสุดกระบวนการ หรือได้รับคำสั่ง Migrate จาก Admin เพื่อป้องกันความขัดแย้งของ State -- 2.4.2 Separation of Concerns: +- 2.5.2 Separation of Concerns: - Module ต่างๆ (Correspondence, RFA, Circulation) จะเก็บเฉพาะข้อมูลของเอกสาร (Data) ส่วนสถานะและการเปลี่ยนสถานะ (State Transition) จะถูกจัดการโดย Workflow Engine -- 2.4.3 Idempotency & Locking: +- 2.5.3 Idempotency & Locking: - ใช้กลไกเดิมในการป้องกันการทำรายการซ้ำ -- 2.4.4 Optimistic Locking: +- 2.5.4 Optimistic Locking: - ใช้ Version Column ใน Database ควบคู่กับ Redis Lock สำหรับการสร้างเลขที่เอกสาร เพื่อเป็น Safety Net ชั้นสุดท้าย -- 2.4.5 จะไม่มีการใช้ SQL Triggers +- 2.5.5 จะไม่มีการใช้ SQL Triggers - เพื่อป้องกันตรรกะซ่อนเร้น (Hidden Logic) และความซับซ้อนในการดีบัก -## **2.5 Data Migration และ Schema Versioning:** +## **2.6 Data Migration และ Schema Versioning:** - ต้องมี database migration scripts สำหรับทุก schema change โดยใช้ TypeORM migrations - ต้องรองรับ rollback ของ migration ได้ @@ -133,10 +495,11 @@ specs/01-objectives.md - Migration scripts ต้องผ่านการทดสอบใน staging environment ก่อน production - ต้องมี database backup ก่อนทำ migration ใน production -## **2.6 กลยุทธ์ความทนทานและการจัดการข้อผิดพลาด (Resilience & Error Handling Strategy)** +## **2.7 กลยุทธ์ความทนทานและการจัดการข้อผิดพลาด (Resilience & Error Handling Strategy)** -- 2.6.1 Circuit Breaker Pattern: ใช้สำหรับ external service calls (Email, LINE, Elasticsearch) -- 2.6.2 Retry Mechanism: ด้วย exponential backoff สำหรับ transient failures -- 2.6.3 Fallback Strategies: Graceful degradation เมื่อบริการภายนอกล้มเหลว -- 2.6.4 Error Handling: Error messages ต้องไม่เปิดเผยข้อมูล sensitive +- 2.7.1 Circuit Breaker Pattern: ใช้สำหรับ external service calls (Email, LINE, Elasticsearch) +- 2.7.2 Retry Mechanism: ด้วย exponential backoff สำหรับ transient failures +- 2.7.3 Fallback Strategies: Graceful degradation เมื่อบริการภายนอกล้มเหลว +- 2.7.4 Error Handling: Error messages ต้องไม่เปิดเผยข้อมูล sensitive - 2.6.5 Monitoring: Centralized error monitoring และ alerting system + diff --git a/specs/08-infrastructure/Gitea_setting.md b/specs/08-infrastructure/Gitea_setting.md index 6791bab..6a092ec 100644 --- a/specs/08-infrastructure/Gitea_setting.md +++ b/specs/08-infrastructure/Gitea_setting.md @@ -7,25 +7,26 @@ ## กำหนดสิทธิ ```bash -chown -R 1000:1000 /share/Container/gitea/ +chown -R 1000:1000 /share/np-dms/gitea/ [/share/Container/git] # ls -l /share/Container/gitea/etc/app.ini [/share/Container/git] # setfacl -R -m u:1000:rwx /share/Container/gitea/ [/share/Container/git] # setfacl -R -m u:70:rwx /share/Container/git/postgres/ -getfacl /share/Container/git/etc/app.ini -chown -R 1000:1000 /share/Container/gitea/ -ล้าง -setfacl -R -b /share/Container/gitea/ +getfacl /share/np-dms/git/etc/app.ini +chown -R 1000:1000 /share/np-dms/gitea/ +ล้างสิทธิ์ +setfacl -R -b /share/np-dms/gitea/ -chgrp -R administrators /share/Container/gitea/ -chown -R 1000:1000 /share/Container/gitea/etc /share/Container/gitea/lib /share/Container/gitea/backup -setfacl -m u:1000:rwx -m g:1000:rwx /share/Container/gitea/etc /share/Container/gitea/lib /share/Container/gitea/backup +chgrp -R administrators /share/np-dms/gitea/ +chown -R 1000:1000 /share/np-dms/gitea/etc /share/np-dms/gitea/lib /share/np-dms/gitea/backup +setfacl -m u:1000:rwx -m g:1000:rwx /share/np-dms/gitea/etc /share/np-dms/gitea/lib /share/np-dms/gitea/backup ``` ## Docker file ```yml -# File: share/Container/git/docker-compose.yml -# DMS Container v1_4_1 : แยก service และ folder, Application name: git, Servive:gitea +# File: share/np-dms/git/docker-compose.yml +# DMS Container v1_7_0 : แยก service และ folder +# Application name: git, Servive:gitea networks: lcbp3: external: true @@ -74,12 +75,12 @@ services: # Optional: lock install after setup (เปลี่ยนเป็น true เมื่อจบ onboarding) GITEA__security__INSTALL_LOCK: "true" volumes: - - /share/Container/gitea/backup:/backup - - /share/Container/gitea/etc:/etc/gitea - - /share/Container/gitea/lib:/var/lib/gitea + - /share/np-dms/gitea/backup:/backup + - /share/np-dms/gitea/etc:/etc/gitea + - /share/np-dms/gitea/lib:/var/lib/gitea # ให้ repo root ใช้จาก /share/dms-data/gitea_repos - - /share/dms-data/gitea_repos:/var/lib/gitea/git/repositories - - /share/dms-data/gitea_registry:/data/registry + - /share/np-dms/gitea/gitea_repos:/var/lib/gitea/git/repositories + - /share/np-dms/gitea/gitea_registry:/data/registry - /etc/timezone:/etc/timezone:ro - /etc/localtime:/etc/localtime:ro ports: diff --git a/specs/08-infrastructure/Infrastructure Setup.md b/specs/08-infrastructure/Infrastructure Setup.md index ecbec13..a22f8be 100644 --- a/specs/08-infrastructure/Infrastructure Setup.md +++ b/specs/08-infrastructure/Infrastructure Setup.md @@ -1,6 +1,27 @@ # Infrastructure Setup -## 1. Redis Cluster Configuration +> 📍 **Document Version:** v1.8.0 +> 🖥️ **Primary Server:** QNAP TS-473A (Application & Database) +> 💾 **Backup Server:** ASUSTOR AS5403T (Infrastructure & Backup) + +--- + +## Server Role Overview + +| Component | QNAP TS-473A | ASUSTOR AS5403T | +| :-------------------- | :---------------------------- | :--------------------------- | +| **Redis/Cache** | ✅ Primary (Section 1) | ❌ Not deployed | +| **Database** | ✅ Primary MariaDB (Section 2) | ❌ Not deployed | +| **Backend Service** | ✅ NestJS API (Section 3) | ❌ Not deployed | +| **Monitoring** | ❌ Exporters only | ✅ Prometheus/Grafana | +| **Backup Target** | ❌ Source only | ✅ Backup storage (Section 5) | +| **Disaster Recovery** | ✅ Recovery target | ✅ Backup source (Section 7) | + +> 📖 See [monitoring.md](monitoring.md) for ASUSTOR-specific monitoring setup + +--- + +## 1. Redis Configuration (Standalone + Persistence) ### 1.1 Docker Compose Setup ```yaml @@ -8,99 +29,29 @@ version: '3.8' services: - redis-1: - image: redis:7-alpine - container_name: lcbp3-redis-1 - command: redis-server --port 6379 --cluster-enabled yes --cluster-config-file nodes.conf - ports: - - "6379:6379" - - "16379:16379" - volumes: - - redis-1-data:/data - networks: - - lcbp3-network + redis: + image: 'redis:7.2-alpine' + container_name: lcbp3-redis restart: unless-stopped - - redis-2: - image: redis:7-alpine - container_name: lcbp3-redis-2 - command: redis-server --port 6379 --cluster-enabled yes --cluster-config-file nodes.conf - ports: - - "6380:6379" - - "16380:16379" + # AOF: Enabled for durability + # Maxmemory: Prevent OOM + command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD} --maxmemory 1gb --maxmemory-policy noeviction volumes: - - redis-2-data:/data - networks: - - lcbp3-network - restart: unless-stopped - - redis-3: - image: redis:7-alpine - container_name: lcbp3-redis-3 - command: redis-server --port 6379 --cluster-enabled yes --cluster-config-file nodes.conf + - ./redis/data:/data ports: - - "6381:6379" - - "16381:16379" - volumes: - - redis-3-data:/data + - '6379:6379' networks: - - lcbp3-network - restart: unless-stopped - -volumes: - redis-1-data: - redis-2-data: - redis-3-data: - + - lcbp3 + deploy: + resources: + limits: + cpus: '2.0' + memory: 1.5G networks: lcbp3-network: external: true ``` -#### Initialize Cluster -```bash -# Start Redis nodes -docker-compose -f docker-compose-redis.yml up -d - -# Wait for nodes to start -sleep 10 - -# Create cluster -docker exec -it lcbp3-redis-1 redis-cli --cluster create \ - 172.20.0.2:6379 \ - 172.20.0.3:6379 \ - 172.20.0.4:6379 \ - --cluster-replicas 0 - -# Verify cluster -docker exec -it lcbp3-redis-1 redis-cli cluster info -docker exec -it lcbp3-redis-1 redis-cli cluster nodes -``` - -#### Health Check Script -```bash -#!/bin/bash -# scripts/check-redis-cluster.sh - -echo "🔍 Checking Redis Cluster Health..." - -for port in 6379 6380 6381; do - echo "\n📍 Node on port $port:" - - # Check if node is up - docker exec lcbp3-redis-$(($port - 6378)) redis-cli -p 6379 ping - - # Check cluster status - docker exec lcbp3-redis-$(($port - 6378)) redis-cli -p 6379 cluster info | grep cluster_state - - # Check memory usage - docker exec lcbp3-redis-$(($port - 6378)) redis-cli -p 6379 info memory | grep used_memory_human -done - -echo "\n✅ Cluster check complete" -``` - ---- ## 2. Database Configuration diff --git a/specs/08-infrastructure/MariaDB_setting.md b/specs/08-infrastructure/MariaDB_setting.md index cee526b..26d239a 100644 --- a/specs/08-infrastructure/MariaDB_setting.md +++ b/specs/08-infrastructure/MariaDB_setting.md @@ -7,24 +7,30 @@ ## กำหนดสิทธิ ```bash -chown -R 999:999 /share/nap-dms/mariadb/init -chmod 755 /share/nap-dms/mariadb/init -setfacl -R -m u:999:r-x /share/nap-dms/mariadb/init -setfacl -R -d -m u:999:r-x /share/nap-dms/mariadb/init -chown -R 33:33 /share/Container/pma/tmp -chmod 755 /share/Container/pma/tmp -setfacl -R -m u:33:rwx /share/Container/pma/tmp -setfacl -R -d -m u:33:rwx /share/Container/pma/tmp +chown -R 999:999 /share/np-dms/mariadb +chmod -R 755 /share/np-dms/mariadb +setfacl -R -m u:999:rwx /share/np-dms/mariadb +setfacl -R -d -m u:999:rwx /share/np-dms/mariadb + +chown -R 999:999 /share/np-dms/mariadb/init +chmod 755 /share/np-dms/mariadb/init +setfacl -R -m u:999:r-x /share/np-dms/mariadb/init +setfacl -R -d -m u:999:r-x /share/np-dms/mariadb/init + +chown -R 33:33 /share/np-dms/pma/tmp +chmod 755 /share/np-dms/pma/tmp +setfacl -R -m u:33:rwx /share/np-dms/pma/tmp +setfacl -R -d -m u:33:rwx /share/np-dms/pma/tmp chown -R 33:33 /share/dms-data/logs/pma chmod 755 /share/dms-data/logs/pma setfacl -R -m u:33:rwx /share/dms-data/logs/pma setfacl -R -d -m u:33:rwx /share/dms-data/logs/pma -setfacl -R -m u:1000:rwx /share/Container/gitea -setfacl -R -m u:1000:rwx /share/dms-data/gitea_repos -setfacl -R -m u:1000:rwx /share/dms-data/gitea_registry +setfacl -R -m u:1000:rwx /share/nap-dms/gitea +setfacl -R -m u:1000:rwx /share/nap-dms/gitea/gitea_repos +setfacl -R -m u:1000:rwx /share/nap-dms/gitea/gitea_registry ``` ## เพิ่ม database & user สำหรับ Nginx Proxy Manager (NPM) @@ -50,8 +56,9 @@ docker exec -it mariadb mysql -u root -p ## Docker file ```yml -# File: share/Container/mariadb/docker-compose.yml -# DMS Container v1_4_1 : แยก service และ folder,Application name: lcbp3-db, Servive: mariadb, pma +# File: share/nap-dms/mariadb/docker-compose.yml +# DMS Container v1_7_0 : ย้าย folder ไปที่ share/nap-dms/ +# Application name: lcbp3-db, Servive: mariadb, pma x-restart: &restart_policy restart: unless-stopped @@ -85,19 +92,19 @@ services: TZ: "Asia/Bangkok" ports: - "3306:3306" + networks: + - lcbp3 volumes: - - "/share/nap-dms/mariadb/data:/var/lib/mysql" - - "/share/nap-dms/mariadb/my.cnf:/etc/mysql/conf.d/my.cnf:ro" - - "/share/nap-dms/mariadb/init:/docker-entrypoint-initdb.d:ro" + - "/share/np-dms/mariadb/data:/var/lib/mysql" + - "/share/np-dms/mariadb/my.cnf:/etc/mysql/conf.d/my.cnf:ro" + - "/share/np-dms/mariadb/init:/docker-entrypoint-initdb.d:ro" - "/share/dms-data/mariadb/backup:/backup" healthcheck: - test: - ["CMD-SHELL", "mysqladmin ping -h 127.0.0.1 -pCenter#2025 || exit 1"] + test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"] interval: 10s timeout: 5s - retries: 15 - networks: - lcbp3: {} + retries: 3 + start_period: 30s pma: <<: [*restart_policy, *default_logging] @@ -119,20 +126,46 @@ services: MEMORY_LIMIT: "512M" ports: - "89:80" + networks: + - lcbp3 # expose: # - "80" volumes: - - "/share/Container/pma/config.user.inc.php:/etc/phpmyadmin/config.user.inc.php:ro" - - "/share/Container/pma/zzz-custom.ini:/usr/local/etc/php/conf.d/zzz-custom.ini:ro" - - "/share/Container/pma/tmp:/var/lib/phpmyadmin/tmp:rw" + - "/share/np-dms/pma/config.user.inc.php:/etc/phpmyadmin/config.user.inc.php:ro" + - "/share/np-dms/pma/zzz-custom.ini:/usr/local/etc/php/conf.d/zzz-custom.ini:ro" + - "/share/np-dms/pma/tmp:/var/lib/phpmyadmin/tmp:rw" - "/share/dms-data/logs/pma:/var/log/apache2" depends_on: mariadb: condition: service_healthy - networks: - lcbp3: {} networks: lcbp3: external: true + +# chown -R 999:999 /share/np-dms/mariadb/init +# chmod 755 /share/np-dms/mariadb/init +# setfacl -R -m u:999:r-x /share/np-dms/mariadb/init +# setfacl -R -d -m u:999:r-x /share/np-dms/mariadb/init + +# chown -R 33:33 /share/np-dms/pma/tmp +# chmod 755 /share/np-dms/pma/tmp +# setfacl -R -m u:33:rwx /share/np-dms/pma/tmp +# setfacl -R -d -m u:33:rwx /share/np-dms/pma/tmp + +# chown -R 33:33 /share/dms-data/logs/pma +# chmod 755 /share/dms-data/logs/pma +# setfacl -R -m u:33:rwx /share/dms-data/logs/pma +# setfacl -R -d -m u:33:rwx /share/dms-data/logs/pma + +# setfacl -R -m u:1000:rwx /share/Container/gitea +# setfacl -R -m u:1000:rwx /share/dms-data/gitea_repos +# setfacl -R -m u:1000:rwx /share/dms-data/gitea_registry + +# docker exec -it mariadb mysql -u root -p +# CREATE DATABASE npm; +# CREATE USER 'npm'@'%' IDENTIFIED BY 'npm'; +# GRANT ALL PRIVILEGES ON npm.* TO 'npm'@'%'; +# FLUSH PRIVILEGES; + ``` diff --git a/specs/08-infrastructure/NPM_setting.md b/specs/08-infrastructure/NPM_setting.md index 8aa05ab..83a8a4b 100644 --- a/specs/08-infrastructure/NPM_setting.md +++ b/specs/08-infrastructure/NPM_setting.md @@ -33,8 +33,9 @@ setfacl -R -m u:0:rwx /share/Container/npm ## Docker file ```yml -# File: share/Container/npm/docker-compose-npm.yml -# DMS Container v1_4_1 แยก service และ folder, Application name: lcbp3-npm, Servive:npm +# File: share/np-dms/npm/docker-compose-npm.yml +# DMS Container v1_7_0 : ย้าย folder ไปที่ share/np-dms/ +# Application name: lcbp3-npm, Servive:npm x-restart: &restart_policy restart: unless-stopped @@ -73,17 +74,17 @@ services: - lcbp3 - giteanet volumes: - - "/share/Container/npm/data:/data" + - "/share/np-dms/npm/data:/data" - "/share/dms-data/logs/npm:/data/logs" # <-- เพิ่ม logging volume - - "/share/Container/npm/letsencrypt:/etc/letsencrypt" - - "/share/Container/npm/custom:/data/nginx/custom" # <-- สำคัญสำหรับ http_top.conf + - "/share/np-dms/npm/letsencrypt:/etc/letsencrypt" + - "/share/np-dms/npm/custom:/data/nginx/custom" # <-- สำคัญสำหรับ http_top.conf # - "/share/Container/lcbp3/npm/landing:/data/landing:ro" landing: image: nginx:1.27-alpine container_name: landing restart: unless-stopped volumes: - - "/share/Container/npm/landing:/usr/share/nginx/html:ro" + - "/share/np-dms/npm/landing:/usr/share/nginx/html:ro" networks: - lcbp3 networks: @@ -92,7 +93,7 @@ networks: giteanet: external: true name: gitnet - + diff --git a/specs/08-infrastructure/README.md b/specs/08-infrastructure/README.md new file mode 100644 index 0000000..49909af --- /dev/null +++ b/specs/08-infrastructure/README.md @@ -0,0 +1,499 @@ +# 08-Infrastructure + +คู่มือการตั้งค่า Infrastructure สำหรับ **NAP-DMS LCBP3** (Laem Chabang Port Phase 3 - Document Management System) + +> 📍 **Platform:** QNAP (Container Station) + ASUSTOR (Portainer) +> 🌐 **Domain:** `*.np-dms.work` (IP: 159.192.126.103) +> 🔒 **Network:** `lcbp3` (Docker External Network) +> 📄 **Version:** v1.8.0 (aligned with 01-02-architecture.md) + +--- + +## 🏢 Hardware Infrastructure + +### Server Role Separation + +#### QNAP TS-473A +| (Application & Database Server) | | | +| :------------------------------ | :---------------- | :-------------------- | +| ✔ Application Runtime | ✔ API / Web | ✔ Database (Primary) | +| ✔ High CPU / RAM usage | ✔ Worker / Queue | ✖ No long-term backup | +| Container Station (UI) | 32GB RAM (Capped) | AMD Ryzen V1500B | + +#### ASUSTOR AS5403T +| (Infrastructure & Backup Server) | | | +| :------------------------------- | :---------------- | :------------------- | +| ✔ File Storage | ✔ Backup Target | ✔ Docker Infra | +| ✔ Monitoring / Registry | ✔ Log Aggregation | ✖ No heavy App logic | +| Portainer (Manage All) | 16GB RAM | Intel Celeron @2GHz | + +### Servers Specification + +| Device | Model | CPU | RAM | Resource Policy | Role | +| :---------- | :------ | :---------------------- | :--- | :------------------ | :--------------------- | +| **QNAP** | TS-473A | AMD Ryzen V1500B | 32GB | **Strict Limits** | Application, DB, Cache | +| **ASUSTOR** | AS5403T | Intel Celeron @ 2.00GHz | 16GB | **Moderate Limits** | Infra, Backup, Monitor | + +### Service Distribution by Server + +#### QNAP TS-473A (Application Stack) + +| Category | Service | Strategy | Resource Limit (Est.) | +| :-------------- | :------------------------ | :------------------------------ | :-------------------- | +| **Web App** | Next.js (Frontend) | Single Instance | 2.0 CPU / 2GB RAM | +| **Backend API** | NestJS | **2 Replicas** (Load Balanced) | 2.0 CPU / 1.5GB RAM | +| **Database** | MariaDB (Primary) | Performance Tuned (Buffer Pool) | 4.0 CPU / 5GB RAM | +| **Worker** | Redis + BullMQ Worker | **Standalone + AOF** | 2.0 CPU / 1.5GB RAM | +| **Search** | Elasticsearch | **Heap Locked (2GB)** | 2.0 CPU / 4GB RAM | +| **API Gateway** | NPM (Nginx Proxy Manager) | SSL Termination | 1.0 CPU / 512MB RAM | +| **Workflow** | n8n | Automation | 1.0 CPU / 1GB RAM | +| **Code** | Gitea | Git Repository | 1.0 CPU / 1GB RAM | + +#### ASUSTOR AS5403T (Infrastructure Stack) +| Category | Service | Notes | +| :--------------- | :------------------ | :------------------------------ | +| **File Storage** | NFS / SMB | Shared volumes for backup | +| **Backup** | Restic / Borg | Pull-based Backup (More Safe) | +| **Docker Infra** | Registry, Portainer | Container image registry, mgmt | +| **Monitoring** | Uptime Kuma | Service availability monitoring | +| **Metrics** | Prometheus, Grafana | Cross-Server Scraping | +| **Log** | Loki / Syslog | Centralized logging | + +--- + +## 🔄 Data Flow Architecture + +``` +┌──────────────┐ +│ User │ +└──────┬───────┘ + │ HTTPS (443) + ▼ +┌──────────────────────────────────────────────────────────────┐ +│ QNAP TS-473A │ +│ ┌─────────────────────────────────────────────────────────┐ │ +│ │ Nginx Proxy Manager (NPM) │ │ +│ │ SSL Termination + Round Robin LB │ │ +│ └───────────────────────┬─────────────────────────────────┘ │ +│ │ │ +│ ┌───────────────────────▼─────────────────────────────────┐ │ +│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ +│ │ │ Next.js │───▶│ NestJS │ │ NestJS │ │ │ +│ │ │ (Frontend) │ │ (Replica 1)│ │ (Replica 2)│ │ │ +│ │ └──────────────┘ └──────┬───────┘ └──────┬──────┘ │ │ +│ │ │ │ │ │ +│ │ ┌────────────────────────┼─────────────────┼ │ │ +│ │ ▼ ▼ ▼ │ │ +│ │ ┌──────────┐ ┌────────────┐ ┌─────────────┐ │ │ +│ │ │ MariaDB │ │ Redis │ │Elasticsearch│ │ │ +│ │ │(Primary) | │ (Persist.) │ │ (Search) │ │ │ +│ │ └────┬─────┘ └────────────┘ └─────────────┘ │ │ +│ └───────┼─────────────────────────────────────────────────┘ │ +│ │ │ +└──────────┼───────────────────────────────────────────────────┘ + │ Local Dump -> Restic Pull (Cross-Server) + ▼ +┌──────────────────────────────────────────────────────────────┐ +│ ASUSTOR AS5403T │ +│ ┌──────────────────────────────────────────────────────────┐│ +│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ││ +│ │ │ Backup │ │ Registry │ │ Uptime │ ││ +│ │ │ (Restic) │ │ (Docker) │ │ Kuma │ ││ +│ │ └──────────┘ └──────────┘ └──────────┘ ││ +│ │ ││ +│ │ ┌──────────┐ ┌────────────┐ ┌──────────┐ ││ +│ │ │Prometheus│ ──▶│ Grafana │ │ Loki │ ││ +│ │ │(Metrics) │ │(Dashboard) │ │ (Logs) │ ││ +│ │ └──────────┘ └────────────┘ └──────────┘ ││ +│ │ ││ +│ │ ┌───────────────────────────────────────────┐ ││ +│ │ │ NFS / SMB Shared Storage │ ││ +│ │ │ (Backup Volume) │ ││ +│ │ └───────────────────────────────────────────┘ ││ +│ └──────────────────────────────────────────────────────────┘│ +└──────────────────────────────────────────────────────────────┘ +``` + +--- + +## 🖥️ Docker Management Architecture + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ Portainer (ASUSTOR) │ +│ https://portainer.np-dms.work │ +├─────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────────────────┐ ┌─────────────────────────────┐ │ +│ │ Manage Infra Stack │ │ Remote Docker Endpoint │ │ +│ │ (Local - ASUSTOR) │ │ (QNAP App Stack) │ │ +│ ├─────────────────────────────┤ ├─────────────────────────────┤ │ +│ │ • Registry │ │ • Next.js (Frontend) │ │ +│ │ • Prometheus │ │ • NestJS (Backend) │ │ +│ │ • Grafana │ │ • MariaDB │ │ +│ │ • Uptime Kuma │ │ • Redis │ │ +│ │ • Loki │ │ • Elasticsearch │ │ +│ │ • Backup (Restic) │ │ • NPM │ │ +│ │ • ClamAV │ │ • Gitea │ │ +│ │ • node-exporter │ │ • n8n │ │ +│ │ • cAdvisor │ │ • phpMyAdmin │ │ +│ └─────────────────────────────┘ └─────────────────────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────────────┘ + +Container Station (QNAP): ใช้สำหรับ local UI management เท่านั้น +Portainer (ASUSTOR): ใช้เป็น centralized management ทั้ง 2 servers +``` + +--- + +## 🔐 Security Zones + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ SECURITY ZONES │ +├─────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────────────────────────────────────────────────────┐ │ +│ │ 🌐 PUBLIC ZONE │ │ +│ │ ───────────────────────────────────────────────────────────── │ │ +│ │ • Nginx Proxy Manager (NPM) │ │ +│ │ • HTTPS (Port 443 only) │ │ +│ │ • SSL/TLS Termination │ │ +│ │ • Rate Limiting │ │ +│ └─────────────────────────────────────────────────────────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌─────────────────────────────────────────────────────────────────┐ │ +│ │ 📱 APPLICATION ZONE (QNAP - VLAN 10) │ │ +│ │ ───────────────────────────────────────────────────────────── │ │ +│ │ • Next.js (Frontend) │ │ +│ │ • NestJS (Backend API) │ │ +│ │ • n8n Workflow │ │ +│ │ • Gitea │ │ +│ │ • Internal API communication only │ │ +│ └─────────────────────────────────────────────────────────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌─────────────────────────────────────────────────────────────────┐ │ +│ │ 💾 DATA ZONE (QNAP - Internal Only) │ │ +│ │ ───────────────────────────────────────────────────────────── │ │ +│ │ • MariaDB (Primary Database) │ │ +│ │ • Redis (Cache/Queue) │ │ +│ │ • Elasticsearch (Search) │ │ +│ │ • No public access - Backend only │ │ +│ └─────────────────────────────────────────────────────────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌─────────────────────────────────────────────────────────────────┐ │ +│ │ 🛠️ INFRASTRUCTURE ZONE (ASUSTOR - VLAN 10) │ │ +│ │ ───────────────────────────────────────────────────────────── │ │ +│ │ • Backup (Restic/Borg) │ │ +│ │ • Docker Registry │ │ +│ │ • Prometheus + Grafana │ │ +│ │ • Uptime Kuma │ │ +│ │ • Loki (Logs) │ │ +│ │ • NFS/SMB Storage │ │ +│ │ • Access via MGMT VLAN only │ │ +│ └─────────────────────────────────────────────────────────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────────────┘ +``` + +--- + +## 🌐 Network Architecture (VLAN) + +### VLAN Networks + +| VLAN ID | Name | Gateway/Subnet | DHCP Range | Purpose | +| :------ | :----- | :-------------- | :----------------- | :-------------------- | +| 10 | SERVER | 192.168.10.1/24 | Static | Servers (NAS, Docker) | +| 20 | MGMT | 192.168.20.1/24 | Static | Network Management | +| 30 | USER | 192.168.30.1/24 | .10-.254 (7 days) | Staff Devices | +| 40 | CCTV | 192.168.40.1/24 | .100-.150 (7 days) | Surveillance | +| 50 | VOICE | 192.168.50.1/24 | .201-.250 (7 days) | IP Phones | +| 60 | DMZ | 192.168.60.1/24 | Static | Public Services | +| 70 | GUEST | 192.168.70.1/24 | .200-.250 (1 day) | Guest WiFi | + +### Static IP Allocation (Key Devices) + +| VLAN | Device | IP Address | Role | +| :--------- | :------ | :------------- | :------------------ | +| SERVER(10) | QNAP | 192.168.10.8 | App/DB Server | +| SERVER(10) | ASUSTOR | 192.168.10.9 | Infra/Backup Server | +| MGMT(20) | ER7206 | 192.168.20.1 | Gateway/Router | +| MGMT(20) | SG2428P | 192.168.20.2 | Core Switch | +| MGMT(20) | AMPCOM | 192.168.20.3 | Server Switch | +| MGMT(20) | OC200 | 192.168.20.250 | Omada Controller | +| USER(30) | Printer | 192.168.30.222 | Kyocera CS3554ci | +| CCTV(40) | NVR | 192.168.40.100 | HikVision NVR | + +### Network Equipment + +| Device | Model | Ports | IP Address | Role | +| :------------------ | :----------------- | :---------------------- | :------------- | :--------------- | +| **Router** | TP-LINK ER7206 | 1 SFP + WAN + 4×GbE | 192.168.20.1 | Gateway/Firewall | +| **Core Switch** | TP-LINK SG2428P | 24×GbE PoE+ + 4×SFP | 192.168.20.2 | Core/PoE Switch | +| **Server Switch** | AMPCOM | 8×2.5GbE + 1×10G SFP+ | 192.168.20.3 | Server Uplink | +| **Admin Switch** | TP-LINK ES205G | 5×GbE (Unmanaged) | N/A | Admin PC | +| **CCTV Switch** | TP-LINK TL-SL1226P | 24×PoE+ 100Mbps + 2×SFP | 192.168.20.4 | CCTV PoE | +| **IP Phone Switch** | TP-LINK SG1210P | 8×PoE+ + 1×GbE + 1×SFP | 192.168.20.5 | VoIP | +| **Controller** | TP-LINK OC200 | Omada Controller | 192.168.20.250 | AP Management | + +> 📖 Detailed port mappings and ACL rules: see [Securities.md](Securities.md) and [แผนผัง Network.md](แผนผัง%20Network.md) + +--- + +## 🔗 Network Topology + +```mermaid +graph TB + subgraph Internet + WAN[("🌐 Internet
WAN")] + end + + subgraph Router["ER7206 Router"] + R[("🔲 ER7206
192.168.20.1")] + end + + subgraph CoreSwitch["SG2428P Core Switch"] + CS[("🔲 SG2428P
192.168.20.2")] + end + + subgraph ServerSwitch["AMPCOM 2.5G Switch"] + SS[("🔲 AMPCOM
192.168.20.3")] + end + + subgraph Servers["VLAN 10 - Servers"] + QNAP[("💾 QNAP (App/DB)
192.168.10.8")] + ASUSTOR[("💾 ASUSTOR (Infra)
192.168.10.9")] + end + + subgraph AccessPoints["EAP610 x16"] + AP[("📶 WiFi APs")] + end + + subgraph OtherSwitches["Distribution"] + CCTV_SW[("🔲 TL-SL1226P
CCTV")] + PHONE_SW[("🔲 SG1210P
IP Phone")] + ADMIN_SW[("🔲 ES205G
Admin")] + end + + WAN --> R + R -->|Port 3| CS + CS -->|LAG Port 3-4| SS + SS -->|Port 3-4 LACP| QNAP + SS -->|Port 5-6 LACP| ASUSTOR + SS -->|Port 8| ADMIN_SW + CS -->|Port 5-20| AP + CS -->|SFP 25| CCTV_SW + CS -->|SFP 26| PHONE_SW + CS -->|Port 24| ADMIN_SW +``` + +--- + +## 📁 สารบัญเอกสาร + +| ไฟล์ | คำอธิบาย | +| :--------------------------------------------------- | :--------------------------------------------------------------------------- | +| [Infrastructure Setup.md](Infrastructure%20Setup.md) | ภาพรวมการตั้งค่าโครงสร้างพื้นฐาน (Redis, MariaDB, Backend, Monitoring, Backup, DR) | +| [แผนผัง Network.md](แผนผัง%20Network.md) | แผนผัง Network Architecture และ Container Services | +| [Securities.md](Securities.md) | VLAN Segmentation, Firewall Rules, ACL (ER7206, SG2428P, EAP) | + +--- + +## 🐳 Docker Compose Files + +### Core Services (QNAP) + +| ไฟล์ | Application | Services | Path บน QNAP | +| :--------------------------------------- | :---------- | :---------------------------------------- | :------------------------ | +| [MariaDB_setting.md](MariaDB_setting.md) | `lcbp3-db` | `mariadb`, `pma` | `/share/np-dms/mariadb/` | +| [NPM_setting.md](NPM_setting.md) | `lcbp3-npm` | `npm`, `landing` | `/share/np-dms/npm/` | +| [Service_setting.md](Service_setting.md) | `services` | `cache` (Redis), `search` (Elasticsearch) | `/share/np-dms/services/` | +| [Gitea_setting.md](Gitea_setting.md) | `git` | `gitea` | `/share/np-dms/gitea/` | +| [n8n_setting.md](n8n_setting.md) | `n8n` | `n8n` | `/share/np-dms/n8n/` | + +### Infrastructure Services (ASUSTOR) + +| ไฟล์ | Application | Services | Path บน ASUSTOR | +| :----------------------------- | :----------------- | :--------------------------------------------------- | :---------------------------- | +| [monitoring.md](monitoring.md) | `lcbp3-monitoring` | `prometheus`, `grafana`, `node-exporter`, `cadvisor` | `/volume1/np-dms/monitoring/` | +| *(NEW)* backup.md | `lcbp3-backup` | `restic`, `borg` | `/volume1/np-dms/backup/` | +| *(NEW)* registry.md | `lcbp3-registry` | `registry` | `/volume1/np-dms/registry/` | +| *(NEW)* uptime-kuma.md | `lcbp3-uptime` | `uptime-kuma` | `/volume1/np-dms/uptime/` | + +--- + +## 🌐 Domain Mapping (NPM Proxy) + +### Application Domains (QNAP) + +| Domain | Service | Port | Host | Description | +| :-------------------- | :------- | :--- | :--- | :------------------------ | +| `lcbp3.np-dms.work` | frontend | 3000 | QNAP | Frontend Next.js | +| `backend.np-dms.work` | backend | 3000 | QNAP | Backend NestJS API | +| `pma.np-dms.work` | pma | 80 | QNAP | phpMyAdmin | +| `git.np-dms.work` | gitea | 3000 | QNAP | Gitea Git Server | +| `n8n.np-dms.work` | n8n | 5678 | QNAP | n8n Workflow Automation | +| `npm.np-dms.work` | npm | 81 | QNAP | Nginx Proxy Manager Admin | + +### Infrastructure Domains (ASUSTOR) + +| Domain | Service | Port | Host | Description | +| :----------------------- | :---------- | :--- | :------ | :----------------- | +| `grafana.np-dms.work` | grafana | 3000 | ASUSTOR | Grafana Dashboard | +| `prometheus.np-dms.work` | prometheus | 9090 | ASUSTOR | Prometheus Metrics | +| `uptime.np-dms.work` | uptime-kuma | 3001 | ASUSTOR | Uptime Monitoring | +| `portainer.np-dms.work` | portainer | 9443 | ASUSTOR | Docker Management | +| `registry.np-dms.work` | registry | 5000 | ASUSTOR | Docker Registry | + +--- + +## ⚙️ Core Services Summary + +### QNAP Services (Application) + +| Service | Technology | Port | Purpose | +| :---------------- | :----------------- | :----- | :------------------------------------------- | +| **Reverse Proxy** | NPM | 80/443 | SSL Termination, Domain Routing | +| **Backend API** | NestJS | 3000 | REST API, Business Logic, Workflow Engine | +| **Frontend** | Next.js | 3000 | Web UI (App Router, React, Tailwind, Shadcn) | +| **Database** | MariaDB 11.8 | 3306 | Primary Relational Database | +| **Cache** | Redis 7.2 | 6379 | Caching, Session, BullMQ | +| **Search** | Elasticsearch 8.11 | 9200 | Full-text Search | +| **Code Hosting** | Gitea | 3000 | Git Repository (Self-hosted) | +| **Workflow** | n8n | 5678 | Automation, Integrations (LINE, Email) | + +### ASUSTOR Services (Infrastructure) + +| Service | Technology | Port | Purpose | +| :--------------- | :-------------- | :--- | :---------------------------- | +| **Metrics** | Prometheus | 9090 | Metrics Collection | +| **Dashboard** | Grafana | 3000 | Visualization, Alerting | +| **Uptime** | Uptime Kuma | 3001 | Service Availability Monitor | +| **Registry** | Docker Registry | 5000 | Private Container Images | +| **Management** | Portainer | 9443 | Centralized Docker Management | +| **Host Metrics** | node-exporter | 9100 | CPU, Memory, Disk metrics | +| **Container** | cAdvisor | 8080 | Container resource metrics | +| **Backup** | Restic/Borg | N/A | Automated Backups | + +--- + +## 🔧 Quick Reference + +### Docker Commands (QNAP - Container Station) + +```bash +# ดู containers ทั้งหมด +docker ps -a + +# ดู logs +docker logs -f + +# เข้าไปใน container +docker exec -it sh + +# Restart service +docker restart +``` + +### Docker Commands (ASUSTOR - Portainer) + +```bash +# Remote Docker endpoint connection +# Configure via Portainer UI: Settings > Environments > Add Environment + +# Direct SSH to ASUSTOR +ssh admin@192.168.10.9 + +# Portainer API (Optional) +curl -X GET https://portainer.np-dms.work/api/endpoints \ + -H "X-API-Key: " +``` + +### Network + +```bash +# สร้าง external network (ครั้งแรก) - ต้องทำทั้ง 2 servers +# On QNAP: +docker network create lcbp3 + +# On ASUSTOR: +docker network create lcbp3 + +# ดู network +docker network ls +docker network inspect lcbp3 +``` + +### MariaDB + +```bash +# เข้า MySQL CLI (QNAP) +docker exec -it mariadb mysql -u root -p + +# Backup database (QNAP -> ASUSTOR) +docker exec mariadb mysqldump -u root -p lcbp3 > backup.sql +# Copy to ASUSTOR via NFS/SCP +``` + +--- + +## ⚙️ Environment Variables + +ตัวแปรสำคัญที่ใช้ร่วมกันทุก Service: + +| Variable | Value | Description | +| :----------------------- | :------------- | :--------------------- | +| `TZ` | `Asia/Bangkok` | Timezone | +| `MYSQL_HOST` / `DB_HOST` | `mariadb` | MariaDB hostname | +| `MYSQL_PORT` / `DB_PORT` | `3306` | MariaDB port | +| `REDIS_HOST` | `cache` | Redis hostname | +| `ELASTICSEARCH_HOST` | `search` | Elasticsearch hostname | + +> ⚠️ **Security Note:** Sensitive secrets (Password, Keys) ต้องใช้ `docker-compose.override.yml` (gitignored) หรือ Docker secrets - ห้ามระบุใน docker-compose.yml หลัก + +--- + +## 📚 เอกสารเสริม + +| ไฟล์ | คำอธิบาย | +| :------------------------------- | :------------------------------------------------ | +| [Git_command.md](Git_command.md) | คำสั่ง Git + Gitea Cheat Sheet | +| [lcbp3-db.md](lcbp3-db.md) | Docker Compose สำหรับ MariaDB (alternative version) | + +--- + +## 📋 Checklist สำหรับการติดตั้งใหม่ + +### Phase 1: Network & Infrastructure +1. [ ] Configure VLANs on ER7206 Router +2. [ ] Configure Switch Profiles on SG2428P +3. [ ] Configure Static IPs (QNAP: .8, ASUSTOR: .9) + +### Phase 2: ASUSTOR Setup (Infra) +1. [ ] Create Docker Network: `docker network create lcbp3` +2. [ ] Deploy Portainer & Registry +3. [ ] Deploy Monitoring Stack (`prometheus.yml` with QNAP IP target) +4. [ ] Verify Prometheus can reach QNAP services + +### Phase 3: QNAP Setup (App) +1. [ ] Create Docker Network: `docker network create lcbp3` +2. [ ] Create `.env` file with secure passwords +3. [ ] Deploy **MariaDB** (Wait for init) +4. [ ] Deploy **Redis Standalone** (Check AOF is active) +5. [ ] Deploy **Elasticsearch** (Check Heap limit) +6. [ ] Deploy **NPM** & App Services (Backend/Frontend) +7. [ ] Verify Internal Load Balancing (Backend Replicas) + +### Phase 4: Backup & Security +1. [ ] Configure Restic on ASUSTOR to pull from QNAP +2. [ ] Set Resource Limits (Check `docker stats`) +3. [ ] Configure Firewall ACL Rules + +--- + +> 📝 **หมายเหตุ:** เอกสารทั้งหมดอ้างอิงจาก Architecture Document **v1.8.0** และ DMS Container Schema **v1.7.0** diff --git a/specs/08-infrastructure/Rev01/README.md b/specs/08-infrastructure/Rev01/README.md new file mode 100644 index 0000000..d109a3e --- /dev/null +++ b/specs/08-infrastructure/Rev01/README.md @@ -0,0 +1,106 @@ +# 08-Infrastructure + +คู่มือการตั้งค่า Infrastructure สำหรับ **NAP-DMS LCBP3** (Laem Chabang Port Phase 3 - Document Management System) + +> 📍 **Platform:** QNAP (Container Station) + ASUSTOR (Portainer) +> 🌐 **Domain:** `*.np-dms.work` (IP: 159.192.126.103) +> 🔒 **Network:** `lcbp3` (Docker External Network) +> 📄 **Version:** v2.0.0 (Refactored for Stability) + +--- + +## 🏢 Hardware Infrastructure + +### Server Role Separation + +#### QNAP TS-473A +| (Application & Database Server)||| +| :--------------------- | :---------------- | :-------------------- | +| ✔ Application Runtime |✔ API / Web | ✔ Database (Primary) | +| ✔ High CPU / RAM usage | ✔ Worker / Queue | ✖ No long-term backup | +| Container Station (UI) | 32GB RAM (Capped) | AMD Ryzen V1500B | + +#### ASUSTOR AS5403T +| (Infrastructure & Backup Server) ||| +| :--------------------- | :---------------- | :------------------- | +| ✔ File Storage | ✔ Backup Target | ✔ Docker Infra | +|✔ Monitoring / Registry | ✔ Log Aggregation | ✖ No heavy App logic | +| Portainer (Manage All) | 16GB RAM | Intel Celeron @2GHz | + +### Servers Specification & Resource Allocation + +| Device | Model | CPU | RAM | Resource Policy | Role | +| :---------- | :------ | :---------------------- | :--- | :------------------ | :--------------------- | +| **QNAP** | TS-473A | AMD Ryzen V1500B | 32GB | **Strict Limits** | Application, DB, Cache | +| **ASUSTOR** | AS5403T | Intel Celeron @ 2.00GHz | 16GB | **Moderate Limits** | Infra, Backup, Monitor | + +### Service Distribution by Server + +#### QNAP TS-473A (Application Stack) + +| Category | Service | Strategy | Resource Limit (Est.) | +| :-------------- | :------------------------ | :------------------------------ | :-------------------- | +| **Web App** | Next.js (Frontend) | Single Instance | 2.0 CPU / 2GB RAM | +| **Backend API** | NestJS | **2 Replicas** (Load Balanced) | 2.0 CPU / 1.5GB RAM | +| **Database** | MariaDB (Primary) | Performance Tuned (Buffer Pool) | 4.0 CPU / 5GB RAM | +| **Worker** | Redis + BullMQ Worker | **Standalone + AOF** | 2.0 CPU / 1.5GB RAM | +| **Search** | Elasticsearch | **Heap Locked (2GB)** | 2.0 CPU / 4GB RAM | +| **API Gateway** | NPM (Nginx Proxy Manager) | SSL Termination | 1.0 CPU / 512MB RAM | +| **Workflow** | n8n | Automation | 1.0 CPU / 1GB RAM | +| **Code** | Gitea | Git Repository | 1.0 CPU / 1GB RAM | + +#### ASUSTOR AS5403T (Infrastructure Stack) + +| Category | Service | Notes | +| :--------------- | :------------------ | :------------------------------ | +| **File Storage** | NFS / SMB | Shared volumes for backup | +| **Backup** | Restic / Borg | Pull-based Backup (More Safe) | +| **Docker Infra** | Registry, Portainer | Container image registry, mgmt | +| **Monitoring** | Uptime Kuma | Service availability monitoring | +| **Metrics** | Prometheus, Grafana | Cross-Server Scraping | +| **Log** | Loki / Syslog | Centralized logging | + +--- + +## 🔄 Data Flow Architecture +┌──────────────┐ +│ User │ +└──────┬───────┘ + │ HTTPS (443) + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ QNAP TS-473A │ +│ ┌─────────────────────────────────────────────────────────┐ │ +│ │ Nginx Proxy Manager (NPM) │ │ +│ │ SSL Termination + Round Robin LB │ │ +│ └───────────────────────┬─────────────────────────────────┘ │ +│ │ │ +│ ┌───────────────────────▼─────────────────────────────────┐ │ +│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ | │ +│ │ │ Next.js │─▶│ NestJS │ │ NestJS │ | │ +│ │ │ (Frontend) │ │ (Replica 1) │ │ (Replica 2) │ │ │ +│ │ └──────────────┘ └──────┬───────┘ └──────┬───────┘ │ │ +│ │ │ │ │ │ +│ │ ┌─────────────────────────┼────────────────┼────┐ │ │ +│ │ ▼ ▼ ▼ ▼ │ │ +│ │ ┌──────────┐ ┌──────────┐ ┌─────────────┐ │ │ +│ │ │ MariaDB │ │ Redis │ │Elasticsearch│ │ │ +│ │ │ (Primary)│ │(Persist.)│ │ (Search) │ │ │ +│ │ └────┬─────┘ └──────────┘ └─────────────┘ │ │ +│ └──────┼──────────────────────────────────────────────────┘ │ +│ └──────┼────────────────────────────────────────────────────┘ + | Local Dump -> Restic Pull (Cross-Server) + ▼ +┌──────────────────────────────────────────────────────────────┐ +│ ASUSTOR AS5403T │ +│ ┌──────────────────────────────────────────────────────────┐ │ +│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ +│ │ │ Backup │ │ Registry │ │ Uptime │ │ │ +│ │ │ (Restic) │ │ (Docker) │ │ Kuma │ │ │ +│ │ └──────────┘ └──────────┘ └──────────┘ │ │ +│ │ │ │ +│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ +│ │ │Prometheus│───▶│ Grafana │ │ Loki │ │ │ +│ │ │(Scraper) │ │(Dashboard)│ │ (Logs) │ │ │ +│ │ └──────────┘ └──────────┘ └──────────┘ ││ +│ └──────────────────────────────────────────────────────────┘│ └──────────────────────────────────────────────────────────────┘ diff --git a/specs/08-infrastructure/Service_setting.md b/specs/08-infrastructure/Service_setting.md index 7840c92..666d81d 100644 --- a/specs/08-infrastructure/Service_setting.md +++ b/specs/08-infrastructure/Service_setting.md @@ -36,24 +36,25 @@ ```bash # สร้าง Directory -mkdir -p /share/Container/services/cache/data -mkdir -p /share/Container/services/search/data +mkdir -p /share/np-dms/services/cache/data +mkdir -p /share/np-dms/services/search/data # กำหนดสิทธิ์ให้ตรงกับ User ID ใน Container # Redis (UID 999) -chown -R 999:999 /share/Container/services/cache/data -chmod -R 750 /share/Container/services/cache/data +chown -R 999:999 /share/np-dms/services/cache/data +chmod -R 750 /share/np-dms/services/cache/data # Elasticsearch (UID 1000) -chown -R 1000:1000 /share/Container/services/search/data -chmod -R 750 /share/Container/services/search/data +chown -R 1000:1000 /share/np-dms/services/search/data +chmod -R 750 /share/np-dms/services/search/data ``` ## Docker file ```yml -# File: /share/Container/services/docker-compose.yml (หรือไฟล์ที่คุณใช้รวม) -# DMS Container v1_4_1: เพิ่ม Application name: services, Services 'cache' (Redis) และ 'search' (Elasticsearch) +# File: /share/np-dms/services/docker-compose.yml (หรือไฟล์ที่คุณใช้รวม) +# DMS Container v1_7_0: เพิ่ม Application name: services +#Services 'cache' (Redis) และ 'search' (Elasticsearch) x-restart: &restart_policy restart: unless-stopped @@ -93,7 +94,7 @@ services: networks: - lcbp3 # เชื่อมต่อ network ภายในเท่านั้น volumes: - - "/share/Container/cache/data:/data" # Map volume สำหรับเก็บข้อมูล (ถ้าต้องการ persistence) + - "/share/np-dms/services/cache/data:/data" # Map volume สำหรับเก็บข้อมูล (ถ้าต้องการ persistence) healthcheck: test: ["CMD", "redis-cli", "ping"] # ตรวจสอบว่า service พร้อมใช้งาน interval: 10s @@ -132,7 +133,7 @@ services: networks: - lcbp3 # เชื่อมต่อ network ภายใน (NPM จะ proxy port 9200 จากภายนอก) volumes: - - "/share/Container/search/data:/usr/share/elasticsearch/data" # Map volume สำหรับเก็บ data/indices + - "/share/np-dms/services/search/data:/usr/share/elasticsearch/data" # Map volume สำหรับเก็บ data/indices healthcheck: # รอจนกว่า cluster health จะเป็น yellow หรือ green test: ["CMD-SHELL", "curl -s http://localhost:9200/_cluster/health | grep -q '\"status\":\"green\"\\|\\\"status\":\"yellow\"'"] diff --git a/specs/08-infrastructure/monitoring.md b/specs/08-infrastructure/monitoring.md new file mode 100644 index 0000000..04f5698 --- /dev/null +++ b/specs/08-infrastructure/monitoring.md @@ -0,0 +1,455 @@ +# การติดตั้ง Monitoring Stack บน ASUSTOR + +## **📝 คำอธิบายและข้อควรพิจารณา** + +> ⚠️ **หมายเหตุ**: Monitoring Stack ทั้งหมดติดตั้งบน **ASUSTOR AS5403T** ไม่ใช่ QNAP +> เพื่อแยก Application workload ออกจาก Infrastructure/Monitoring workload + +Stack สำหรับ Monitoring ประกอบด้วย: + +| Service | Port | Purpose | Host | +| :---------------- | :--- | :-------------------------------- | :------ | +| **Prometheus** | 9090 | เก็บ Metrics และ Time-series data | ASUSTOR | +| **Grafana** | 3000 | Dashboard สำหรับแสดงผล Metrics | ASUSTOR | +| **Node Exporter** | 9100 | เก็บ Metrics ของ Host system | Both | +| **cAdvisor** | 8080 | เก็บ Metrics ของ Docker containers | Both | +| **Uptime Kuma** | 3001 | Service Availability Monitoring | ASUSTOR | +| **Loki** | 3100 | Log aggregation | ASUSTOR | + +--- + +## 🏗️ Architecture Overview + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ ASUSTOR AS5403T (Monitoring Hub) │ +├─────────────────────────────────────────────────────────────────────────┤ +│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ +│ │ Prometheus │───▶│ Grafana │ │ Uptime Kuma │ │ +│ │ :9090 │ │ :3000 │ │ :3001 │ │ +│ └──────┬──────┘ └─────────────┘ └─────────────┘ │ +│ │ │ +│ │ Scrape Metrics │ +│ ▼ │ +│ ┌─────────────┐ ┌─────────────┐ │ +│ │node-exporter│ │ cAdvisor │ │ +│ │ :9100 │ │ :8080 │ │ +│ │ (Local) │ │ (Local) │ │ +│ └─────────────┘ └─────────────┘ │ +└─────────────────────────────────────────────────────────────────────────┘ + │ Remote Scrape + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ QNAP TS-473A (App Server) │ +├─────────────────────────────────────────────────────────────────────────┤ +│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ +│ │node-exporter│ │ cAdvisor │ │ Backend │ │ +│ │ :9100 │ │ :8080 │ │ /metrics │ │ +│ └─────────────┘ └─────────────┘ └─────────────┘ │ +└─────────────────────────────────────────────────────────────────────────┘ +``` + +--- + +## กำหนดสิทธิ (บน ASUSTOR) + +```bash +# SSH เข้า ASUSTOR +ssh admin@192.168.10.9 + +# สร้าง Directory +mkdir -p /volume1/np-dms/monitoring/prometheus/data +mkdir -p /volume1/np-dms/monitoring/prometheus/config +mkdir -p /volume1/np-dms/monitoring/grafana/data +mkdir -p /volume1/np-dms/monitoring/uptime-kuma/data +mkdir -p /volume1/np-dms/monitoring/loki/data + +# กำหนดสิทธิ์ให้ตรงกับ User ID ใน Container +# Prometheus (UID 65534 - nobody) +chown -R 65534:65534 /volume1/np-dms/monitoring/prometheus +chmod -R 750 /volume1/np-dms/monitoring/prometheus + +# Grafana (UID 472) +chown -R 472:472 /volume1/np-dms/monitoring/grafana/data +chmod -R 750 /volume1/np-dms/monitoring/grafana/data + +# Uptime Kuma (UID 1000) +chown -R 1000:1000 /volume1/np-dms/monitoring/uptime-kuma/data +chmod -R 750 /volume1/np-dms/monitoring/uptime-kuma/data + +# Loki (UID 10001) +chown -R 10001:10001 /volume1/np-dms/monitoring/loki/data +chmod -R 750 /volume1/np-dms/monitoring/loki/data +``` + +--- + +## Note: NPM Proxy Configuration (ถ้าใช้ NPM บน ASUSTOR) + +| Domain Names | Forward Hostname | IP Forward Port | Cache Assets | Block Common Exploits | Websockets | Force SSL | HTTP/2 | +| :--------------------- | :--------------- | :-------------- | :----------- | :-------------------- | :--------- | :-------- | :----- | +| grafana.np-dms.work | grafana | 3000 | [ ] | [x] | [x] | [x] | [x] | +| prometheus.np-dms.work | prometheus | 9090 | [ ] | [x] | [ ] | [x] | [x] | +| uptime.np-dms.work | uptime-kuma | 3001 | [ ] | [x] | [x] | [x] | [x] | + +> **หมายเหตุ**: ถ้าใช้ NPM บน QNAP เพียงตัวเดียว ให้ forward ไปยัง IP ของ ASUSTOR (192.168.10.9) + +--- + +## Docker Compose File (ASUSTOR) + +```yaml +# File: /volume1/np-dms/monitoring/docker-compose.yml +# DMS Container v1.8.0: Application name: lcbp3-monitoring +# Deploy on: ASUSTOR AS5403T +# Services: prometheus, grafana, node-exporter, cadvisor, uptime-kuma, loki + +x-restart: &restart_policy + restart: unless-stopped + +x-logging: &default_logging + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "5" + +networks: + lcbp3: + external: true + +services: + # ---------------------------------------------------------------- + # 1. Prometheus (Metrics Collection & Storage) + # ---------------------------------------------------------------- + prometheus: + <<: [*restart_policy, *default_logging] + image: prom/prometheus:v2.48.0 + container_name: prometheus + stdin_open: true + tty: true + deploy: + resources: + limits: + cpus: "1.0" + memory: 1G + reservations: + cpus: "0.25" + memory: 256M + environment: + TZ: "Asia/Bangkok" + command: + - '--config.file=/etc/prometheus/prometheus.yml' + - '--storage.tsdb.path=/prometheus' + - '--storage.tsdb.retention.time=30d' + - '--web.enable-lifecycle' + networks: + - lcbp3 + volumes: + - "/volume1/np-dms/monitoring/prometheus/config:/etc/prometheus:ro" + - "/volume1/np-dms/monitoring/prometheus/data:/prometheus" + healthcheck: + test: ["CMD", "wget", "--spider", "-q", "http://localhost:9090/-/healthy"] + interval: 30s + timeout: 10s + retries: 3 + + # ---------------------------------------------------------------- + # 2. Grafana (Dashboard & Visualization) + # ---------------------------------------------------------------- + grafana: + <<: [*restart_policy, *default_logging] + image: grafana/grafana:10.2.2 + container_name: grafana + stdin_open: true + tty: true + deploy: + resources: + limits: + cpus: "1.0" + memory: 512M + reservations: + cpus: "0.25" + memory: 128M + environment: + TZ: "Asia/Bangkok" + GF_SECURITY_ADMIN_USER: admin + GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_PASSWORD:-Center#2025} + GF_SERVER_ROOT_URL: "https://grafana.np-dms.work" + GF_INSTALL_PLUGINS: grafana-clock-panel,grafana-piechart-panel + networks: + - lcbp3 + volumes: + - "/volume1/np-dms/monitoring/grafana/data:/var/lib/grafana" + depends_on: + - prometheus + healthcheck: + test: ["CMD-SHELL", "wget --spider -q http://localhost:3000/api/health || exit 1"] + interval: 30s + timeout: 10s + retries: 3 + + # ---------------------------------------------------------------- + # 3. Uptime Kuma (Service Availability Monitoring) + # ---------------------------------------------------------------- + uptime-kuma: + <<: [*restart_policy, *default_logging] + image: louislam/uptime-kuma:1 + container_name: uptime-kuma + deploy: + resources: + limits: + cpus: "0.5" + memory: 256M + environment: + TZ: "Asia/Bangkok" + networks: + - lcbp3 + volumes: + - "/volume1/np-dms/monitoring/uptime-kuma/data:/app/data" + healthcheck: + test: ["CMD", "wget", "--spider", "-q", "http://localhost:3001"] + interval: 30s + timeout: 10s + retries: 3 + + # ---------------------------------------------------------------- + # 4. Node Exporter (Host Metrics - ASUSTOR) + # ---------------------------------------------------------------- + node-exporter: + <<: [*restart_policy, *default_logging] + image: prom/node-exporter:v1.7.0 + container_name: node-exporter + deploy: + resources: + limits: + cpus: "0.5" + memory: 128M + environment: + TZ: "Asia/Bangkok" + command: + - '--path.procfs=/host/proc' + - '--path.sysfs=/host/sys' + - '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)' + networks: + - lcbp3 + volumes: + - /proc:/host/proc:ro + - /sys:/host/sys:ro + - /:/rootfs:ro + healthcheck: + test: ["CMD", "wget", "--spider", "-q", "http://localhost:9100/metrics"] + interval: 30s + timeout: 10s + retries: 3 + + # ---------------------------------------------------------------- + # 5. cAdvisor (Container Metrics - ASUSTOR) + # ---------------------------------------------------------------- + cadvisor: + <<: [*restart_policy, *default_logging] + image: gcr.io/cadvisor/cadvisor:v0.47.2 + container_name: cadvisor + deploy: + resources: + limits: + cpus: "0.5" + memory: 256M + environment: + TZ: "Asia/Bangkok" + networks: + - lcbp3 + volumes: + - /:/rootfs:ro + - /var/run:/var/run:ro + - /sys:/sys:ro + - /var/lib/docker/:/var/lib/docker:ro + healthcheck: + test: ["CMD", "wget", "--spider", "-q", "http://localhost:8080/healthz"] + interval: 30s + timeout: 10s + retries: 3 + + # ---------------------------------------------------------------- + # 6. Loki (Log Aggregation) + # ---------------------------------------------------------------- + loki: + <<: [*restart_policy, *default_logging] + image: grafana/loki:2.9.0 + container_name: loki + deploy: + resources: + limits: + cpus: "0.5" + memory: 512M + environment: + TZ: "Asia/Bangkok" + command: -config.file=/etc/loki/local-config.yaml + networks: + - lcbp3 + volumes: + - "/volume1/np-dms/monitoring/loki/data:/loki" + healthcheck: + test: ["CMD", "wget", "--spider", "-q", "http://localhost:3100/ready"] + interval: 30s + timeout: 10s + retries: 3 +``` + +--- + +## QNAP Node Exporter & cAdvisor + +ติดตั้ง node-exporter และ cAdvisor บน QNAP เพื่อให้ Prometheus บน ASUSTOR scrape metrics ได้: + +```yaml +# File: /share/np-dms/monitoring/docker-compose.yml (QNAP) +# เฉพาะ exporters เท่านั้น - metrics ถูก scrape โดย Prometheus บน ASUSTOR + +version: '3.8' + +networks: + lcbp3: + external: true + +services: + node-exporter: + image: prom/node-exporter:v1.7.0 + container_name: node-exporter + restart: unless-stopped + command: + - '--path.procfs=/host/proc' + - '--path.sysfs=/host/sys' + - '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)' + networks: + - lcbp3 + volumes: + - /proc:/host/proc:ro + - /sys:/host/sys:ro + - /:/rootfs:ro + + cadvisor: + image: gcr.io/cadvisor/cadvisor:v0.47.2 + container_name: cadvisor + restart: unless-stopped + networks: + - lcbp3 + volumes: + - /:/rootfs:ro + - /var/run:/var/run:ro + - /sys:/sys:ro + - /var/lib/docker/:/var/lib/docker:ro +``` + +--- + +## Prometheus Configuration + +สร้างไฟล์ `/volume1/np-dms/monitoring/prometheus/config/prometheus.yml` บน ASUSTOR: + +```yaml +global: + scrape_interval: 15s + evaluation_interval: 15s + +scrape_configs: + # Prometheus self-monitoring (ASUSTOR) + - job_name: 'prometheus' + static_configs: + - targets: ['localhost:9090'] + + # ============================================ + # ASUSTOR Metrics (Local) + # ============================================ + + # Host metrics from Node Exporter (ASUSTOR) + - job_name: 'asustor-node' + static_configs: + - targets: ['node-exporter:9100'] + labels: + host: 'asustor' + + # Container metrics from cAdvisor (ASUSTOR) + - job_name: 'asustor-cadvisor' + static_configs: + - targets: ['cadvisor:8080'] + labels: + host: 'asustor' + + # ============================================ + # QNAP Metrics (Remote - 192.168.10.8) + # ============================================ + + # Host metrics from Node Exporter (QNAP) + - job_name: 'qnap-node' + static_configs: + - targets: ['192.168.10.8:9100'] + labels: + host: 'qnap' + + # Container metrics from cAdvisor (QNAP) + - job_name: 'qnap-cadvisor' + static_configs: + - targets: ['192.168.10.8:8080'] + labels: + host: 'qnap' + + # Backend NestJS application (QNAP) + - job_name: 'backend' + static_configs: + - targets: ['192.168.10.8:3000'] + labels: + host: 'qnap' + metrics_path: '/metrics' + + # MariaDB Exporter (optional - QNAP) + # - job_name: 'mariadb' + # static_configs: + # - targets: ['192.168.10.8:9104'] + # labels: + # host: 'qnap' +``` + +--- + +## Uptime Kuma Monitors + +เมื่อ Uptime Kuma พร้อมใช้งาน ให้เพิ่ม monitors ต่อไปนี้: + +| Monitor Name | Type | URL / Host | Interval | +| :------------ | :--- | :--------------------------------- | :------- | +| QNAP NPM | HTTP | https://npm.np-dms.work | 60s | +| Frontend | HTTP | https://lcbp3.np-dms.work | 60s | +| Backend API | HTTP | https://backend.np-dms.work/health | 60s | +| MariaDB | TCP | 192.168.10.8:3306 | 60s | +| Redis | TCP | 192.168.10.8:6379 | 60s | +| Elasticsearch | HTTP | http://192.168.10.8:9200 | 60s | +| Gitea | HTTP | https://git.np-dms.work | 60s | +| n8n | HTTP | https://n8n.np-dms.work | 60s | +| Grafana | HTTP | https://grafana.np-dms.work | 60s | +| QNAP Host | Ping | 192.168.10.8 | 60s | +| ASUSTOR Host | Ping | 192.168.10.9 | 60s | + +--- + +## Grafana Dashboards + +### Recommended Dashboards to Import + +| Dashboard ID | Name | Purpose | +| :----------- | :--------------------------- | :------------------ | +| 1860 | Node Exporter Full | Host system metrics | +| 14282 | cAdvisor exporter | Container metrics | +| 11074 | Node Exporter for Prometheus | Node overview | +| 7362 | Docker and Host Monitoring | Combined view | + +### Import Dashboard via Grafana UI + +1. Go to **Dashboards → Import** +2. Enter Dashboard ID (e.g., `1860`) +3. Select Prometheus data source +4. Click **Import** + +--- + +> 📝 **หมายเหตุ**: เอกสารนี้อ้างอิงจาก Architecture Document **v1.8.0** - Monitoring Stack deploy บน ASUSTOR AS5403T diff --git a/specs/08-infrastructure/n8n_setting.md b/specs/08-infrastructure/n8n_setting.md index b81a894..e3a21ad 100644 --- a/specs/08-infrastructure/n8n_setting.md +++ b/specs/08-infrastructure/n8n_setting.md @@ -8,15 +8,15 @@ ```bash # สำหรับ n8n volumes -chown -R 1000:1000 /share/Container/n8n -chmod -R 755 /share/Container/n8n +chown -R 1000:1000 /share/np-dms/n8n +chmod -R 755 /share/np-dms/n8n ``` ## Docker file ```yml -# File: share/Container/n8n/docker-compose.yml -# DMS Container v1_4_1 แยก service และ folder, Application name:n8n service n8n +# File: share/np-dms/n8n/docker-compose.yml +# DMS Container v1_7_0 แยก service และ folder, Application name:n8n service n8n x-restart: &restart_policy restart: unless-stopped @@ -72,10 +72,10 @@ services: networks: lcbp3: {} volumes: - - "/share/Container/n8n:/home/node/.n8n" - - "/share/Container/n8n/cache:/home/node/.cache" - - "/share/Container/n8n/scripts:/scripts" - - "/share/Container/n8n/data:/data" + - "/share/np-dms/n8n:/home/node/.n8n" + - "/share/np-dms/n8n/cache:/home/node/.cache" + - "/share/np-dms/n8n/scripts:/scripts" + - "/share/np-dms/n8n/data:/data" - "/var/run/docker.sock:/var/run/docker.sock" healthcheck: diff --git a/specs/08-infrastructure/แผนผัง Network.md b/specs/08-infrastructure/แผนผัง Network.md index e160341..e8abb34 100644 --- a/specs/08-infrastructure/แผนผัง Network.md +++ b/specs/08-infrastructure/แผนผัง Network.md @@ -1,120 +1,359 @@ -# **🗺️ แผนผัง Network Architecture & Firewall (LCBP3-DMS)** +# 🗺️ แผนผัง Network Architecture & Container Services (LCBP3-DMS) -แผนผังนี้แสดงการแบ่งส่วนเครือข่าย (VLANs) และกฎ Firewall (ACLs) สำหรับ TP-Link Omada (ER7206/OC200) เพื่อรักษาความปลอดภัยของ QNAP NAS และ Docker Services +แผนผังนี้แสดงการแบ่งส่วนเครือข่าย (VLANs), การเชื่อมต่อ Firewall (ACLs) และบทบาทของ Server ทั้งสองตัว (QNAP: Application, ASUSTOR: Infrastructure) -## **1\. แผนผังการเชื่อมต่อ (Connection Flow Diagram)** +--- -graph TD +## 1. ภาพรวมการแบ่งบทบาท Server + +``` +┌──────────────────────────────────────────────────────────────────────────────┐ +│ LCBP3-DMS INFRASTRUCTURE │ +├────────────────────────────────┬─────────────────────────────────────────────┤ +│ QNAP TS-473A │ ASUSTOR AS5403T │ +│ (Application & Database) │ (Infrastructure & Backup) │ +├────────────────────────────────┼─────────────────────────────────────────────┤ +│ ✔ Application Runtime │ ✔ File Storage (NFS/SMB) │ +│ ✔ API / Web (NestJS, Next.js) │ ✔ Backup Target (Restic/Borg) │ +│ ✔ Database (MariaDB Primary) │ ✔ Docker Infra (Registry, Portainer) │ +│ ✔ High CPU / RAM usage │ ✔ Monitoring (Prometheus, Grafana) │ +│ ✔ Worker / Queue (Redis) │ ✔ Log Aggregation (Loki) │ +│ ✔ API Gateway (NPM) │ ✔ Uptime Monitoring (Uptime Kuma) │ +│ ✖ ไม่เก็บ backup ระยะยาว │ ✖ ไม่รัน App logic หนัก │ +├────────────────────────────────┼─────────────────────────────────────────────┤ +│ Container: Container Station │ Container: Portainer │ +│ IP: 192.168.10.8 │ IP: 192.168.10.9 │ +│ Storage: 4TB×4 RAID5 + 1TB SSD │ Storage: 6TB×3 RAID5 + 1TB SSD │ +└────────────────────────────────┴─────────────────────────────────────────────┘ +``` + +--- + +## 2. Data Flow Diagram + +```mermaid +flowchart TB + subgraph Internet["🌐 Internet"] + User[("👤 User")] + end + + subgraph QNAP["💾 QNAP TS-473A (App Server)"] + NPM["🔲 NPM
(Reverse Proxy)"] + Frontend["📱 Next.js
(Frontend)"] + Backend["⚙️ NestJS
(Backend API)"] + DB["🗄️ MariaDB"] + Redis["📦 Redis"] + ES["🔍 Elasticsearch"] + end + + subgraph ASUSTOR["💾 ASUSTOR AS5403T (Infra Server)"] + Portainer["🐳 Portainer"] + Registry["📦 Registry"] + Prometheus["📊 Prometheus"] + Grafana["📈 Grafana"] + Uptime["⏱️ Uptime Kuma"] + Backup["💾 Restic/Borg"] + NFS["📁 NFS Storage"] + end + + User -->|HTTPS 443| NPM + NPM --> Frontend + NPM --> Backend + Frontend --> Backend + Backend --> DB + Backend --> Redis + Backend --> ES + + DB -.->|Scheduled Backup| Backup + Backup --> NFS + + Portainer -.->|Manage| QNAP + Prometheus -.->|Collect Metrics| Backend + Prometheus -.->|Collect Metrics| DB + Uptime -.->|Health Check| NPM +``` + +--- + +## 3. Docker Management View + +```mermaid +flowchart TB + subgraph Portainer["🐳 Portainer (ASUSTOR - Central Management)"] + direction TB + + subgraph LocalStack["📦 Local Infra Stack"] + Registry["Docker Registry"] + Prometheus["Prometheus"] + Grafana["Grafana"] + Uptime["Uptime Kuma"] + Backup["Restic/Borg"] + Loki["Loki (Logs)"] + ClamAV["ClamAV"] + end + + subgraph RemoteStack["🔗 Remote: QNAP App Stack"] + Frontend["Next.js"] + Backend["NestJS"] + MariaDB["MariaDB"] + Redis["Redis"] + ES["Elasticsearch"] + NPM["NPM"] + Gitea["Gitea"] + N8N["n8n"] + PMA["phpMyAdmin"] + end + end +``` + +--- + +## 4. Security Zones Diagram + +```mermaid +flowchart TB + subgraph PublicZone["🌐 PUBLIC ZONE"] + direction LR + NPM["NPM (Reverse Proxy)"] + SSL["SSL/TLS Termination"] + end + + subgraph AppZone["📱 APPLICATION ZONE (QNAP)"] + direction LR + Frontend["Next.js"] + Backend["NestJS"] + N8N["n8n"] + Gitea["Gitea"] + end + + subgraph DataZone["💾 DATA ZONE (QNAP - Internal Only)"] + direction LR + MariaDB["MariaDB"] + Redis["Redis"] + ES["Elasticsearch"] + end + + subgraph InfraZone["🛠️ INFRASTRUCTURE ZONE (ASUSTOR)"] + direction LR + Backup["Backup Services"] + Registry["Docker Registry"] + Monitoring["Prometheus + Grafana"] + Logs["Loki / Syslog"] + end + + PublicZone -->|HTTPS Only| AppZone + AppZone -->|Internal API| DataZone + DataZone -.->|Backup| InfraZone + AppZone -.->|Metrics| InfraZone +``` + +--- + +## 5. แผนผังการเชื่อมต่อเครือข่าย (Network Flow) + +```mermaid +graph TD direction TB - subgraph Flow1 \[\การเชื่อมต่อจากภายนอก (Public WAN)\\] - User\[ผู้ใช้งานภายนอก (Internet)\] + subgraph Flow1["การเชื่อมต่อจากภายนอก (Public WAN)"] + User["ผู้ใช้งานภายนอก (Internet)"] end - subgraph Router \[\Router (ER7206)\ \- Gateway\] - User \-- "Port 80/443 (HTTPS/HTTP)" \--\> ER7206 - ER7206(\Port Forwarding\\
TCP 80 \-\> 192.168.10.100:80\
TCP 443 \-\> 192.168.10.100:443) + subgraph Router["Router (ER7206) - Gateway"] + User -- "Port 80/443 (HTTPS/HTTP)" --> ER7206 + ER7206["Port Forwarding
TCP 80 → 192.168.10.8:80
TCP 443 → 192.168.10.8:443"] end - subgraph VLANs \[\เครือข่ายภายใน (VLANs & Firewall Rules)\\] + subgraph VLANs["เครือข่ายภายใน (VLANs & Firewall Rules)"] direction LR - subgraph VLAN10 \[\VLAN 10: Servers (DMZ)\\
192.168.10.x\] - QNAP\[\QNAP NAS (192.168.10.100)\\] - end - - subgraph VLAN20 \[\VLAN 20: Office\\
192.168.20.x\] - OfficePC\[PC พนักงาน/Wi-Fi\] + subgraph VLAN10["VLAN 10: Servers
192.168.10.x"] + QNAP["QNAP NAS
(192.168.10.8)"] + ASUSTOR["ASUSTOR NAS
(192.168.10.9)"] end - subgraph VLAN30 \[\VLAN 30: Guests\\
192.168.30.x\] - GuestPC\[Guest Wi-Fi\] + subgraph VLAN20["VLAN 20: MGMT
192.168.20.x"] + AdminPC["Admin PC / Switches"] end - subgraph Firewall \[\Firewall ACLs (ควบคุมโดย OC200)\\] - direction TB - rule1(\Rule 1: DENY\\
Guest (VLAN 30\) \-\> All VLANs) - rule2(\Rule 2: DENY\\
Server (VLAN 10\) \-\> Office (VLAN 20)) - rule3(\Rule 3: ALLOW\\
Office (VLAN 20\) \-\> QNAP (192.168.10.100)\
Ports: 443, 80, 81, 2222\) + subgraph VLAN30["VLAN 30: USER
192.168.30.x"] + OfficePC["PC พนักงาน/Wi-Fi"] end - %% \--- แสดงผล Firewall Rules \--- - GuestPC \-.x|rule1| QNAP - QNAP \-.x|rule2| OfficePC - OfficePC \-- "\[https://lcbp3.np-dms.work\](https://lcbp3.np-dms.work)" \--\>|rule3| QNAP + subgraph VLAN70["VLAN 70: GUEST
192.168.70.x"] + GuestPC["Guest Wi-Fi"] + end + + subgraph Firewall["Firewall ACLs (OC200/ER7206)"] + direction TB + rule1["Rule 1: DENY
Guest (VLAN 70) → All VLANs"] + rule2["Rule 2: DENY
Server (VLAN 10) → User (VLAN 30)"] + rule3["Rule 3: ALLOW
User (VLAN 30) → QNAP
Ports: 443, 80"] + rule4["Rule 4: ALLOW
MGMT (VLAN 20) → All"] + end + + GuestPC -.x|rule1| QNAP + QNAP -.x|rule2| OfficePC + OfficePC -- "https://lcbp3.np-dms.work" -->|rule3| QNAP + AdminPC -->|rule4| QNAP + AdminPC -->|rule4| ASUSTOR end - %% \--- เชื่อมต่อ Router กับ QNAP \--- - ER7206 \--\> QNAP + ER7206 --> QNAP - subgraph Docker \[\Docker Network 'lcbp3' (ภายใน QNAP)\\] - direction TB - - subgraph PublicServices \[Services ที่ NPM เปิดสู่ภายนอก\] - direction LR - NPM\[\NPM (Nginx Proxy Manager)\\
รับการจราจรจาก QNAP\] - Frontend(frontend:3000) - Backend(backend:3000) - Gitea(gitea:3000) - PMA(pma:80) - N8N(n8n:5678) + subgraph DockerQNAP["Docker 'lcbp3' (QNAP - Applications)"] + direction TB + + subgraph PublicServices["Services ที่ NPM เปิดสู่ภายนอก"] + direction LR + NPM["NPM (Nginx Proxy Manager)"] + FrontendC["frontend:3000"] + BackendC["backend:3000"] + GiteaC["gitea:3000"] + PMAC["pma:80"] + N8NC["n8n:5678"] end - subgraph InternalServices \[Internal Services (Backend เรียกใช้เท่านั้น)\] - direction LR - DB(mariadb:3306) - Cache(cache:6379) - Search(search:9200) + subgraph InternalServices["Internal Services (Backend Only)"] + direction LR + DBC["mariadb:3306"] + CacheC["cache:6379"] + SearchC["search:9200"] end - %% \--- การเชื่อมต่อภายใน Docker \--- - NPM \-- "lcbp3.np-dms.work" \--\> Frontend - NPM \-- "backend.np-dms.work" \--\> Backend - NPM \-- "git.np-dms.work" \--\> Gitea - NPM \-- "pma.np-dms.work" \--\> PMA - NPM \-- "n8n.np-dms.work" \--\> N8N + NPM -- "lcbp3.np-dms.work" --> FrontendC + NPM -- "backend.np-dms.work" --> BackendC + NPM -- "git.np-dms.work" --> GiteaC + NPM -- "pma.np-dms.work" --> PMAC + NPM -- "n8n.np-dms.work" --> N8NC - Backend \-- "lcbp3 Network" \--\> DB - Backend \-- "lcbp3 Network" \--\> Cache - Backend \-- "lcbp3 Network" \--\> Search - - end - - %% \--- เชื่อมต่อ QNAP กับ Docker \--- - QNAP \--\> NPM + BackendC -- "lcbp3 Network" --> DBC + BackendC -- "lcbp3 Network" --> CacheC + BackendC -- "lcbp3 Network" --> SearchC + end - %% \--- Styling \--- - classDef default fill:\#f9f9f9,stroke:\#333,stroke-width:2px; - classDef router fill:\#e6f7ff,stroke:\#0056b3,stroke-width:2px; - classDef vlan fill:\#fffbe6,stroke:\#d46b08,stroke-width:2px; - classDef docker fill:\#e6ffed,stroke:\#096dd9,stroke-width:2px; - classDef internal fill:\#f0f0f0,stroke:\#595959,stroke-width:2px,stroke-dasharray: 5 5; - classDef fw fill:\#fff0f0,stroke:\#d9363e,stroke-width:2px,stroke-dasharray: 3 3; + subgraph DockerASUSTOR["Docker 'lcbp3' (ASUSTOR - Infrastructure)"] + direction TB - class Router,ER7206 router; - class VLANs,VLAN10,VLAN20,VLAN30 vlan; - class Docker,PublicServices,InternalServices docker; - class DB,Cache,Search internal; - class Firewall,rule1,rule2,rule3 fw; + subgraph InfraServices["Infrastructure Services"] + direction LR + PortainerC["portainer:9443"] + RegistryC["registry:5000"] + PrometheusC["prometheus:9090"] + GrafanaC["grafana:3000"] + UptimeC["uptime-kuma:3001"] + end -## **2\. สรุปการตั้งค่า Firewall ACLs (สำหรับ Omada OC200)** + subgraph BackupServices["Backup & Storage"] + direction LR + ResticC["restic/borg"] + NFSC["NFS Share"] + end -นี่คือรายการกฎ (Rules) ที่คุณต้องสร้างใน Settings \> Network Security \> ACL (เรียงลำดับจากบนลงล่าง): + PortainerC -.->|"Remote Endpoint"| NPM + PrometheusC -.->|"Scrape Metrics"| BackendC + ResticC --> NFSC + end -| ลำดับ | Name | Policy | Source | Destination | Ports | -| :---- | :---- | :---- | :---- | :---- | :---- | -| **1** | Isolate-Guests | **Deny** | Network \-\> VLAN 30 (Guests) | Network \-\> VLAN 1, 10, 20 | All | -| **2** | Isolate-Servers | **Deny** | Network \-\> VLAN 10 (Servers) | Network \-\> VLAN 20 (Office) | All | -| **3** | Block-Office-to-Mgmt | **Deny** | Network \-\> VLAN 20 (Office) | Network \-\> VLAN 1 (Mgmt) | All | -| **4** | Allow-Office-to-Services | **Allow** | Network \-\> VLAN 20 (Office) | IP Group \-\> QNAP\_Services (192.168.10.100) | Port Group \-\> Web\_Services (443, 80, 81, 2222\) | -| **5** | (Default) | Allow | Any | Any | All | + QNAP --> NPM + ASUSTOR --> PortainerC + DBC -.->|"Scheduled Backup"| ResticC +``` -## **3\. สรุปการตั้งค่า Port Forwarding (สำหรับ Omada ER7206)** +--- -นี่คือรายการกฎที่คุณต้องสร้างใน Settings \> Transmission \> Port Forwarding: +## 6. สรุปการตั้งค่า Firewall ACLs (สำหรับ Omada OC200) -| Name | External Port | Internal IP | Internal Port | Protocol | -| :---- | :---- | :---- | :---- | :---- | -| Allow-NPM-HTTPS | 443 | 192.168.10.100 | 443 | TCP | -| Allow-NPM-HTTP | 80 | 192.168.10.100 | 80 | TCP | +นี่คือรายการกฎ (Rules) ที่คุณต้องสร้างใน **Settings > Network Security > ACL** (เรียงลำดับจากบนลงล่าง): +| ลำดับ | Name | Policy | Source | Destination | Ports | +| :---- | :--------------------- | :-------- | :---------------- | :------------------------ | :----------------------------------- | +| **1** | Isolate-Guests | **Deny** | Network → VLAN 70 | Network → VLAN 10, 20, 30 | All | +| **2** | Isolate-Servers | **Deny** | Network → VLAN 10 | Network → VLAN 30 (USER) | All | +| **3** | Block-User-to-Mgmt | **Deny** | Network → VLAN 30 | Network → VLAN 20 (MGMT) | All | +| **4** | Allow-User-to-Services | **Allow** | Network → VLAN 30 | IP → QNAP (192.168.10.8) | Port Group → Web (443, 80, 81, 2222) | +| **5** | Allow-MGMT-to-All | **Allow** | Network → VLAN 20 | Any | All | +| **6** | Allow-Server-Internal | **Allow** | IP → 192.168.10.8 | IP → 192.168.10.9 | All (QNAP ↔ ASUSTOR) | +| **7** | (Default) | Deny | Any | Any | All | + +--- + +## 7. สรุปการตั้งค่า Port Forwarding (สำหรับ Omada ER7206) + +นี่คือรายการกฎที่คุณต้องสร้างใน **Settings > Transmission > Port Forwarding**: + +| Name | External Port | Internal IP | Internal Port | Protocol | +| :-------------- | :------------ | :----------- | :------------ | :------- | +| Allow-NPM-HTTPS | 443 | 192.168.10.8 | 443 | TCP | +| Allow-NPM-HTTP | 80 | 192.168.10.8 | 80 | TCP | + +> **หมายเหตุ**: Port forwarding ไปที่ QNAP (NPM) เท่านั้น, ASUSTOR ไม่ควรเปิดรับ traffic จากภายนอก + +--- + +## 8. Container Service Distribution + +### QNAP (192.168.10.8) - Application Services + +| Container | Port | Domain | Network | +| :------------ | :--- | :------------------ | :------ | +| npm | 81 | npm.np-dms.work | lcbp3 | +| frontend | 3000 | lcbp3.np-dms.work | lcbp3 | +| backend | 3000 | backend.np-dms.work | lcbp3 | +| mariadb | 3306 | (internal) | lcbp3 | +| cache (redis) | 6379 | (internal) | lcbp3 | +| search (es) | 9200 | (internal) | lcbp3 | +| gitea | 3000 | git.np-dms.work | lcbp3 | +| n8n | 5678 | n8n.np-dms.work | lcbp3 | +| pma | 80 | pma.np-dms.work | lcbp3 | + +### ASUSTOR (192.168.10.9) - Infrastructure Services + +| Container | Port | Domain | Network | +| :------------ | :--- | :--------------------- | :------ | +| portainer | 9443 | portainer.np-dms.work | lcbp3 | +| prometheus | 9090 | prometheus.np-dms.work | lcbp3 | +| grafana | 3000 | grafana.np-dms.work | lcbp3 | +| uptime-kuma | 3001 | uptime.np-dms.work | lcbp3 | +| registry | 5000 | registry.np-dms.work | lcbp3 | +| node-exporter | 9100 | (internal) | lcbp3 | +| cadvisor | 8080 | (internal) | lcbp3 | +| loki | 3100 | (internal) | lcbp3 | +| restic/borg | N/A | (scheduled job) | host | + +--- + +## 9. Backup Flow + +``` +┌────────────────────────────────────────────────────────────────────────┐ +│ BACKUP STRATEGY │ +├────────────────────────────────────────────────────────────────────────┤ +│ │ +│ QNAP (Source) ASUSTOR (Target) │ +│ ┌──────────────┐ ┌──────────────────────┐ │ +│ │ MariaDB │ ──── Daily 2AM ────▶ │ /volume1/backup/db/ │ │ +│ │ (mysqldump) │ │ (Restic Repository) │ │ +│ └──────────────┘ └──────────────────────┘ │ +│ │ +│ ┌──────────────┐ ┌──────────────────────┐ │ +│ │ Redis RDB │ ──── Daily 3AM ────▶ │ /volume1/backup/ │ │ +│ │ + AOF │ │ redis/ │ │ +│ └──────────────┘ └──────────────────────┘ │ +│ │ +│ ┌──────────────┐ ┌──────────────────────┐ │ +│ │ App Config │ ──── Weekly ───────▶ │ /volume1/backup/ │ │ +│ │ + Volumes │ Sunday 4AM │ config/ │ │ +│ └──────────────┘ └──────────────────────┘ │ +│ │ +│ Retention Policy: │ +│ • Daily: 7 days │ +│ • Weekly: 4 weeks │ +│ • Monthly: 6 months │ +│ │ +└────────────────────────────────────────────────────────────────────────┘ +``` + +--- + +> 📝 **หมายเหตุ**: เอกสารนี้อ้างอิงจาก Architecture Document **v1.8.0** - Last updated: 2026-01-28