Files
squid-manager/templates/config_main.html
T
Hermes Agent 4a1d949e41 feat: 完整 Squid Web Manager 平台 - P0-P3 全功能
完整 Web 管理平台,涵盖:

P0 生产加固:
- 会话超时(空闲+绝对) + CSRF 防护 + 登录失败限流
- HTTPS/TLS 证书管理(自签生成/上传/删除/过期提醒)
- SSL Bump (HTTPS 透明代理) 可视化配置
- 配置文件 diff 预览 + 二次确认才写入
- 服务控制二次确认 + 操作期间按钮锁定

P1 运维能力:
- 日志轮转管理(logrotate) + 日志状态监控
- 告警规则(5xx/命中率/磁盘/客户端流量)
- 多 Squid 实例管理 + 一键切换
- squidclient mgr 实时性能指标
- 流量异常检测(突增/大文件/高频小包/新客户端)

P2 日志分析增强:
- 日志持久化到 SQLite + 历史时间范围查询
- 导出 CSV/JSON(日志/KPI/异常/审计)
- GeoIP 地图(Leaflet + ip-api.com 离线可选 GeoLite2)
- 每客户端 24h 趋势图
- 自定义 Squid logformat 解析器

P3 体验锦上添花:
- 暗/亮主题切换(cookie 持久化)
- WebSSH 终端(xterm.js + paramiko)
- 完整审计日志 + 用户管理

技术栈: Flask 3.0 + SQLAlchemy 2.0 + SQLite + Chart.js + Leaflet
总代码量: ~16500 行 (15 Python 模块 + 34 模板 + CSS)
路由数: 73
2026-07-15 10:19:21 +08:00

216 lines
12 KiB
HTML

{% extends "base.html" %}
{% block title %}主配置 - Squid Manager{% endblock %}
{% block content %}
<div class="page-header">
<h1>⚙️ 主配置</h1>
<div class="page-actions">
<span class="meta-text">配置文件: <code>{{ squid_conf_path }}</code></span>
</div>
</div>
<div class="card">
<form method="post">
<input type="hidden" name="_csrf" value="{{ csrf_token() }}">
<div class="config-section">
<h3 class="config-section-title">🌐 网络 (Network)</h3>
<div class="filter-grid">
<div class="form-group">
<label>http_port <span class="hint">HTTP 代理监听端口</span></label>
<input type="text" name="http_port" value="{{ simple.http_port }}" class="form-input" placeholder="3128">
</div>
<div class="form-group">
<label>https_port <span class="hint">HTTPS 监听 (用于 SSL Bump)</span></label>
<input type="text" name="https_port" value="{{ simple.https_port }}" class="form-input" placeholder="留空则不启用">
</div>
<div class="form-group">
<label>icp_port <span class="hint">ICP 协议端口 (邻居间)</span></label>
<input type="text" name="icp_port" value="{{ simple.icp_port }}" class="form-input" placeholder="3130">
</div>
<div class="form-group">
<label>snmp_port <span class="hint">SNMP 监控端口</span></label>
<input type="text" name="snmp_port" value="{{ simple.snmp_port }}" class="form-input" placeholder="留空则不启用">
</div>
<div class="form-group">
<label>visible_hostname <span class="hint">对外显示的主机名</span></label>
<input type="text" name="visible_hostname" value="{{ simple.visible_hostname }}" class="form-input" placeholder="proxy.example.com">
</div>
<div class="form-group">
<label>unique_hostname <span class="hint">多实例区分 (可选)</span></label>
<input type="text" name="unique_hostname" value="{{ simple.unique_hostname }}" class="form-input">
</div>
</div>
</div>
<div class="config-section">
<h3 class="config-section-title">💾 缓存 (Cache)</h3>
<div class="filter-grid">
<div class="form-group">
<label>cache_mem <span class="hint">内存缓存大小</span></label>
<input type="text" name="cache_mem" value="{{ simple.cache_mem }}" class="form-input" placeholder="256 MB">
</div>
<div class="form-group">
<label>maximum_object_size <span class="hint">最大对象大小</span></label>
<input type="text" name="maximum_object_size" value="{{ simple.maximum_object_size }}" class="form-input" placeholder="4096 KB">
</div>
<div class="form-group">
<label>minimum_object_size</label>
<input type="text" name="minimum_object_size" value="{{ simple.minimum_object_size }}" class="form-input" placeholder="0 KB">
</div>
<div class="form-group">
<label>maximum_object_size_in_memory</label>
<input type="text" name="maximum_object_size_in_memory" value="{{ simple.maximum_object_size_in_memory }}" class="form-input" placeholder="512 KB">
</div>
<div class="form-group">
<label>cache_replacement_policy</label>
<select name="cache_replacement_policy" class="form-input">
{% for p in ['lru','heap GDSF','heap LFUDA','heap LRU'] %}
<option value="{{ p }}" {% if simple.cache_replacement_policy == p %}selected{% endif %}>{{ p }}</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<label>memory_replacement_policy</label>
<select name="memory_replacement_policy" class="form-input">
{% for p in ['lru','heap GDSF','heap LFUDA','heap LRU'] %}
<option value="{{ p }}" {% if simple.memory_replacement_policy == p %}selected{% endif %}>{{ p }}</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<label>cache_swap_low <span class="hint">%</span></label>
<input type="number" name="cache_swap_low" value="{{ simple.cache_swap_low }}" class="form-input" placeholder="90">
</div>
<div class="form-group">
<label>cache_swap_high <span class="hint">%</span></label>
<input type="number" name="cache_swap_high" value="{{ simple.cache_swap_high }}" class="form-input" placeholder="95">
</div>
</div>
<p class="meta-text">磁盘缓存目录 (cache_dir) 在 <a href="{{ url_for('config_cache') }}">缓存目录</a> 页面配置</p>
</div>
<div class="config-section">
<h3 class="config-section-title">📝 日志 (Logging)</h3>
<div class="filter-grid">
<div class="form-group">
<label>access_log <span class="hint">访问日志路径</span></label>
<input type="text" name="access_log" value="{{ simple.access_log }}" class="form-input" placeholder="/var/log/squid/access.log">
</div>
<div class="form-group">
<label>cache_log <span class="hint">缓存日志</span></label>
<input type="text" name="cache_log" value="{{ simple.cache_log }}" class="form-input" placeholder="/var/log/squid/cache.log">
</div>
<div class="form-group">
<label>cache_store_log</label>
<input type="text" name="cache_store_log" value="{{ simple.cache_store_log }}" class="form-input" placeholder="/var/log/squid/store.log 或留空">
</div>
<div class="form-group">
<label>pid_filename</label>
<input type="text" name="pid_filename" value="{{ simple.pid_filename }}" class="form-input" placeholder="/var/run/squid.pid">
</div>
<div class="form-group">
<label>logformat <span class="hint">自定义格式</span></label>
<input type="text" name="logformat" value="{{ simple.logformat }}" class="form-input" placeholder="留空使用默认">
</div>
<div class="form-group">
<label>debug_options <span class="hint">ALL,1 / section,level</span></label>
<input type="text" name="debug_options" value="{{ simple.debug_options }}" class="form-input" placeholder="ALL,1">
</div>
<div class="form-group">
<label>log_ip_on_direct</label>
<select name="log_ip_on_direct" class="form-input">
<option value="on" {% if simple.log_ip_on_direct == 'on' %}selected{% endif %}>on</option>
<option value="off" {% if simple.log_ip_on_direct == 'off' %}selected{% endif %}>off</option>
</select>
</div>
<div class="form-group">
<label>buffered_logs</label>
<select name="buffered_logs" class="form-input">
<option value="on" {% if simple.buffered_logs == 'on' %}selected{% endif %}>on</option>
<option value="off" {% if simple.buffered_logs == 'off' %}selected{% endif %}>off</option>
</select>
</div>
</div>
</div>
<div class="config-section">
<h3 class="config-section-title">🌍 DNS</h3>
<div class="filter-grid">
<div class="form-group">
<label>dns_nameservers <span class="hint">DNS 服务器 (空格分隔)</span></label>
<input type="text" name="dns_nameservers" value="{{ simple.dns_nameservers }}" class="form-input" placeholder="8.8.8.8 1.1.1.1">
</div>
<div class="form-group">
<label>dns_timeout</label>
<input type="text" name="dns_timeout" value="{{ simple.dns_timeout }}" class="form-input" placeholder="30 seconds">
</div>
<div class="form-group">
<label>hosts_file</label>
<input type="text" name="hosts_file" value="{{ simple.hosts_file }}" class="form-input" placeholder="/etc/hosts">
</div>
<div class="form-group">
<label>dns_defnames</label>
<select name="dns_defnames" class="form-input">
<option value="off" {% if simple.dns_defnames == 'off' %}selected{% endif %}>off</option>
<option value="on" {% if simple.dns_defnames == 'on' %}selected{% endif %}>on</option>
</select>
</div>
</div>
</div>
<div class="config-section">
<h3 class="config-section-title">⏱️ 超时 (Timeouts)</h3>
<div class="filter-grid">
<div class="form-group">
<label>connect_timeout</label>
<input type="text" name="connect_timeout" value="{{ simple.connect_timeout }}" class="form-input" placeholder="60 seconds">
</div>
<div class="form-group">
<label>read_timeout</label>
<input type="text" name="read_timeout" value="{{ simple.read_timeout }}" class="form-input" placeholder="15 minutes">
</div>
<div class="form-group">
<label>client_lifetime</label>
<input type="text" name="client_lifetime" value="{{ simple.client_lifetime }}" class="form-input" placeholder="1 day">
</div>
<div class="form-group">
<label>shutdown_lifetime</label>
<input type="text" name="shutdown_lifetime" value="{{ simple.shutdown_lifetime }}" class="form-input" placeholder="30 seconds">
</div>
</div>
</div>
<div class="config-section">
<h3 class="config-section-title">🛠️ 管理 (Admin)</h3>
<div class="filter-grid">
<div class="form-group">
<label>cache_mgr <span class="hint">管理员邮箱</span></label>
<input type="text" name="cache_mgr" value="{{ simple.cache_mgr }}" class="form-input" placeholder="root">
</div>
<div class="form-group">
<label>err_html_language</label>
<input type="text" name="err_html_language" value="{{ simple.err_html_language }}" class="form-input" placeholder="en">
</div>
<div class="form-group">
<label>ftp_user</label>
<input type="text" name="ftp_user" value="{{ simple.ftp_user }}" class="form-input" placeholder="Squid@">
</div>
</div>
</div>
<div class="config-section">
<h3 class="config-section-title">📝 原始附加指令</h3>
<p class="meta-text">此处填写本页未涵盖的额外指令 (每行一条,会原样写入 squid.conf 末尾)。</p>
<div class="form-group">
<textarea name="raw_extra" rows="5" class="form-input monospace" placeholder="# 例如 forward_timeout 4 minutes
# maximum_single_addr_connections 16"></textarea>
</div>
</div>
<div class="form-actions">
<button type="submit" class="btn btn-primary">💾 保存并校验</button>
<a href="{{ url_for('config_raw') }}" class="btn btn-secondary">📝 原始编辑</a>
</div>
</form>
</div>
{% endblock %}