diff --git a/homepage/assets/screenshots/alerts.png b/homepage/assets/screenshots/alerts.png
new file mode 100644
index 0000000..1cd0861
Binary files /dev/null and b/homepage/assets/screenshots/alerts.png differ
diff --git a/homepage/assets/screenshots/analysis.png b/homepage/assets/screenshots/analysis.png
new file mode 100644
index 0000000..bf97022
Binary files /dev/null and b/homepage/assets/screenshots/analysis.png differ
diff --git a/homepage/assets/screenshots/dashboard.png b/homepage/assets/screenshots/dashboard.png
new file mode 100644
index 0000000..41824fc
Binary files /dev/null and b/homepage/assets/screenshots/dashboard.png differ
diff --git a/homepage/assets/screenshots/logs-query.png b/homepage/assets/screenshots/logs-query.png
new file mode 100644
index 0000000..4a31a65
Binary files /dev/null and b/homepage/assets/screenshots/logs-query.png differ
diff --git a/homepage/assets/screenshots/settings.png b/homepage/assets/screenshots/settings.png
new file mode 100644
index 0000000..e400d08
Binary files /dev/null and b/homepage/assets/screenshots/settings.png differ
diff --git a/homepage/assets/screenshots/wizard.png b/homepage/assets/screenshots/wizard.png
new file mode 100644
index 0000000..9bee585
Binary files /dev/null and b/homepage/assets/screenshots/wizard.png differ
diff --git a/homepage/dist/assets/site.css b/homepage/dist/assets/site.css
new file mode 100644
index 0000000..ad537a5
--- /dev/null
+++ b/homepage/dist/assets/site.css
@@ -0,0 +1,58 @@
+:root {
+ --brand: #059669; --brand-dark: #047857; --ink: #0f172a; --muted: #64748b;
+ --bg: #f8fafc; --card: #ffffff; --line: #e2e8f0;
+ --code-bg: #0f172a; --code-ink: #e2e8f0;
+}
+* { margin: 0; padding: 0; box-sizing: border-box; }
+html { scroll-behavior: smooth; }
+body { font-family: -apple-system, "PingFang SC", "Microsoft YaHei", "Segoe UI", sans-serif; color: var(--ink); background: var(--bg); line-height: 1.7; }
+a { color: var(--brand); text-decoration: none; }
+.container { max-width: 1080px; margin: 0 auto; padding: 0 24px; }
+
+.nav { position: sticky; top: 0; z-index: 10; background: rgba(255,255,255,.92); backdrop-filter: blur(8px); border-bottom: 1px solid var(--line); }
+.nav-inner { max-width: 1080px; margin: 0 auto; padding: 14px 24px; display: flex; align-items: center; justify-content: space-between; }
+.brand { display: flex; align-items: center; gap: 10px; font-weight: 700; font-size: 20px; color: var(--ink); }
+.brand-logo { display: inline-flex; align-items: center; justify-content: center; width: 34px; height: 34px; border-radius: 9px; background: linear-gradient(135deg, #10b981, #047857); color: #fff; font-weight: 800; }
+.nav-links { display: flex; gap: 26px; font-size: 15px; }
+.nav-links a { color: var(--muted); }
+.nav-links a:hover { color: var(--ink); }
+
+.hero { padding: 96px 0 84px; text-align: center; background: radial-gradient(1200px 500px at 50% -100px, rgba(16,185,129,.12), transparent); }
+.hero h1 { font-size: 46px; line-height: 1.25; letter-spacing: -1px; }
+.hero h1 em { font-style: normal; color: var(--brand); }
+.hero p.tagline { margin: 18px auto 0; max-width: 640px; font-size: 19px; color: var(--muted); }
+.hero-actions { margin-top: 34px; display: flex; gap: 14px; justify-content: center; flex-wrap: wrap; }
+.btn { display: inline-flex; align-items: center; gap: 8px; padding: 12px 26px; border-radius: 10px; font-size: 16px; font-weight: 600; border: 1px solid transparent; transition: all .15s; }
+.btn-primary { background: var(--brand); color: #fff; }
+.btn-primary:hover { background: var(--brand-dark); }
+.btn-outline { border-color: var(--line); color: var(--ink); background: var(--card); }
+.btn-outline:hover { border-color: var(--brand); color: var(--brand); }
+.hero-meta { margin-top: 26px; font-size: 14px; color: var(--muted); }
+
+section.block { padding: 72px 0; }
+section.block.alt { background: var(--card); border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
+.block h2 { font-size: 30px; text-align: center; }
+.block .sub { text-align: center; color: var(--muted); margin-top: 10px; margin-bottom: 44px; }
+
+.grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }
+.feature { background: var(--card); border: 1px solid var(--line); border-radius: 14px; padding: 26px; }
+.feature .icon { width: 42px; height: 42px; border-radius: 10px; display: flex; align-items: center; justify-content: center; background: rgba(16,185,129,.1); color: var(--brand); margin-bottom: 14px; }
+.feature h3 { font-size: 17px; margin-bottom: 8px; }
+.feature p { font-size: 14.5px; color: var(--muted); }
+
+.steps { max-width: 760px; margin: 0 auto; }
+.step { display: flex; gap: 18px; padding: 18px 0; border-bottom: 1px dashed var(--line); }
+.step:last-child { border-bottom: none; }
+.step .no { flex-shrink: 0; width: 34px; height: 34px; border-radius: 50%; background: var(--brand); color: #fff; font-weight: 700; display: flex; align-items: center; justify-content: center; }
+.step h3 { font-size: 16px; }
+.step p { font-size: 14.5px; color: var(--muted); margin-top: 4px; }
+code.inline { background: rgba(16,185,129,.08); color: var(--brand-dark); padding: 2px 7px; border-radius: 5px; font-size: 13.5px; font-family: ui-monospace, "SF Mono", Menlo, monospace; }
+
+.footer { padding: 40px 0 56px; color: var(--muted); font-size: 14px; text-align: center; }
+.footer .links { display: flex; gap: 22px; justify-content: center; margin-bottom: 14px; }
+
+@media (max-width: 840px) {
+ .grid { grid-template-columns: 1fr; }
+ .hero h1 { font-size: 34px; }
+ .nav-links { display: none; }
+}
diff --git a/homepage/dist/docs/access/index.html b/homepage/dist/docs/access/index.html
new file mode 100644
index 0000000..376d51a
--- /dev/null
+++ b/homepage/dist/docs/access/index.html
@@ -0,0 +1,33 @@
+
+
+
+查询授权 · LokiStack 文档
+
+
+
+
+
+
+
+
+
+ 查询授权
+ 采集与查询 · 更新于 2026-10-28
+ 管理员在「日志查询 → 查询授权」用策略组控制普通用户可见的日志范围:
+
+- 策略组 = 数据源 + 允许的标签范围(命名空间 / App / Pod,均精确匹配,未选不限) + 关联用户。
+- 同一用户在同一数据源只能属于一个策略组;已在其他组的用户置灰。
+- 支持快捷的「所有人」策略(默认策略的常用形态)。
+- 授权在服务端强制执行:普通用户的查询必须以流选择器开头,策略标签自动合并,无法越权。
+
+用户管理(仅管理员)支持创建/重置密码/批量删除;LDAP 用户可在系统设置接入后导入。
+
+
+
+
+
+
diff --git a/homepage/dist/docs/alerts/index.html b/homepage/dist/docs/alerts/index.html
new file mode 100644
index 0000000..404e393
--- /dev/null
+++ b/homepage/dist/docs/alerts/index.html
@@ -0,0 +1,48 @@
+
+
+
+告警通知 · LokiStack 文档
+
+
+
+
+
+
+
+
+
+ 告警通知
+ 告警与运维 · 更新于 2026-10-28
+ 「日志告警」页(/alerts)管理规则、通知通道与发送历史。
+
+快速开始
+
+- 在「通知通道」中编辑默认通道,填入飞书群机器人 Webhook 并启用。
+- 内置九条规则默认启用并已绑定默认通道,命中阈值即发送到群。
+
+规则
+
+- 查询为 LogQL 日志流匹配;窗口(分钟)、阈值(条数)、冷却(分钟)三要素。
+- 内置规则已排除 Loki 自身日志(app=loki),避免告警查询日志造成自我误报。
+- 模板按钮一键填充常用规则(命名空间错误 / Ingress 4xx5xx / FATAL 等)。
+
+通道与发送历史
+
+- 通道支持飞书 Webhook(可选签名);可建多通道对应不同告警群。
+- 发送历史记录每次触发的命中数、投递结果与失败原因;保留天数在「系统设置 → 日志保留时间」调整。
+
+防刷屏机制
+
+- 单规则冷却(默认 ≥ 2 小时);全平台每小时发送上限(风暴抑制)。
+- 通道未配置/未启用时命中只记入历史,不影响规则评估。
+
+
+
+
+
+
+
diff --git a/homepage/dist/docs/analysis/index.html b/homepage/dist/docs/analysis/index.html
new file mode 100644
index 0000000..6697567
--- /dev/null
+++ b/homepage/dist/docs/analysis/index.html
@@ -0,0 +1,84 @@
+
+
+
+日志分析 · LokiStack 文档
+
+
+
+
+
+
+
+
+
+ 日志分析
+ 采集与查询 · 更新于 2026-10-28
+ 「日志分析」页(/analysis,管理员)自动聚合日志指标,无需手动查询:
+
+
+- 统计卡:日志总量、日志体积、错误行数、活跃应用
+- 趋势折线:按时间分桶的日志体积(≤12 小时 15 分钟一桶,>12 小时 1 小时一桶)
+- 应用排行:按日志体积排 Top 10,支持 10/30/50 与前端分页,点击「查看日志」跳转查询页
+- 每日日志量:平台留存历史,支持 7 / 30 / 90 / 365 天切换(独立于上方时间范围)
+- Ingress 访问分析:自动识别 ingress-nginx 访问日志,PV/UV、状态码、慢请求与接口排行;未安装 ingress-nginx 时自动折叠
+
+数据来源与耗时
+
+
+
+| 数据 |
+来源 |
+耗时 |
+
+
+
+
+| 总量/体积趋势、总条数 |
+Loki 索引接口(index/volume_range、index/stats),只读 chunk 元数据 |
+百毫秒级 |
+
+
+| ≤1 小时范围的应用排行 |
+实时扫描日志内容(count_over_time) |
+5 分钟窗口约 5~10 秒 |
+
+
+| >1 小时范围的应用排行 |
+平台按小时预聚合快照(每小时第 5 分钟抓上一个完整小时) |
+毫秒级 |
+
+
+
+
+一次分析页要跑多条按应用的重查询,因此筛选栏改条件后点「刷新」才生效;
+应用排行卡片滚动到可视区才发起重查询,避免首屏一起等。
+
+应用排行的「体积」口径
+预聚合快照对每个应用每小时同时留存 条数 + 体积:
+
+- 条数走
count_over_time(要解码日志内容,一小时代价高,每小时后台跑一次)
+- 体积走
index/volume(Loki 索引接口,一个应用约 80ms,所以长范围排行也能按体积排序)
+
+体积优先排序的原因:条数会被高频短日志主导(一条 INFO 刷屏 vs 一条大 JSON),
+用户真正关心的是「哪个应用把日志量吃掉了」。
+体积列上线前抓的小时只有条数,页面会在表格下方提示
+「其中 N/M 小时有体积数据…」——不要把这个提示当成故障,
+它是在说明这段时间的体积偏小是采样口径问题,而不是应用体积真的小。
+每日日志量的「未留存」
+每日量来自平台自己的留存库(默认保留 400 天),不受 Loki retention(72 小时)限制。
+
+- 今天的柱子是「进行中」,每 30 分钟刷新一次;零点后 1 分钟结算前一天
+- 灰色柱 = 平台没有留存记录(平台当天没运行 / 超出留存期),不是「当天没有日志」
+- 如果缺失的天画成 0,30/90 天视角会出现大片空柱,容易被误读成「以前日志量很低」甚至「系统停摆过」
+
+时间范围与数据源在页面顶部切换;指标查询经服务端聚合,开销远低于拉取原始日志。
+
+
+
+
+
+
diff --git a/homepage/dist/docs/assets/docs.css b/homepage/dist/docs/assets/docs.css
new file mode 100644
index 0000000..28649df
--- /dev/null
+++ b/homepage/dist/docs/assets/docs.css
@@ -0,0 +1,255 @@
+/* OpsxAPI 文档站 —— 清爽专业风格(浅色) */
+:root {
+ --blue: #059669;
+ --blue-dark: #047857;
+ --blue-soft: rgba(5, 150, 105, 0.08);
+ --bg: #f6f8fb;
+ --panel: #ffffff;
+ --border: #e4e9f1;
+ --text: #1c2434;
+ --text-2: #5b6880;
+ --text-3: #98a2b3;
+ --code-bg: #f3f6fb;
+ --code-border: #e1e8f3;
+ --green: #059669;
+ --amber: #b45309;
+ --red: #dc2626;
+ --sidebar-w: 262px;
+ --toc-w: 220px;
+ --topbar-h: 56px;
+ --radius: 10px;
+ --shadow: 0 1px 3px rgba(16, 24, 40, 0.06), 0 8px 24px rgba(16, 24, 40, 0.05);
+ --mono: "JetBrains Mono", SFMono-Regular, Menlo, Consolas, monospace;
+}
+* { box-sizing: border-box; }
+html { scroll-behavior: smooth; scroll-padding-top: 72px; }
+body {
+ margin: 0;
+ font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Microsoft YaHei", "Segoe UI", sans-serif;
+ background: var(--bg);
+ color: var(--text);
+ font-size: 14.5px;
+ line-height: 1.75;
+}
+a { color: var(--blue); text-decoration: none; }
+.i { width: 15px; height: 15px; stroke: currentColor; fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; vertical-align: -2px; }
+a:hover { color: var(--blue-dark); text-decoration: underline; }
+
+/* ---------- 顶栏 ---------- */
+.topbar {
+ position: sticky; top: 0; z-index: 50;
+ background: rgba(255, 255, 255, 0.92);
+ backdrop-filter: saturate(1.4) blur(8px);
+ border-bottom: 1px solid var(--border);
+}
+.topbar-inner {
+ max-width: 1440px; margin: 0 auto; height: var(--topbar-h);
+ display: flex; align-items: center; gap: 14px; padding: 0 20px;
+}
+.menu-btn {
+ display: none; border: 1px solid var(--border); background: #fff;
+ border-radius: 8px; width: 34px; height: 34px; cursor: pointer; color: var(--text-2);
+ place-items: center;
+}
+.menu-btn .i { width: 17px; height: 17px; }
+.brand { display: flex; align-items: center; gap: 9px; text-decoration: none !important; }
+.brand-logo { display: inline-flex; }
+.brand-logo svg { display: block; border-radius: 7px; }
+.brand-name { font-size: 16px; font-weight: 700; color: var(--text); }
+.brand-name em { font-style: normal; font-weight: 500; color: var(--text-2); margin-left: 2px; }
+.ver-badge {
+ font-size: 11px; font-weight: 600; color: var(--blue);
+ background: var(--blue-soft); border: 1px solid rgba(5, 150, 105, 0.22);
+ padding: 1px 9px; border-radius: 999px; white-space: nowrap;
+}
+.search { position: relative; flex: 1; max-width: 420px; margin-left: 8px; }
+.search input {
+ width: 100%; height: 36px; border: 1px solid var(--border); border-radius: 9px;
+ background: var(--bg); padding: 0 14px 0 34px; font-size: 13.5px; color: var(--text); outline: none;
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' fill='none' stroke='%2398a2b3' stroke-width='2' viewBox='0 0 24 24'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='m20 20-3.5-3.5'/%3E%3C/svg%3E");
+ background-repeat: no-repeat; background-position: 12px center;
+}
+.search input:focus { border-color: var(--blue); background: #fff; box-shadow: 0 0 0 3px var(--blue-soft); }
+.search-panel {
+ position: absolute; top: 44px; left: 0; right: 0; background: #fff;
+ border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow);
+ max-height: 420px; overflow: auto; padding: 6px;
+}
+.search-item { display: block; padding: 8px 12px; border-radius: 8px; text-decoration: none !important; }
+.search-item:hover, .search-item.sel { background: var(--blue-soft); }
+.search-item .si-title { font-weight: 600; color: var(--text); font-size: 13.5px; }
+.search-item .si-group { color: var(--text-3); font-size: 11px; margin-left: 6px; }
+.search-item .si-snippet { color: var(--text-2); font-size: 12px; margin-top: 2px; display: block; }
+.search-empty { padding: 14px; text-align: center; color: var(--text-3); font-size: 13px; }
+.top-links { margin-left: auto; display: flex; gap: 16px; align-items: center; }
+.top-links a { font-size: 13.5px; font-weight: 500; }
+
+/* ---------- 三栏布局 ---------- */
+.layout {
+ max-width: 1440px; margin: 0 auto; display: grid;
+ grid-template-columns: var(--sidebar-w) minmax(0, 1fr) var(--toc-w);
+ gap: 0 28px; padding: 24px 20px 60px;
+}
+
+/* 侧栏 */
+.sidebar { position: sticky; top: calc(var(--topbar-h) + 24px); align-self: start; max-height: calc(100vh - var(--topbar-h) - 48px); overflow-y: auto; padding-right: 8px; }
+.sidebar::-webkit-scrollbar { width: 4px; }
+.sidebar::-webkit-scrollbar-thumb { background: #d6dde8; border-radius: 4px; }
+.nav-group { margin-bottom: 18px; }
+.nav-group-title {
+ font-size: 11.5px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
+ color: var(--text-3); padding: 0 10px 6px;
+}
+.nav-link {
+ display: block; padding: 6px 10px; border-radius: 8px; font-size: 13.5px;
+ color: var(--text-2); text-decoration: none !important; border-left: 2px solid transparent;
+}
+.nav-link:hover { background: rgba(5, 150, 105, 0.06); color: var(--text); }
+.nav-link.active {
+ background: var(--blue-soft); color: var(--blue-dark); font-weight: 600;
+ border-left-color: var(--blue);
+}
+.sidebar-foot { margin-top: 24px; padding: 12px 10px 0; border-top: 1px solid var(--border); font-size: 11.5px; color: var(--text-3); }
+
+/* 内容 */
+.content { min-width: 0; max-width: 860px; }
+.breadcrumb { font-size: 12.5px; color: var(--text-3); margin-bottom: 10px; }
+.breadcrumb span { margin: 0 6px; }
+.page-title { font-size: 30px; font-weight: 700; letter-spacing: -0.02em; margin: 0 0 6px; line-height: 1.3; }
+.page-meta { font-size: 12.5px; color: var(--text-3); margin-bottom: 22px; }
+
+/* Markdown 排版 */
+.md h2 { font-size: 21px; font-weight: 700; margin: 38px 0 12px; padding-top: 8px; letter-spacing: -0.01em; }
+.md h3 { font-size: 16.5px; font-weight: 700; margin: 26px 0 8px; }
+.md h2 + h3, .md h1 + h2 { margin-top: 18px; }
+.md p { margin: 10px 0; color: #2a3348; }
+.md ul, .md ol { padding-left: 22px; margin: 10px 0; }
+.md li { margin: 5px 0; color: #2a3348; }
+.md li::marker { color: var(--blue); }
+.md strong { color: var(--text); }
+.md hr { border: none; border-top: 1px solid var(--border); margin: 30px 0; }
+.md img { max-width: 100%; border-radius: var(--radius); border: 1px solid var(--border); }
+.md blockquote {
+ margin: 14px 0; padding: 10px 16px; border-left: 3px solid var(--blue);
+ background: var(--blue-soft); border-radius: 0 8px 8px 0; color: #33415e;
+}
+
+/* 表格 */
+.md table { border-collapse: collapse; width: 100%; margin: 16px 0; font-size: 13.5px; background: #fff; border-radius: var(--radius); overflow: hidden; box-shadow: 0 0 0 1px var(--border); }
+.md th, .md td { padding: 9px 14px; text-align: left; border-bottom: 1px solid var(--border); vertical-align: top; }
+.md th { background: #f9fbfe; font-weight: 600; color: var(--text); white-space: nowrap; }
+.md tr:last-child td { border-bottom: none; }
+
+/* 代码块 */
+.md code { font-family: var(--mono); font-size: 12.8px; background: var(--code-bg); border: 1px solid var(--code-border); border-radius: 5px; padding: 1px 6px; color: #334155; }
+.md pre {
+ position: relative; background: #0f172a; color: #dbe4f3; border-radius: var(--radius);
+ padding: 16px 16px 14px; overflow-x: auto; margin: 16px 0; font-size: 13px; line-height: 1.65;
+}
+.md pre code { background: none; border: none; color: inherit; padding: 0; font-size: inherit; }
+.md pre .lang-tag {
+ position: absolute; top: 8px; right: 12px; font-size: 10.5px; color: #7c8db0;
+ font-family: var(--mono); text-transform: lowercase; letter-spacing: 0.04em;
+}
+.md pre .copy-btn {
+ position: absolute; top: 6px; right: 60px; font-size: 11px; color: #9fb0d0;
+ background: rgba(255, 255, 255, 0.07); border: none; border-radius: 6px; padding: 2px 9px; cursor: pointer;
+ opacity: 0; transition: opacity 0.15s;
+}
+.md pre:hover .copy-btn { opacity: 1; }
+.md pre .copy-btn:hover { color: #fff; background: rgba(255, 255, 255, 0.14); }
+/* 行内高亮 token */
+.md pre .tok-key { color: #7dd3fc; }
+.md pre .tok-str { color: #86efac; }
+.md pre .tok-num { color: #fcd34d; }
+.md pre .tok-com { color: #64748b; font-style: italic; }
+
+/* 提示块(通过 blockquote 首字符约定) */
+.md blockquote.tip { border-left-color: var(--green); background: rgba(5, 150, 105, 0.07); }
+.md blockquote.warn { border-left-color: var(--amber); background: rgba(180, 83, 9, 0.07); }
+
+/* 上下页 */
+.pn-nav { display: flex; gap: 14px; margin-top: 48px; }
+.pn {
+ flex: 1; border: 1px solid var(--border); background: #fff; border-radius: var(--radius);
+ padding: 13px 16px; text-decoration: none !important; transition: border-color 0.15s, box-shadow 0.15s;
+}
+.pn:hover { border-color: var(--blue); box-shadow: var(--shadow); }
+.pn.next { text-align: right; }
+.pn-label { display: block; font-size: 11.5px; color: var(--text-3); }
+.pn-title { display: block; font-weight: 600; color: var(--text); font-size: 14px; margin-top: 2px; }
+
+/* 右侧目录 */
+.toc { position: sticky; top: calc(var(--topbar-h) + 24px); align-self: start; max-height: calc(100vh - var(--topbar-h) - 48px); overflow-y: auto; padding-top: 34px; }
+.toc-title { font-size: 11.5px; font-weight: 700; letter-spacing: 0.08em; color: var(--text-3); margin-bottom: 8px; }
+.toc-nav { display: flex; flex-direction: column; gap: 1px; border-left: 2px solid var(--border); padding-left: 0; }
+.toc-nav a {
+ font-size: 12.5px; color: var(--text-2); padding: 4px 0 4px 12px; text-decoration: none !important;
+ border-left: 2px solid transparent; margin-left: -2px; line-height: 1.5;
+}
+.toc-nav a:hover { color: var(--blue); }
+.toc-nav a.toc-l3 { padding-left: 26px; font-size: 12px; color: var(--text-3); }
+.toc-nav a.active { color: var(--blue); border-left-color: var(--blue); font-weight: 600; }
+/* 404 */
+.doc-404 { display: grid; place-items: center; min-height: 100vh; text-align: center; }
+.doc-404 h1 { font-size: 56px; margin: 0; color: var(--blue); }
+.doc-404 .btn {
+ display: inline-block; margin-top: 12px; background: var(--blue); color: #fff;
+ padding: 8px 18px; border-radius: 8px; text-decoration: none !important; font-weight: 600;
+}
+
+/* ---------- 响应式 ---------- */
+@media (max-width: 1200px) {
+ .layout { grid-template-columns: var(--sidebar-w) minmax(0, 1fr); }
+ .toc { display: none; }
+}
+@media (max-width: 880px) {
+ .menu-btn { display: inline-grid; place-items: center; }
+ .layout { grid-template-columns: minmax(0, 1fr); padding-top: 12px; }
+ .sidebar {
+ position: fixed; z-index: 60; left: 0; top: var(--topbar-h); bottom: 0;
+ width: 280px; background: #fff; border-right: 1px solid var(--border);
+ padding: 16px; transform: translateX(-100%); transition: transform 0.2s; max-height: none;
+ }
+ .sidebar.open { transform: none; box-shadow: var(--shadow); }
+ .ver-badge { display: none; }
+ .top-links a { font-size: 12.5px; }
+ .page-title { font-size: 24px; }
+}
+
+/* ---------- 打印 ---------- */
+@media print {
+ .topbar, .sidebar, .toc, .pn-nav, .feedback, .menu-btn { display: none !important; }
+ .layout { display: block; max-width: none; padding: 0; }
+ body { background: #fff; }
+ .md pre { background: #f1f5f9 !important; color: #1e293b !important; }
+ .md pre .copy-btn, .md pre .lang-tag { display: none; }
+}
+
+/* ---------- LokiStack 品牌适配 ---------- */
+.brand-logo {
+ display: inline-flex; align-items: center; justify-content: center;
+ width: 28px; height: 28px; border-radius: 8px;
+ background: linear-gradient(135deg, #10b981, #047857);
+ color: #fff; font-weight: 800; font-size: 17px;
+}
+
+/* 响应式(窄屏收起侧栏与目录) */
+@media (max-width: 1100px) {
+ .layout { grid-template-columns: var(--sidebar-w) minmax(0, 1fr); }
+ .toc { display: none; }
+}
+@media (max-width: 860px) {
+ .layout { grid-template-columns: minmax(0, 1fr); padding: 16px 14px 40px; }
+ .menu-btn { display: grid; }
+ .sidebar {
+ position: fixed; z-index: 60; top: var(--topbar-h); left: 0; bottom: 0;
+ width: var(--sidebar-w); background: #fff; border-right: 1px solid var(--border);
+ transform: translateX(-100%); transition: transform 0.2s; max-height: none; padding: 14px 10px;
+ }
+ .sidebar.open { transform: none; box-shadow: var(--shadow); }
+ .search { max-width: none; }
+ .top-links { display: none; }
+}
+
+.pn-empty { flex: 1; }
diff --git a/homepage/dist/docs/assets/docs.js b/homepage/dist/docs/assets/docs.js
new file mode 100644
index 0000000..833ffde
--- /dev/null
+++ b/homepage/dist/docs/assets/docs.js
@@ -0,0 +1,196 @@
+/* LokiStack 文档站交互:搜索 / 代码复制 / 目录高亮 / 移动端导航(参考 opsxapi 体系) */
+(function () {
+ "use strict";
+
+ /* ---------- 代码块:语言标签 + 复制按钮 + 轻量高亮 ---------- */
+ document.querySelectorAll("article.md pre").forEach(function (pre) {
+ var code = pre.querySelector("code");
+ if (!code) return;
+ var lang = (code.className.match(/language-([\w-]+)/) || [, ""])[1];
+ if (lang) {
+ var tag = document.createElement("span");
+ tag.className = "lang-tag";
+ tag.textContent = lang;
+ pre.appendChild(tag);
+ }
+ // 复制按钮
+ var btn = document.createElement("button");
+ btn.className = "copy-btn";
+ btn.type = "button";
+ btn.textContent = "复制";
+ btn.addEventListener("click", function () {
+ navigator.clipboard.writeText(code.textContent).then(
+ function () {
+ btn.textContent = "已复制 ✓";
+ setTimeout(function () { btn.textContent = "复制"; }, 1400);
+ },
+ function () { btn.textContent = "复制失败"; }
+ );
+ });
+ pre.appendChild(btn);
+ // JSON / bash 轻量高亮
+ if (lang === "json") highlightJSON(code);
+ else if (lang === "bash" || lang === "sh" || lang === "shell") highlightBash(code);
+ });
+
+ function esc(s) {
+ return s.replace(/&/g, "&").replace(//g, ">");
+ }
+ function highlightJSON(code) {
+ var src = code.textContent;
+ code.innerHTML = esc(src).replace(
+ /("(?:\\.|[^"\\])*")(\s*:)?|\b(true|false|null)\b|(-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?)/g,
+ function (m, str, colon, kw, num) {
+ if (str && colon) return '' + str + "" + colon;
+ if (str) return '' + str + "";
+ if (kw) return '' + kw + "";
+ if (num) return '' + num + "";
+ return m;
+ }
+ );
+ }
+ function highlightBash(code) {
+ var lines = code.textContent.split("\n");
+ code.innerHTML = lines
+ .map(function (line) {
+ if (/^\s*#/.test(line)) return '' + esc(line) + "";
+ return esc(line).replace(/(^|\s)(-{1,2}[\w-]+)/g, '$1$2');
+ })
+ .join("\n");
+ }
+
+ /* ---------- blockquote 提示样式约定:> **提示** / > **注意** ---------- */
+ document.querySelectorAll("article.md blockquote").forEach(function (bq) {
+ var t = (bq.textContent || "").trim();
+ if (/^(注意|警告|⚠)/.test(t)) bq.classList.add("warn");
+ else if (/^(提示|说明|💡|Tip)/i.test(t)) bq.classList.add("tip");
+ });
+
+ /* ---------- 搜索 ---------- */
+ var input = document.getElementById("search-input");
+ var panel = document.getElementById("search-panel");
+ var entries = null;
+ var selIndex = -1;
+
+ function ensureIndex(cb) {
+ if (entries) return cb();
+ fetch("/docs/search-data.json")
+ .then(function (r) { return r.json(); })
+ .then(function (data) { entries = data; cb(); })
+ .catch(function () { entries = []; cb(); });
+ }
+
+ function snippet(text, q) {
+ var i = text.toLowerCase().indexOf(q);
+ if (i < 0) return text.slice(0, 60) + "…";
+ var start = Math.max(0, i - 24);
+ return (start > 0 ? "…" : "") + text.slice(start, i + q.length + 40) + "…";
+ }
+
+ function doSearch() {
+ var q = input.value.trim().toLowerCase();
+ selIndex = -1;
+ if (!q) { panel.hidden = true; return; }
+ ensureIndex(function () {
+ var hits = [];
+ entries.forEach(function (e) {
+ var titleHit = e.title.toLowerCase().indexOf(q) >= 0;
+ var idx = e.text.toLowerCase().indexOf(q);
+ if (titleHit || idx >= 0) {
+ hits.push({
+ slug: e.slug,
+ title: e.title,
+ group: e.group,
+ score: (titleHit ? 10 : 0) + (idx === 0 ? 3 : 0),
+ snippet: titleHit ? snippet(e.text, q) : snippet(e.text, q),
+ });
+ }
+ });
+ hits.sort(function (a, b) { return b.score - a.score; });
+ hits = hits.slice(0, 8);
+ if (!hits.length) {
+ panel.innerHTML = '没有找到相关内容,换个关键词试试
';
+ } else {
+ panel.innerHTML = hits
+ .map(function (h) {
+ return (
+ '' +
+ '' + h.title + '' + h.group + "" +
+ '' + h.snippet + ""
+ );
+ })
+ .join("");
+ }
+ panel.hidden = false;
+ });
+ }
+
+ var debounce;
+ if (input) {
+ input.addEventListener("input", function () {
+ clearTimeout(debounce);
+ debounce = setTimeout(doSearch, 160);
+ });
+ input.addEventListener("focus", function () {
+ if (input.value.trim()) doSearch();
+ });
+ input.addEventListener("keydown", function (e) {
+ var items = panel.querySelectorAll(".search-item");
+ if (e.key === "ArrowDown" && items.length) {
+ e.preventDefault();
+ selIndex = Math.min(selIndex + 1, items.length - 1);
+ } else if (e.key === "ArrowUp" && items.length) {
+ e.preventDefault();
+ selIndex = Math.max(selIndex - 1, 0);
+ } else if (e.key === "Enter") {
+ if (selIndex >= 0 && items[selIndex]) { location.href = items[selIndex].href; return; }
+ var first = items[0];
+ if (first) location.href = first.href;
+ return;
+ } else if (e.key === "Escape") {
+ panel.hidden = true;
+ return;
+ } else {
+ return;
+ }
+ items.forEach(function (el, i) { el.classList.toggle("sel", i === selIndex); });
+ });
+ document.addEventListener("click", function (e) {
+ if (!e.target.closest(".search")) panel.hidden = true;
+ });
+ }
+
+ /* ---------- 目录滚动高亮 ---------- */
+ var tocLinks = Array.prototype.slice.call(document.querySelectorAll(".toc-nav a"));
+ if (tocLinks.length && "IntersectionObserver" in window) {
+ var byId = {};
+ tocLinks.forEach(function (a) { byId[a.getAttribute("href").slice(1)] = a; });
+ var io = new IntersectionObserver(
+ function (entries) {
+ entries.forEach(function (en) {
+ if (en.isIntersecting) {
+ tocLinks.forEach(function (a) { a.classList.remove("active"); });
+ var a = byId[en.target.id];
+ if (a) a.classList.add("active");
+ }
+ });
+ },
+ { rootMargin: "-72px 0px -70% 0px", threshold: 0 }
+ );
+ document.querySelectorAll("article.md h2[id], article.md h3[id]").forEach(function (h) { io.observe(h); });
+ }
+
+
+
+ /* ---------- 移动端侧栏 ---------- */
+ var menuBtn = document.getElementById("menu-btn");
+ var sidebar = document.getElementById("sidebar");
+ if (menuBtn && sidebar) {
+ menuBtn.addEventListener("click", function () { sidebar.classList.toggle("open"); });
+ document.addEventListener("click", function (e) {
+ if (sidebar.classList.contains("open") && !e.target.closest(".sidebar") && !e.target.closest(".menu-btn")) {
+ sidebar.classList.remove("open");
+ }
+ });
+ }
+})();
diff --git a/homepage/dist/docs/assets/loki-docs.css b/homepage/dist/docs/assets/loki-docs.css
new file mode 100644
index 0000000..13c3f73
--- /dev/null
+++ b/homepage/dist/docs/assets/loki-docs.css
@@ -0,0 +1,38 @@
+
+:root{--brand:#059669;--brand-d: #047857;--ink:#0f172a;--muted:#5b6676;--line:#e6e9ee;--bg:#fff;--side:#f7f9f8}
+*{box-sizing:border-box}
+body{margin:0;font:15px/1.75 -apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Hiragino Sans GB","Microsoft YaHei",sans-serif;color:var(--ink);background:var(--bg)}
+a{color:var(--brand-d);text-decoration:none}a:hover{text-decoration:underline}
+.topbar{position:sticky;top:0;z-index:20;display:flex;align-items:center;gap:18px;height:56px;padding:0 20px;background:rgba(255,255,255,.92);backdrop-filter:blur(8px);border-bottom:1px solid var(--line)}
+.brand{display:flex;align-items:center;gap:9px;font-weight:800;font-size:15px;color:var(--ink)}
+.brand i{width:26px;height:26px;border-radius:8px;background:var(--brand);color:#fff;display:grid;place-items:center;font-style:normal;font-weight:800;font-size:14px}
+.topnav{display:flex;gap:16px;margin-left:auto;font-size:14px}
+.topnav a{color:var(--muted)}.topnav a:hover{color:var(--brand-d)}
+.layout{display:grid;grid-template-columns:250px minmax(0,1fr) 200px;gap:34px;max-width:1240px;margin:0 auto;padding:26px 20px 70px}
+aside.side{position:sticky;top:80px;align-self:start;max-height:calc(100vh - 100px);overflow:auto;font-size:14px}
+.side h4{margin:18px 0 6px;font-size:11px;letter-spacing:.09em;text-transform:uppercase;color:#93a0af;font-weight:700}
+.side a{display:block;padding:5px 10px;border-radius:7px;color:#3b4656}
+.side a:hover{background:var(--side);text-decoration:none}
+.side a.on{background:#e8f7f1;color:var(--brand-d);font-weight:650}
+article{min-width:0}
+article h1{font-size:30px;line-height:1.3;margin:0 0 8px;letter-spacing:-.01em}
+.meta{color:#98a2b3;font-size:12.5px;margin-bottom:22px}
+article h2{font-size:21px;margin:32px 0 10px;padding-bottom:7px;border-bottom:1px solid var(--line)}
+article h3{font-size:17px;margin:24px 0 8px}
+article p{margin:12px 0}
+article img{max-width:100%;height:auto;border:1px solid var(--line);border-radius:10px;margin:14px 0;box-shadow:0 1px 3px rgba(16,24,40,.06)}
+article pre{background:#0f172a;color:#e6edf3;padding:14px 16px;border-radius:10px;overflow:auto;font-size:13px;line-height:1.6}
+article code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:13px}
+article :not(pre)>code{background:#f1f5f9;padding:2px 5px;border-radius:5px;color:#0f766e}
+article table{border-collapse:collapse;width:100%;margin:14px 0;font-size:14px}
+article th,article td{border:1px solid var(--line);padding:8px 10px;text-align:left}
+article th{background:var(--side)}
+article blockquote{margin:14px 0;padding:10px 16px;border-left:3px solid var(--brand);background:#f4fbf8;color:#33415c;border-radius:0 8px 8px 0}
+.toc{position:sticky;top:84px;align-self:start;font-size:13px;color:var(--muted)}
+.toc b{display:block;font-size:11px;letter-spacing:.09em;text-transform:uppercase;color:#93a0af;margin-bottom:8px}
+.toc a{display:block;padding:3px 0 3px 10px;border-left:2px solid var(--line);color:#5b6676}
+.toc a:hover{color:var(--brand-d);border-color:var(--brand)}
+.pager{display:flex;justify-content:space-between;gap:16px;margin-top:46px;padding-top:18px;border-top:1px solid var(--line);font-size:14px}
+footer{border-top:1px solid var(--line);padding:20px;text-align:center;color:#98a2b3;font-size:12.5px}
+@media (max-width:1080px){.layout{grid-template-columns:230px minmax(0,1fr)}.toc{display:none}}
+@media (max-width:820px){.layout{grid-template-columns:1fr;padding-top:16px}aside.side{position:static;max-height:none;border-bottom:1px solid var(--line);padding-bottom:10px}.topnav{display:none}}
diff --git a/homepage/dist/docs/assets/screenshots/alerts.png b/homepage/dist/docs/assets/screenshots/alerts.png
new file mode 100644
index 0000000..1cd0861
Binary files /dev/null and b/homepage/dist/docs/assets/screenshots/alerts.png differ
diff --git a/homepage/dist/docs/assets/screenshots/analysis.png b/homepage/dist/docs/assets/screenshots/analysis.png
new file mode 100644
index 0000000..bf97022
Binary files /dev/null and b/homepage/dist/docs/assets/screenshots/analysis.png differ
diff --git a/homepage/dist/docs/assets/screenshots/dashboard.png b/homepage/dist/docs/assets/screenshots/dashboard.png
new file mode 100644
index 0000000..41824fc
Binary files /dev/null and b/homepage/dist/docs/assets/screenshots/dashboard.png differ
diff --git a/homepage/dist/docs/assets/screenshots/logs-query.png b/homepage/dist/docs/assets/screenshots/logs-query.png
new file mode 100644
index 0000000..4a31a65
Binary files /dev/null and b/homepage/dist/docs/assets/screenshots/logs-query.png differ
diff --git a/homepage/dist/docs/assets/screenshots/settings.png b/homepage/dist/docs/assets/screenshots/settings.png
new file mode 100644
index 0000000..e400d08
Binary files /dev/null and b/homepage/dist/docs/assets/screenshots/settings.png differ
diff --git a/homepage/dist/docs/assets/screenshots/wizard.png b/homepage/dist/docs/assets/screenshots/wizard.png
new file mode 100644
index 0000000..9bee585
Binary files /dev/null and b/homepage/dist/docs/assets/screenshots/wizard.png differ
diff --git a/homepage/dist/docs/assets/site.css b/homepage/dist/docs/assets/site.css
new file mode 100644
index 0000000..ad537a5
--- /dev/null
+++ b/homepage/dist/docs/assets/site.css
@@ -0,0 +1,58 @@
+:root {
+ --brand: #059669; --brand-dark: #047857; --ink: #0f172a; --muted: #64748b;
+ --bg: #f8fafc; --card: #ffffff; --line: #e2e8f0;
+ --code-bg: #0f172a; --code-ink: #e2e8f0;
+}
+* { margin: 0; padding: 0; box-sizing: border-box; }
+html { scroll-behavior: smooth; }
+body { font-family: -apple-system, "PingFang SC", "Microsoft YaHei", "Segoe UI", sans-serif; color: var(--ink); background: var(--bg); line-height: 1.7; }
+a { color: var(--brand); text-decoration: none; }
+.container { max-width: 1080px; margin: 0 auto; padding: 0 24px; }
+
+.nav { position: sticky; top: 0; z-index: 10; background: rgba(255,255,255,.92); backdrop-filter: blur(8px); border-bottom: 1px solid var(--line); }
+.nav-inner { max-width: 1080px; margin: 0 auto; padding: 14px 24px; display: flex; align-items: center; justify-content: space-between; }
+.brand { display: flex; align-items: center; gap: 10px; font-weight: 700; font-size: 20px; color: var(--ink); }
+.brand-logo { display: inline-flex; align-items: center; justify-content: center; width: 34px; height: 34px; border-radius: 9px; background: linear-gradient(135deg, #10b981, #047857); color: #fff; font-weight: 800; }
+.nav-links { display: flex; gap: 26px; font-size: 15px; }
+.nav-links a { color: var(--muted); }
+.nav-links a:hover { color: var(--ink); }
+
+.hero { padding: 96px 0 84px; text-align: center; background: radial-gradient(1200px 500px at 50% -100px, rgba(16,185,129,.12), transparent); }
+.hero h1 { font-size: 46px; line-height: 1.25; letter-spacing: -1px; }
+.hero h1 em { font-style: normal; color: var(--brand); }
+.hero p.tagline { margin: 18px auto 0; max-width: 640px; font-size: 19px; color: var(--muted); }
+.hero-actions { margin-top: 34px; display: flex; gap: 14px; justify-content: center; flex-wrap: wrap; }
+.btn { display: inline-flex; align-items: center; gap: 8px; padding: 12px 26px; border-radius: 10px; font-size: 16px; font-weight: 600; border: 1px solid transparent; transition: all .15s; }
+.btn-primary { background: var(--brand); color: #fff; }
+.btn-primary:hover { background: var(--brand-dark); }
+.btn-outline { border-color: var(--line); color: var(--ink); background: var(--card); }
+.btn-outline:hover { border-color: var(--brand); color: var(--brand); }
+.hero-meta { margin-top: 26px; font-size: 14px; color: var(--muted); }
+
+section.block { padding: 72px 0; }
+section.block.alt { background: var(--card); border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
+.block h2 { font-size: 30px; text-align: center; }
+.block .sub { text-align: center; color: var(--muted); margin-top: 10px; margin-bottom: 44px; }
+
+.grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }
+.feature { background: var(--card); border: 1px solid var(--line); border-radius: 14px; padding: 26px; }
+.feature .icon { width: 42px; height: 42px; border-radius: 10px; display: flex; align-items: center; justify-content: center; background: rgba(16,185,129,.1); color: var(--brand); margin-bottom: 14px; }
+.feature h3 { font-size: 17px; margin-bottom: 8px; }
+.feature p { font-size: 14.5px; color: var(--muted); }
+
+.steps { max-width: 760px; margin: 0 auto; }
+.step { display: flex; gap: 18px; padding: 18px 0; border-bottom: 1px dashed var(--line); }
+.step:last-child { border-bottom: none; }
+.step .no { flex-shrink: 0; width: 34px; height: 34px; border-radius: 50%; background: var(--brand); color: #fff; font-weight: 700; display: flex; align-items: center; justify-content: center; }
+.step h3 { font-size: 16px; }
+.step p { font-size: 14.5px; color: var(--muted); margin-top: 4px; }
+code.inline { background: rgba(16,185,129,.08); color: var(--brand-dark); padding: 2px 7px; border-radius: 5px; font-size: 13.5px; font-family: ui-monospace, "SF Mono", Menlo, monospace; }
+
+.footer { padding: 40px 0 56px; color: var(--muted); font-size: 14px; text-align: center; }
+.footer .links { display: flex; gap: 22px; justify-content: center; margin-bottom: 14px; }
+
+@media (max-width: 840px) {
+ .grid { grid-template-columns: 1fr; }
+ .hero h1 { font-size: 34px; }
+ .nav-links { display: none; }
+}
diff --git a/homepage/dist/docs/collectors/index.html b/homepage/dist/docs/collectors/index.html
new file mode 100644
index 0000000..b14a0b1
--- /dev/null
+++ b/homepage/dist/docs/collectors/index.html
@@ -0,0 +1,39 @@
+
+
+
+日志采集 · LokiStack 文档
+
+
+
+
+
+
+
+
+
+ 日志采集
+ 采集与查询 · 更新于 2026-10-28
+ 「日志采集」页管理采集策略:主机采集(Promtail)与集群采集(DaemonSet / Fluent Bit Sidecar)。
+采集范围
+
+- 集群采集:命名空间多选(默认全集群);app 标签按
app.kubernetes.io/name → app → controller 名 → pod 名 四级回退,可自定义来源标签与 app 白名单收敛日志量。
+- 主机采集:填写业务日志路径(glob 通配,如
/var/log/app/*.log);系统日志自动探测(syslog / messages)。
+- 敏感路径(/etc/shadow、私钥、/proc 等)会被平台拦截,防止主机凭据进入日志平台。
+
+编辑与下发
+保存后点击「部署」下发到目标;「预览 YAML」可先核对将生成的 promtail 配置。修改后同样以「部署」生效。
+排查
+
+- 采集器卡片可看运行状态与日志(主机 docker logs / journalctl,集群 Pod 日志)。
+- 常见问题:目标命名空间无工作负载(app 候选为空)、路径无写入权限、Loki 端点不可达。
+
+
+
+
+
+
+
diff --git a/homepage/dist/docs/faq/index.html b/homepage/dist/docs/faq/index.html
new file mode 100644
index 0000000..8d96e5e
--- /dev/null
+++ b/homepage/dist/docs/faq/index.html
@@ -0,0 +1,39 @@
+
+
+
+常见问题 · LokiStack 文档
+
+
+
+
+
+
+
+
+
+ 常见问题
+ 告警与运维 · 更新于 2026-10-28
+ 登录后看不到「部署向导」「用户管理」等菜单?
+这些页面仅管理员可见。普通用户默认只有日志查询与日志告警;查询范围由策略组控制(见查询授权)。
+部署的 Loki 怎么访问?必须配 Ingress 吗?
+集群内部署经 API Server Service Proxy 查询,不需要 Ingress。跨集群 / 公网查询才需要为 Loki 暴露域名后在「数据源管理」用 URL 直连关联。
+「停止部署」会删掉日志数据吗?
+不会。停止只回收工作负载;数据卷(PVC / 主机数据目录)保留,重新启动即可恢复。仅显式删除部署记录不影响远端资源,卸载需按页面指引执行。
+告警一直不发送?
+按顺序检查:通道是否启用、Webhook 是否正确(通道页有测试)、规则是否启用且命中阈值、发送历史里是否有「冷却抑制」或失败原因。通道未就绪时历史会明确记录失败原因。
+忘记管理员密码?
+管理员可在「用户管理」重置任意账号密码;若唯一管理员丢失密码,参考仓库 README 的离线重置说明。
+平台可以多实例部署吗?
+不可以。JSON 文件存储为单实例设计(防抖串行落盘),水平扩展会互相覆盖;需要高可用时请保持单实例并对数据目录做系统级快照。
+升级安全吗?
+配置与数据向后兼容,结构变更按 schema 版本自动迁移;建议升级前对数据目录(lokistack.json)做一次文件级拷贝。
+
+
+
+
+
+
diff --git a/homepage/dist/docs/index.html b/homepage/dist/docs/index.html
new file mode 100644
index 0000000..eb9e08a
--- /dev/null
+++ b/homepage/dist/docs/index.html
@@ -0,0 +1,46 @@
+
+
+
+LokiStack 用户手册 · LokiStack 文档
+
+
+
+
+
+
+
+
+
+ LokiStack 用户手册
+ 开始使用 · 更新于 2026-10-28
+ LokiStack 把 Grafana Loki 日志聚合的部署、采集、查询、分析与告警收进一个平台:向导式部署到 Kubernetes 集群或裸金属主机,内置中文/英文界面,单二进制交付。
+平台能做什么
+
+- 部署 Loki:三步向导(环境与目标 → 存储 → 部署与采集),支持 Kubernetes(YAML 直发)、裸金属二进制、主机 Docker 三种模式,不需要在平台所在机器安装 kubectl 或 Helm。
+- 采集日志:Promtail / Fluent Bit 采集策略可视化配置,命名空间多选、app 标签来源四级回退、敏感路径拦截。
+- 查询与分析:LogQL 高亮补全、快捷查询、Live Tail;分析页自动聚合日志量、错误与 Ingress 访问指标。
+- 告警:内置九条应用日志规则,绑定默认通道后填入飞书 Webhook 即可接收;支持冷却与风暴抑制。
+- 运维底座:凭证加密存储、操作审计、标准 Prometheus 指标端点(/api/v1/metrics)。
+
+界面预览
+
+
+下一步
+阅读快速安装,或直接进入部署向导。
+
+
+
+
+
+
diff --git a/homepage/dist/docs/install/index.html b/homepage/dist/docs/install/index.html
new file mode 100644
index 0000000..26daa7d
--- /dev/null
+++ b/homepage/dist/docs/install/index.html
@@ -0,0 +1,43 @@
+
+
+
+快速安装 · LokiStack 文档
+
+
+
+
+
+
+
+
+
+ 快速安装
+ 开始使用 · 更新于 2026-10-28
+ 方式一:Kubernetes
+bash kubernetes/install.sh
+
+方式二:Docker
+docker compose up -d
+
+方式三:单二进制
+curl -LO https://gitea.91ai.io/rlwj-lab/LokiStack/releases/download/v2.0.0/lokistack-linux-amd64.tar.gz
+tar xzf lokistack-linux-amd64.tar.gz && cd lokistack-linux-amd64
+./lokistack
+
+arm64 服务器下载 lokistack-linux-arm64.tar.gz。
+说明
+
+- 未提供
JWT_SECRET / ENCRYPTION_KEY 时,自动生成随机密钥并持久化到数据目录(.secrets.env,权限 0600),重启与升级保持不变;显式设置环境变量可随时覆盖
+- 全部状态存储在
$DATA_DIR/lokistack.json,单实例运行;首次启动自动创建管理员账号,初始密码在 $DATA_DIR/initial-admin-password.txt
+- 升级:替换二进制或重新拉取镜像后重启,历史数据自动迁移
+
+
+
+
+
+
+
diff --git a/homepage/dist/docs/query/index.html b/homepage/dist/docs/query/index.html
new file mode 100644
index 0000000..5de2c6c
--- /dev/null
+++ b/homepage/dist/docs/query/index.html
@@ -0,0 +1,42 @@
+
+
+
+日志查询 · LokiStack 文档
+
+
+
+
+
+
+
+
+
+ 日志查询
+ 采集与查询 · 更新于 2026-10-28
+ 「日志查询」页(/logs)按 LogQL 与时间范围检索日志。
+
+查询方式
+
+- LogQL 编辑器:语法高亮与标签/管道补全;回车执行。
+- 快捷查询:先选命名空间,再选 App / Pod(候选值按级联懒加载:选了命名空间才会去取 App 列表,选了 App 才取 Pod 列表,避免一进页面就把 Loki 索引扫一遍),选中即自动填入并执行;Ingress 访问日志按钮在选择 ingress 命名空间或 app 时出现。
+- Label 浏览器:按标签与值点选构建查询;点结果行的标签值可快速加过滤。
+- Live Tail:3 秒轮询最近 5 分钟,编辑查询自动防抖后切换。
+
+结果区
+
+- 顶部时间线展示整个查询范围的日志量,拖选高峰时段自动重查。
+- 原始日志支持关键字高亮、标签过滤、查看上下文(前后 N 行)。
+- 翻页向后游标推进,每页最多 1000 条。
+
+数据源
+「数据源管理」维护 Loki 连接:平台部署自动注册(随部署托管),也可手动添加 URL 直连或集群 Service 数据源,支持 Basic / Bearer / 自定义 Header 认证与连接测试。
+
+
+
+
+
+
diff --git a/homepage/dist/docs/readme/index.html b/homepage/dist/docs/readme/index.html
new file mode 100644
index 0000000..eb9e08a
--- /dev/null
+++ b/homepage/dist/docs/readme/index.html
@@ -0,0 +1,46 @@
+
+
+
+LokiStack 用户手册 · LokiStack 文档
+
+
+
+
+
+
+
+
+
+ LokiStack 用户手册
+ 开始使用 · 更新于 2026-10-28
+ LokiStack 把 Grafana Loki 日志聚合的部署、采集、查询、分析与告警收进一个平台:向导式部署到 Kubernetes 集群或裸金属主机,内置中文/英文界面,单二进制交付。
+平台能做什么
+
+- 部署 Loki:三步向导(环境与目标 → 存储 → 部署与采集),支持 Kubernetes(YAML 直发)、裸金属二进制、主机 Docker 三种模式,不需要在平台所在机器安装 kubectl 或 Helm。
+- 采集日志:Promtail / Fluent Bit 采集策略可视化配置,命名空间多选、app 标签来源四级回退、敏感路径拦截。
+- 查询与分析:LogQL 高亮补全、快捷查询、Live Tail;分析页自动聚合日志量、错误与 Ingress 访问指标。
+- 告警:内置九条应用日志规则,绑定默认通道后填入飞书 Webhook 即可接收;支持冷却与风暴抑制。
+- 运维底座:凭证加密存储、操作审计、标准 Prometheus 指标端点(/api/v1/metrics)。
+
+界面预览
+
+
+下一步
+阅读快速安装,或直接进入部署向导。
+
+
+
+
+
+
diff --git a/homepage/dist/docs/wizard/index.html b/homepage/dist/docs/wizard/index.html
new file mode 100644
index 0000000..efadc02
--- /dev/null
+++ b/homepage/dist/docs/wizard/index.html
@@ -0,0 +1,67 @@
+
+
+
+部署向导 · LokiStack 文档
+
+
+
+
+
+
+
+
+
+ 部署向导
+ 开始使用 · 更新于 2026-10-28
+ 部署向导(/wizard)三步完成 Loki 上线:环境与目标 → 存储 → 部署 Loki 与采集。
+
+第一步:环境与目标
+
+- Kubernetes 集群:粘贴 kubeconfig,或按页面给出的 RBAC 脚本在集群执行一次后粘贴 ServiceAccount 长期 Token。平台经 API Server 操作集群,无需安装 kubectl/Helm。
+- 裸金属主机:填写 SSH 地址与凭证(密码或私钥,AES-GCM 加密存储)。适合二进制或 Docker 模式。
+
+创建后平台自动验证连通性;Kubernetes 资源默认落在 log 命名空间(可改)。
+第二步:准备存储
+推荐对象存储(MinIO / RustFS / S3 / OSS):多副本与数据保留更可靠,创建时可用「测试连接」验证凭证并自动建桶;跳过则使用本地磁盘。
+第三步:部署与采集
+
+- 选择目标、Loki 版本(支持 2.8+ / 3.x)、保留天数与资源规格,点击部署。
+- 部署成功后平台自动注册同名数据源,日志查询页立即可用;按提示添加采集策略(见日志采集)。
+
+三种部署模式
+
+
+
+| 模式 |
+适用 |
+说明 |
+
+
+
+
+| k8s-yaml |
+Kubernetes |
+StatefulSet + SSA 直发,平台全托管 |
+
+
+| host-binary |
+裸金属 |
+SSH 安装二进制 + systemd 托管 |
+
+
+| host-docker |
+裸金属 |
+Docker 容器运行,自动目录迁移 |
+
+
+
+
+
+
+
+
+
diff --git a/homepage/dist/index.html b/homepage/dist/index.html
new file mode 100644
index 0000000..b62057a
--- /dev/null
+++ b/homepage/dist/index.html
@@ -0,0 +1,132 @@
+
+
+
+
+
+LokiStack — Loki 日志管理平台
+
+
+
+
+
+
+
+
+
+
+
+
+
把 Loki 日志聚合
变成五分钟的事
+
向导式部署 Grafana Loki 到 Kubernetes 集群或裸金属主机,内置日志查询、可视化分析与飞书告警 —— 不写 YAML、不装 kubectl/Helm。
+
+
Go + React 单二进制交付 · JSON 文件存储零依赖 · 中文/英文界面
+
+
+
+
+
+
为运维而生的完整日志链路
+
从部署、采集、查询到告警,一个平台全部覆盖
+
+
+
+
向导式部署
+
三步完成:环境与目标 → 存储 → 部署 Loki 与采集。支持 Kubernetes(YAML 直发)、裸金属二进制与 Docker 三种模式。
+
+
+
+
策略化采集
+
Promtail / Fluent Bit 采集策略可视化配置:命名空间多选、app 标签四级回退、敏感路径拦截、配置预览与一键下发。
+
+
+
+
专业日志查询
+
LogQL 高亮补全、快捷查询选中即执行、Live Tail 实时追踪、时间线拖选、上下文查看,细到按用户的查询授权。
+
+
+
+
日志分析大盘
+
统计卡、趋势折线、命名空间分布、应用流图、每日日志量、Top 10 排行与 Ingress 访问分析,自动聚合无需配置。
+
+
+
+
开箱告警
+
内置九条应用日志告警规则,默认启用并绑定默认通道;填好飞书 Webhook 即可接收,冷却与风暴抑制防刷屏。
+
+
+
+
工程级可靠性
+
凭证加密存储、操作审计、标准 Prometheus 指标端点、CI 门禁与测试覆盖,按生产标准构建。
+
+
+
+
+
+
+
+
五分钟启动
+
单二进制或 Docker,一条命令拉起完整平台
+
+
+
1
+
+
准备密钥并启动
+
export JWT_SECRET=... ENCRYPTION_KEY=... 后执行 ./run.sh(开发)或 docker compose up -d(生产)。默认账号在首次启动时自动生成。
+
+
+
+
2
+
+
走完部署向导
+
接入 Kubernetes 集群或 SSH 主机,选择对象存储或本地磁盘,三步部署 Loki 并下发采集策略。
+
+
+
+
3
+
+
查询、分析、告警
+
日志查询页检索与实时追踪,日志分析页看聚合大盘,告警页填入飞书 Webhook 开始接收告警。
+
+
+
+
+
+
+
+
+
文档
+
用户手册覆盖部署、采集、查询、分析与告警全流程
+
+
+
+
+
+
+
+
diff --git a/homepage/dist/pricing.html b/homepage/dist/pricing.html
new file mode 100644
index 0000000..bb55dbf
--- /dev/null
+++ b/homepage/dist/pricing.html
@@ -0,0 +1,213 @@
+
+
+
+
+
+License & Pricing 许可和定价 · LokiStack
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 30 天全功能试用 · 离线可激活 · 无需注册
+ License & Pricing
许可和定价
+ 社区版永久免费;专业版 ¥99/年起,永久授权 ¥199 一次买断。所有版本功能完整,差别只在授权方式与设备数。
+
+
+
+
+
+
社区版
个人 / 非商业使用
+
¥0/ 永久
+
+ - 日志采集与查询
- 告警规则与通知
- 基础仪表盘
- 单机部署
- 社区支持
+
+
免费开始
+
+
+
最受欢迎
+
专业版 · 包年
单设备授权 · 全功能
+
¥99/ 年
+
+ - 全部功能 + 高级分析
- 在线授权 LIC-
- 1 台设备
- 一年免费升级
- 邮件技术支持
+
+
立即购买
+
+
+
专业版 · 永久
一次买断 · 离线许可
+
¥199/ 永久
+
+ - 当前大版本永久可用
- 离线许可 LICOFF-
- 1 台设备
- 1 年免费升级
- 邮件技术支持
+
+
立即购买
+
+
+
企业私有化
按席位 · 5 席起
+
¥6,000起 / 年
+
+ - 集群 / 高可用部署
- 私有化与白牌交付
- SSO / 审计 / 数据留存
- 专属支持与培训
- 可签合同与发票
+
+
预约报价
+
+
+
+
+
+ 激活:粘贴授权码即可
+ 付款后我们通过邮件交付授权码。在线授权以 LIC- 开头,离线许可证文件以 LICOFF- 开头。
+
+
邮件收码付款后 1 个工作日内,授权码发送到你预留的邮箱
+
打开设置程序内「设置 → 账户 / 授权」
+
粘贴激活填入 LIC-… 点击激活;离线环境导入 LICOFF- 文件
+
完成状态显示「已激活 / 剩余 N 天」,可在同一页解绑换机
+
+
+
+
+ 常见问题
+ 授权如何交付?包含哪些内容?
邮件交付授权码 + 发票。授权与设备绑定,包含对应版本的全部功能与一年升级。
+ 换电脑怎么办?
在程序「设置 → 授权」里先解绑,再在新设备激活;解绑次数不限,同一时间仅一台设备在线。
+ 可以离线使用吗?
可以。选择永久/离线许可,我们会提供 LICOFF- 许可证文件,导入后无需联网校验。
+ 团队 / 企业怎么买?
5 席起按席位计价,支持私有化与白牌交付、SSO 与审计。邮件说明规模与环境,我们给方案与报价。
+ 怎么付款?支持哪些方式?
对公转账 / 支付宝,支持开票。本站不介入在线支付,付款与发票均走人工邮件确认。
+
+
+
+ 先用起来,再决定
下载即含 30 天全功能试用,到期前随时激活。
+ 打开用户手册
+
+
+
+
+
+
+
+
diff --git a/homepage/index.html b/homepage/index.html
index 00970ce..b62057a 100644
--- a/homepage/index.html
+++ b/homepage/index.html
@@ -7,6 +7,8 @@
+
+
@@ -18,9 +20,8 @@
@@ -30,8 +31,8 @@
把 Loki 日志聚合
变成五分钟的事
向导式部署 Grafana Loki 到 Kubernetes 集群或裸金属主机,内置日志查询、可视化分析与飞书告警 —— 不写 YAML、不装 kubectl/Helm。
Go + React 单二进制交付 · JSON 文件存储零依赖 · 中文/英文界面
@@ -112,7 +113,7 @@
用户手册覆盖部署、采集、查询、分析与告警全流程
@@ -120,7 +121,7 @@