| <!DOCTYPE html> |
| <html lang="th"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>ROGLAG — Self-host Docs</title> |
| <style> |
| :root{--bg:#0b0f17;--panel:#121826;--panel2:#0f1420;--line:#1f2a3d;--txt:#e6edf6; |
| --muted:#90a0b8;--accent:#4da3ff;--accent2:#7c5cff;--ok:#34d399;--warn:#fbbf24;--crit:#f87171;--code:#0a0e16;} |
| *{box-sizing:border-box}html{scroll-behavior:smooth} |
| body{margin:0;background:radial-gradient(1200px 600px at 80% -10%,#15203a 0%,var(--bg) 55%); |
| color:var(--txt);font-family:-apple-system,"Segoe UI",Roboto,"Noto Sans Thai",sans-serif;line-height:1.65;font-size:15px} |
| .wrap{max-width:1040px;margin:0 auto;padding:32px 22px 96px} |
| header.hero{border:1px solid var(--line);border-radius:18px;padding:26px 30px; |
| background:linear-gradient(135deg,#13203a,#0f1420);margin-bottom:14px} |
| .hero h1{margin:0 0 6px;font-size:28px}.hero p{margin:0;color:var(--muted)} |
| .chips{display:flex;gap:8px;flex-wrap:wrap;margin-top:14px} |
| .chip{font-size:12px;padding:5px 11px;border:1px solid var(--line);border-radius:999px;background:#16203250;color:var(--accent)} |
| nav.toc{position:sticky;top:0;z-index:5;backdrop-filter:blur(8px);background:#0b0f17cc; |
| border:1px solid var(--line);border-radius:14px;padding:12px 16px;margin:18px 0 26px;display:flex;gap:14px;flex-wrap:wrap} |
| nav.toc a{color:var(--muted);text-decoration:none;font-size:13px}nav.toc a:hover{color:var(--accent)} |
| section{border:1px solid var(--line);border-radius:16px;padding:24px 26px;background:var(--panel);margin-bottom:22px} |
| h2{font-size:21px;margin:0 0 10px;display:flex;align-items:center;gap:10px} |
| h2 .num{font-size:13px;color:var(--accent2);border:1px solid var(--line);border-radius:8px;padding:2px 8px;background:var(--panel2)} |
| h3{font-size:16px;margin:20px 0 8px;color:var(--accent)} |
| .sub{color:var(--muted);margin:2px 0 16px;font-size:13.5px} |
| code{background:var(--code);border:1px solid var(--line);border-radius:6px;padding:1px 6px;font-size:13px;color:#cfe3ff; |
| font-family:"SF Mono",Menlo,Consolas,monospace} |
| pre{background:var(--code);border:1px solid var(--line);border-radius:12px;padding:16px 18px;overflow:auto;font-size:12.8px;line-height:1.55} |
| pre code{background:none;border:none;padding:0;color:#d6e2f2} |
| table{width:100%;border-collapse:collapse;margin:12px 0;font-size:13.5px} |
| th,td{border:1px solid var(--line);padding:9px 12px;text-align:left;vertical-align:top} |
| th{background:var(--panel2);color:var(--accent)} |
| .m-get{color:var(--ok);font-weight:700}.m-post{color:var(--warn);font-weight:700}.m-ws{color:var(--accent2);font-weight:700} |
| .flow{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin:14px 0;font-size:13px} |
| .node{border:1px solid var(--line);background:var(--panel2);border-radius:10px;padding:8px 12px} |
| .arrow{color:var(--accent2);font-weight:700} |
| .callout{border-left:3px solid var(--accent);background:#0e1a2e;border-radius:0 10px 10px 0;padding:12px 16px;margin:14px 0;font-size:13.5px} |
| .callout.warn{border-left-color:var(--warn);background:#241d0e} |
| .callout.crit{border-left-color:var(--crit);background:#2a1414} |
| ul,ol{margin:8px 0 8px 4px;padding-left:20px}li{margin:4px 0} |
| .grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:14px;margin:14px 0} |
| .card{border:1px solid var(--line);border-radius:12px;padding:16px;background:var(--panel2)} |
| .card h4{margin:0 0 6px;font-size:14px}.card p{margin:0;color:var(--muted);font-size:13px} |
| footer{color:var(--muted);text-align:center;font-size:12px;margin-top:30px} |
| </style> |
| </head> |
| <body> |
| <div class="wrap"> |
| <header class="hero"> |
| <h1>🛡️ ROGLAG — Self-host Realtime Docs</h1> |
| <p>ระบบตรวจจับความเสี่ยงจาก security log แบบ realtime + RAG ที่ self-host ได้ทั้งหมด รันได้แม้ออฟไลน์</p> |
| <div class="chips"> |
| <span class="chip">FastAPI</span><span class="chip">WebSocket Realtime</span> |
| <span class="chip">Rule Classifier</span><span class="chip">RAG</span> |
| <span class="chip">PostgreSQL / SQLite</span><span class="chip">Docker</span> |
| </div> |
| </header> |
|
|
| <nav class="toc"> |
| <a href="#about">ภาพรวม</a><a href="#run">วิธีรัน</a><a href="#features">ฟีเจอร์</a> |
| <a href="#flow">Data Flow</a><a href="#api">API</a><a href="#csv">รูปแบบ CSV</a> |
| <a href="#n8n">ต่อ n8n</a><a href="#prod">Production</a> |
| </nav> |
|
|
| <section id="about"> |
| <h2><span class="num">1</span> ภาพรวม</h2> |
| <p class="sub">ทำอะไร และต่างจาก demo เดิมอย่างไร</p> |
| <p>ROGLAG รับ log (อัปโหลด CSV หรือ stream เข้ามา) → <b>classify ด้วย rule</b> ทันที (brute force, port scan, web attack, priv esc, data exfil, C2 beacon) → เก็บลง database → <b>push เข้าหน้าเว็บแบบ realtime</b> ผ่าน WebSocket → ถามตอบด้วย RAG ภาษาไทยได้</p> |
| <ul> |
| <li><b>รันได้ออฟไลน์ 100%</b> — การตรวจจับใช้ rule-based ไม่ต้องมี API key / model</li> |
| <li><b>Optional LLM</b> — ใส่ <code>OPENROUTER_API_KEY</code> เพื่อให้ตอบ RAG สวยขึ้น (มี fallback เสมอ)</li> |
| <li><b>Portable DB</b> — default เป็น SQLite (zero-config), สลับเป็น PostgreSQL ได้ด้วย env เดียว</li> |
| <li><b>Realtime จริง</b> — WebSocket fan-out ไปทุก browser ที่เปิดอยู่</li> |
| </ul> |
| </section> |
|
|
| <section id="run"> |
| <h2><span class="num">2</span> วิธีรัน</h2> |
| <p class="sub">เลือกได้ 3 แบบ — แนะนำ Docker สำหรับคนอื่นที่อยากรันต่อ</p> |
|
|
| <h3>A) Docker Compose — full stack (PostgreSQL) ✅ แนะนำ</h3> |
| <pre><code>docker compose up --build |
| # เปิด http://localhost:8000</code></pre> |
| <p class="sub">คำสั่งเดียวได้ทั้ง API + PostgreSQL พร้อม volume เก็บข้อมูลถาวร</p> |
|
|
| <h3>B) Docker Compose — SQLite ล้วน (ไม่ต้องมี postgres)</h3> |
| <pre><code>docker compose up api-sqlite --build |
| # เปิด http://localhost:8000</code></pre> |
|
|
| <h3>C) รันตรงด้วย Python (dev)</h3> |
| <pre><code>python3 -m venv .venv && source .venv/bin/activate |
| pip install -r requirements.txt |
| uvicorn app.main:app --host 0.0.0.0 --port 8000 |
| # เปิด http://localhost:8000 (ใช้ SQLite ที่ ./data/lograg.db อัตโนมัติ)</code></pre> |
|
|
| <div class="callout warn"> |
| รันด้วย <b>1 worker</b> เท่านั้น (default) เพราะ WebSocket manager เก็บ connection ใน process เดียว — ถ้าจะ scale หลาย worker ต้องใส่ Redis pub/sub (ดูหัวข้อ Production) |
| </div> |
| <div class="callout"> |
| เปิด LLM: ตั้งค่า <code>OPENROUTER_API_KEY</code> ใน <code>.env</code> (ดู <code>.env.example</code>) แล้วติ๊ก "ใช้ LLM" ในแท็บ Ask |
| </div> |
| </section> |
|
|
| <section id="features"> |
| <h2><span class="num">3</span> ฟีเจอร์ในหน้า Console</h2> |
| <div class="grid"> |
| <div class="card"><h4>⚡ ส่ง Mock Log</h4><p>ปุ่ม burst สร้าง log จำลองหลากหลาย <b>ไม่ซ้ำทุกครั้ง</b> ยิงเข้า pipeline จริง เห็นใน feed ทันที</p></div> |
| <div class="card"><h4>▶ Live Stream</h4><p>สตรีม mock log ต่อเนื่องตาม rate/interval ที่ตั้ง เพื่อจำลองทราฟฟิกจริงสำหรับทดสอบ</p></div> |
| <div class="card"><h4>⬇ Generate CSV</h4><p>สร้างไฟล์ CSV ใหม่ที่สุ่มไม่ซ้ำ (unseeded) ดาวน์โหลดไปทดสอบ upload ได้</p></div> |
| <div class="card"><h4>🔍 Upload CSV</h4><p>อัปโหลด CSV → classify ทุกแถว realtime → เทียบความแม่นยำกับ label เดิม (ถ้ามี)</p></div> |
| <div class="card"><h4>📡 Live Feed</h4><p>แสดง event เข้ามาสดๆ สีตาม severity + เหตุผลการตรวจจับ + MITRE</p></div> |
| <div class="card"><h4>🚨 Alerts</h4><p>รวม critical event เป็น alert (group ตาม IP/user) พร้อม runbook แนะนำ</p></div> |
| <div class="card"><h4>💬 Ask (RAG)</h4><p>ถามภาษาไทยเกี่ยวกับ log ที่เก็บไว้ — keyword retrieval + สรุป (local หรือ LLM)</p></div> |
| <div class="card"><h4>📊 Stats</h4><p>สัดส่วน category / severity / risk rate แบบ realtime</p></div> |
| </div> |
| </section> |
|
|
| <section id="flow"> |
| <h2><span class="num">4</span> Data Flow</h2> |
| <div class="flow"> |
| <span class="node">CSV upload / Mock / Stream</span><span class="arrow">→</span> |
| <span class="node">parse</span><span class="arrow">→</span> |
| <span class="node">detect_rule()<br><small>classify</small></span><span class="arrow">→</span> |
| <span class="node">DB<br><small>log_events</small></span><span class="arrow">→</span> |
| <span class="node">WebSocket<br><small>broadcast</small></span><span class="arrow">→</span> |
| <span class="node">Browser feed</span> |
| </div> |
| <p>โค้ดหลัก: <code>app/ingest.py</code> (parse+classify+store) · <code>app/realtime.py</code> (WebSocket manager + stream) · <code>app/rag.py</code> (retrieval+answer) · <code>app/main.py</code> (routes)</p> |
| </section> |
|
|
| <section id="api"> |
| <h2><span class="num">5</span> API Reference</h2> |
| <table> |
| <tr><th>Method</th><th>Path</th><th>หน้าที่</th></tr> |
| <tr><td class="m-get">GET</td><td><code>/health</code></td><td>สถานะระบบ (storage, llm_ready, ws_clients, stream_running)</td></tr> |
| <tr><td class="m-get">GET</td><td><code>/api/stats</code></td><td>สถิติ category/severity/source/top_ips</td></tr> |
| <tr><td class="m-get">GET</td><td><code>/api/logs?limit&offset&category&severity&source&q</code></td><td>query log ที่เก็บไว้</td></tr> |
| <tr><td class="m-get">GET</td><td><code>/api/alerts?limit</code></td><td>critical alerts ที่ group แล้ว</td></tr> |
| <tr><td class="m-post">POST</td><td><code>/api/ask</code></td><td>RAG Q&A — body: <code>{question, use_llm, model, limit}</code></td></tr> |
| <tr><td class="m-post">POST</td><td><code>/api/ingest/csv</code></td><td>อัปโหลดไฟล์ CSV (multipart <code>file</code>) → ตรวจจับ + broadcast</td></tr> |
| <tr><td class="m-get">GET</td><td><code>/api/generate/csv?count&profile</code></td><td>ดาวน์โหลด CSV สุ่มใหม่ (profile: mixed/attack/realistic)</td></tr> |
| <tr><td class="m-post">POST</td><td><code>/api/mock/emit?count&profile</code></td><td>ยิง mock burst เข้าระบบ realtime</td></tr> |
| <tr><td class="m-post">POST</td><td><code>/api/mock/stream/start?rate&interval&profile</code></td><td>เริ่มสตรีม mock ต่อเนื่อง</td></tr> |
| <tr><td class="m-post">POST</td><td><code>/api/mock/stream/stop</code></td><td>หยุดสตรีม</td></tr> |
| <tr><td class="m-ws">WS</td><td><code>/ws</code></td><td>realtime feed — รับ <code>{type:event|summary|hello}</code></td></tr> |
| </table> |
| <h3>ตัวอย่าง (curl)</h3> |
| <pre><code># ยิง mock 50 event แบบ attack-heavy |
| curl -X POST "http://localhost:8000/api/mock/emit?count=50&profile=attack" |
|
|
| # ถาม RAG |
| curl -X POST http://localhost:8000/api/ask \ |
| -H "Content-Type: application/json" \ |
| -d '{"question":"มี brute force จาก ip ไหนบ้าง"}' |
|
|
| # อัปโหลด CSV |
| curl -X POST http://localhost:8000/api/ingest/csv -F "file=@roglag_logs.csv"</code></pre> |
| </section> |
|
|
| <section id="csv"> |
| <h2><span class="num">6</span> รูปแบบ CSV</h2> |
| <p class="sub">คอลัมน์ที่ระบบอ่าน — ต้องมีอย่างน้อย <code>message</code> (ใช้ตรวจจับ) หรือ <code>source</code></p> |
| <pre><code>timestamp,source,category,severity,message,src_ip,dst_ip,user,dst_port,path,action</code></pre> |
| <ul> |
| <li><code>message</code> = ข้อความ log ดิบ → ใช้ <b>ตรวจจับ category</b></li> |
| <li><code>category</code> (ถ้ามี) = label เดิม → ระบบเอาไป<b>วัดความแม่นยำ</b>การตรวจจับ ไม่ใช้ในการตัดสิน</li> |
| <li>field อื่นเป็น metadata เสริม</li> |
| </ul> |
| <div class="callout">ใช้ปุ่ม <b>Generate CSV</b> สร้างไฟล์ตัวอย่างที่ถูกฟอร์แมตพอดี แล้วเอามา Upload ทดสอบได้ทันที</div> |
| </section> |
|
|
| <section id="n8n"> |
| <h2><span class="num">7</span> ต่อ n8n (automation)</h2> |
| <p class="sub">ใช้ ROGLAG เป็น detection engine แล้วให้ n8n ทำ action ต่อ</p> |
| <ol> |
| <li>n8n <b>Schedule</b> node เรียก <code>GET /api/alerts?limit=20</code> ทุก X นาที (หรือเก็บ <code>last_seen</code> ไว้กรองของใหม่)</li> |
| <li><b>Filter</b> เฉพาะ alert ใหม่ → <b>HTTP Request</b> ไป enrich (AbuseIPDB/GeoIP ด้วย <code>src_ip</code>)</li> |
| <li>เรียก <code>POST /api/ask</code> ให้สรุปภาษาไทย แนบเข้า ticket</li> |
| <li><b>Action</b>: สร้าง ticket (Jira/GitHub), แจ้ง Slack/LINE, (ออปชัน) block IP</li> |
| </ol> |
| <div class="callout warn">การ block IP อัตโนมัติเป็น action ผลกระทบสูง — ควรมี allowlist + approval node + TTL</div> |
| </section> |
|
|
| <section id="prod"> |
| <h2><span class="num">8</span> หมายเหตุ Production / Security</h2> |
| <div class="callout crit"> |
| <b>ยังไม่มี authentication.</b> CORS เปิด <code>*</code> และทุก endpoint เปิด public — เหมาะกับ dev/self-host ในเครือข่ายปิดเท่านั้น ก่อนขึ้นจริงต้องวาง reverse proxy (Traefik/Caddy) + auth (API key/OAuth) หน้า API |
| </div> |
| <ul> |
| <li><b>Scale realtime:</b> WebSocket manager อยู่ใน process เดียว → ถ้าใช้หลาย worker/instance ต้องใช้ Redis pub/sub broadcast ข้าม process</li> |
| <li><b>Storage:</b> SQLite เหมาะ single-node; ปริมาณสูงให้ใช้ PostgreSQL (ตั้ง <code>DATABASE_URL</code>) และทำ retention/partition</li> |
| <li><b>Vector RAG:</b> เวอร์ชันนี้ใช้ keyword retrieval (ออฟไลน์); อัปเกรดเป็น pgvector/Qdrant ได้ตามแผนใน <a href="/plan">plan</a></li> |
| <li><b>Secrets:</b> อย่า commit <code>.env</code> — ใช้ secret manager ใน production</li> |
| </ul> |
| </section> |
|
|
| <footer>ROGLAG self-host · ดูแผนยกระดับ production ที่ <a href="/plan">/plan</a></footer> |
| </div> |
| </body> |
| </html> |
|
|