refactor(specs): merge 08-infrastructure into canonical 04-06 dirs
All checks were successful
Build and Deploy / deploy (push) Successful in 1m0s

- Append live QNAP configs to 04-01-docker-compose.md (Appendix A)
  - MariaDB+PMA, Redis+Elasticsearch, NPM, Gitea, n8n, App stack
- Append SSH setup + Secrets management to 04-06-security-operations.md
  - Appendix A: SSH key setup, config, hardening, port forwarding
  - Appendix B: .env structure, secret generation, rotation, GPG backup
- Append QNAP/Gitea CI/CD docs to 04-04-deployment-guide.md
  - Appendix A: Container Station deployment steps
  - Appendix B: Gitea Actions CI/CD pipeline setup
  - Appendix C: act_runner (ASUSTOR) installation
- Move Git_command.md -> 05-Engineering-Guidelines/05-05-git-cheatsheet.md
- Move docker-compose-app.yml, lcbp3-monitoring.yml, lcbp3-registry.yml,
  grafana/ -> 04-Infrastructure-OPS/
- Archive lcbp3-db.md -> 99-archives/
- Remove all legacy 08-infrastructure/* files from git
- Remove Google OAuth client_secret JSON from git index (security)
- Add .gitignore rules: *client_secret*.json, *service_account*.json,
  specs/08-infrastructure/
- Update 04-Infrastructure-OPS/README.md with new file index
This commit is contained in:
admin
2026-02-23 15:03:35 +07:00
parent b7676777e8
commit 5eff8861e1
23 changed files with 808 additions and 1971 deletions

View File

@@ -442,3 +442,180 @@ echo "Account compromise response completed for User ID: $USER_ID"
**Version:** 1.8.0
**Last Review:** 2025-12-01
**Next Review:** 2026-03-01
---
# Appendix A — SSH Setup (QNAP & ASUSTOR)
> คู่มือการตั้งค่าและใช้งาน SSH สำหรับ NAS ทั้ง 2 เครื่อง
## A.1 Connection Info
| Item | QNAP (TS-473A) | ASUSTOR (AS5403T) |
| ------------- | ------------------ | ----------------------- |
| **Role** | Application Server | Infrastructure / Backup |
| **IP** | `192.168.10.8` | `192.168.10.9` |
| **SSH Port** | `22` | `22` |
| **SSH Alias** | `qnap` | `asustor` |
## A.2 Enable SSH on NAS
**QNAP:** QTS Web UI → Control Panel → Network & File Services → Telnet/SSH → Enable SSH (port 22)
**ASUSTOR:** ADM Web UI → Settings → Terminal & SNMP → Enable SSH service (port 22)
## A.3 SSH Key Setup (Client → NAS)
```powershell
# Create key (once on dev machine)
ssh-keygen -t ed25519 -C "nattanin@np-dms"
# Copy public key to NAS
ssh-copy-id -i ~/.ssh/id_ed25519.pub nattanin@192.168.10.8 # QNAP
ssh-copy-id -i ~/.ssh/id_ed25519.pub nattanin@192.168.10.9 # ASUSTOR
```
## A.4 SSH Config (`~/.ssh/config`)
```ssh-config
Host gitea
HostName git.np-dms.work
User git
Port 2222
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes
Host qnap
HostName 192.168.10.8
User nattanin
Port 22
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes
Host asustor
HostName 192.168.10.9
User nattanin
Port 22
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes
```
## A.5 SSH Hardening (`/etc/ssh/sshd_config` on NAS)
```bash
PasswordAuthentication no # Key-only login
PermitRootLogin no
AllowUsers nattanin
# Restart SSH
/etc/init.d/login_server.sh restart # QNAP
/etc/init.d/sshd restart # ASUSTOR
```
> ⚠️ **ตรวจสอบว่า SSH Key ใช้งานได้ก่อนปิด PasswordAuthentication**
## A.6 SSH Port Forwarding (Useful Tunnels)
```powershell
# MariaDB local tunnel
ssh -L 3306:localhost:3306 qnap
# Elasticsearch tunnel
ssh -L 9200:localhost:9200 qnap
# Grafana tunnel (from ASUSTOR)
ssh -L 3000:localhost:3000 asustor
```
## A.7 SSH Troubleshooting
| Problem | Cause | Fix |
| ------------------------------- | ------------------------ | ------------------------------------------------------ |
| `Connection refused` | SSH not enabled on NAS | Enable SSH via Web UI |
| `Permission denied (publickey)` | Wrong key or permissions | `chmod 700 ~/.ssh`, `chmod 600 ~/.ssh/authorized_keys` |
| `Host key verification failed` | IP changed, stale key | `ssh-keygen -R 192.168.10.8` |
| `Connection timed out` | Firewall / wrong IP | Check ACL and ping |
---
# Appendix B — Secrets Management (QNAP Deployment)
> ⚠️ **Security Level: CONFIDENTIAL** — ห้าม commit secrets ลง Git
## B.1 Secret Categories
| Category | Examples | Storage |
| -------------------- | ------------------------------ | ---------------------- |
| Database Credentials | `MYSQL_ROOT_PASSWORD` | `.env` (gitignored) |
| API Keys | `JWT_SECRET`, `REDIS_PASSWORD` | `.env` (gitignored) |
| SSL Certificates | Let's Encrypt | NPM volume |
| SSH Keys | Backup access keys | ASUSTOR secure storage |
## B.2 Environment File (QNAP)
```bash
# File: /share/np-dms/.env
# ⚠️ MUST be in .gitignore
# === Database ===
MYSQL_ROOT_PASSWORD=<strong-password>
MYSQL_DATABASE=lcbp3
MYSQL_USER=center
MYSQL_PASSWORD=<strong-password>
# === Redis ===
REDIS_PASSWORD=<strong-password>
# === Application ===
JWT_SECRET=<random-64-hex> # openssl rand -hex 64
JWT_REFRESH_SECRET=<random-64-hex>
# === Monitoring ===
GRAFANA_PASSWORD=<admin-password>
# === External Services ===
LINE_CHANNEL_SECRET=<line-secret>
LINE_CHANNEL_ACCESS_TOKEN=<line-token>
```
## B.3 Generate Strong Secrets
```bash
openssl rand -base64 32 # Strong password (24+ chars)
openssl rand -hex 64 # JWT Secret (64 hex chars)
```
## B.4 Rotation Schedule
| Secret | Period | Impact |
| ----------------- | -------------------- | ----------------------- |
| JWT Secret | 90 days | Users re-login required |
| Database Password | 180 days | Service restart needed |
| Redis Password | 180 days | Service restart needed |
| SSL Certificates | Auto (Let's Encrypt) | None |
## B.5 Encrypted Secret Backup
```bash
# Encrypt and back up to ASUSTOR
gpg --symmetric --cipher-algo AES256 /share/np-dms/.env -o /tmp/env.gpg
scp /tmp/env.gpg admin@192.168.10.9:/volume1/backup/secrets/
rm /tmp/env.gpg
# Restore
scp admin@192.168.10.9:/volume1/backup/secrets/env.gpg /tmp/
gpg --decrypt /tmp/env.gpg > /share/np-dms/.env
rm /tmp/env.gpg
```
## B.6 Gitea Actions Secrets (CI/CD)
Configure at: Gitea → Repository → Settings → Actions → Secrets
| Secret Name | Description |
| ----------- | ----------------------------- |
| `HOST` | QNAP IP (`192.168.10.8`) |
| `PORT` | SSH Port (`22`) |
| `USERNAME` | SSH user with Docker access |
| `PASSWORD` | SSH password (prefer SSH Key) |