# Squid Web Manager 一个基于 Flask 的 Squid 代理服务器 Web 管理平台。 ## 功能 ### 1. 全 Web 化配置管理 - **主配置**: HTTP/HTTPS/ICP/SNMP 端口、缓存内存、对象大小、超时、DNS、日志路径、管理员邮箱等 - **ACL 规则表**: 完整 ACL CRUD,支持 28+ 类型 (src, dst, dstdomain, port, method, time, url_regex, proxy_auth, ...) - **访问控制**: http_access / https_access / icp_access / snmp_access 等所有访问指令的可视化管理 - **缓存目录**: cache_dir 多目录管理 (ufs / aufs / diskd / rock) - **刷新规则**: refresh_pattern 正则/百分比/最大时间 - **认证配置**: basic / digest / ntlm / negotiate 全套 auth_param 管理 - **缓存对等**: cache_peer 父代理/兄弟节点配置 - **原始编辑**: 直接编辑 squid.conf,支持语法校验 每次保存自动备份当前配置,可选启用 `squid -k parse` 语法校验。 ### 2. 日志分析 解析 Squid 原生 access.log,提供: - **KPI 卡片**: 总请求数、缓存命中率、总流量、平均响应、拒绝率、中断率、4xx/5xx 错误率 - **每小时流量图**: 请求数 + 流量双 Y 轴折线图 - **结果码分布**: TCP_HIT / TCP_MISS / TCP_TUNNEL / TCP_DENIED 等 (含中文释义) - **HTTP 状态码分布**: 2xx/3xx/4xx/5xx 分类 - **方法分布**: GET / POST / CONNECT / ... - **请求分类**: Hit / Miss / Tunnel / Denied / Aborted / Error - **Top 客户端**: 按 IP 排序,显示请求数和流量 - **Top 目标主机**: 按域名排序 - **Top URL**: 访问最多的资源 - **层级代码**: HIER_DIRECT / HIER_PARENT_HIT / ... - **Content-Type 分布** - **日志查询**: 多维度过滤 (IP / 方法 / 结果码 / 主机 / URL / 大小范围 / 时间范围) - **实时日志**: 自动刷新的 Live Tail 视图 - **日志导入**: 离线分析一次性粘贴的日志 ### 3. 服务控制 - 启动 / 停止 / 重启 / 平滑重载 (reload,失败回退 restart) - 服务状态查看 (PID, 版本, 启动时间, unit 文件) - 关键路径一览 ### 4. 运维功能 - **配置备份**: 自动备份历史,可下载/恢复 - **审计日志**: 所有配置变更、服务操作、登录登出全程留痕 - **修改密码**: admin/admin 默认账号,强制可改 ## 技术栈 | 组件 | 选型 | |------|------| | 后端 | Python 3 + Flask + SQLAlchemy | | 数据库 | SQLite (instance/squid_mgr.db) | | 前端 | 原生 HTML + CSS + 原生 JS | | 图表 | Chart.js 4.4 (CDN) | | WSGI | gunicorn | | 进程管理 | systemd (可选) | ## 快速开始 ### 安装依赖 ```bash cd /root/squid-manager pip install -r requirements.txt --break-system-packages ``` ### 直接运行 (开发) ```bash python3 app.py # 默认监听 0.0.0.0:5200,调试模式 ``` ### 生产部署 (gunicorn + systemd) ```bash # 初始化数据库 python3 -c "from app import app, db, seed_admin; \ app.app_context().push(); \ db.create_all(); seed_admin()" # 启动 gunicorn gunicorn --workers 2 --bind 0.0.0.0:5200 wsgi:app ``` ### systemd 单元 (推荐) `/etc/systemd/system/squid-manager.service`: ```ini [Unit] Description=Squid Web Manager After=network.target [Service] Type=exec User=root WorkingDirectory=/root/squid-manager ExecStart=/usr/bin/gunicorn --workers 2 --bind 0.0.0.0:5200 wsgi:app Restart=on-failure RestartSec=5 [Install] WantedBy=multi-user.target ``` ```bash systemctl daemon-reload systemctl enable --now squid-manager ``` ## 默认账号 - 用户名: `admin` - 密码: `admin` **首次登录后请立即修改密码** (左侧导航 → 修改密码)。 ## ⚠️ 部署后必做:Squid 服务端 ACL 放行 Squid 安装后默认配置里 `localnet` ACL 虽然定义了 `10.0.0.0/8`、`172.16.0.0/12`、`192.168.0.0/16` 等内网段,但 **对应的 `http_access allow localnet` 这一行默认被注释掉**。如果你的 Squid 同时跑在公网或混合网段,内网客户端的所有代理请求会全部返回 `403 TCP_DENIED`。 **症状**: 客户端配置了代理,浏览器打不开任何网站;`/var/log/squid/access.log` 里看到 `TCP_DENIED/403` 而不是 `TCP_MISS/200`。 **修复** (任选一种): ### 方式一: 通过 Squid Manager Web UI(推荐,有 diff 预览和审计) 1. 登录平台 → **原始编辑** → 在 `http_access allow localhost` 下面、 `http_access deny all` 上面插入一行: ``` http_access allow localnet ``` 2. 点保存 → 看 diff 预览 → 确认 → 自动备份 + 写盘 3. 回到 **服务控制** 页 → 点 **平滑重载 (reload)** ### 方式二: 直接编辑 /etc/squid/squid.conf ```bash cp /etc/squid/squid.conf /etc/squid/squid.conf.bak # 在 http_access allow localhost 之后插入一行: sed -i '/^http_access allow localhost$/a http_access allow localnet' /etc/squid/squid.conf squid -k parse -f /etc/squid/squid.conf # 语法校验 squid -k reconfigure # 让新配置生效 ``` ### 验证生效 ```bash # 从另一台内网机器(比如你的 Windows 10.168.1.201) curl -x http://:3128 -I http://example.com # 应该返回 HTTP/1.1 200 OK # 之前会是 403 Forbidden 或连接重置 ``` > ⚠️ **不要把 `http_access allow all` 加上去** — 那会变成开放代理,服务器 IP 会在 24 小时内被全球黑名单(Spamhaus / Tor exit list / 各种威胁情报)列入。 ## 配置路径 默认假设 Squid 安装在本机: - 配置文件: `/etc/squid/squid.conf` - 访问日志: `/var/log/squid/access.log` - 缓存日志: `/var/log/squid/cache.log` - 二进制: `squid` - 服务名: `squid` 如需管理远程 Squid 或路径不同,在 **路径设置** 页面修改 (路径需在本平台可访问的位置)。 ## 项目结构 ``` squid-manager/ ├── app.py # Flask 应用 (模型、路由、业务逻辑) ├── squid_config.py # squid.conf 解析 / 生成 / 校验 ├── log_parser.py # access.log 解析与统计 ├── wsgi.py # gunicorn 入口 ├── requirements.txt ├── README.md ├── instance/ # SQLite 数据库 (自动创建) │ └── squid_mgr.db ├── backups/ # squid.conf 自动备份 ├── templates/ # Jinja2 模板 │ ├── base.html │ ├── login.html │ ├── dashboard.html │ ├── logs.html │ ├── logs_import.html │ ├── logs_live.html │ ├── service.html │ ├── config_main.html │ ├── config_acls.html │ ├── config_rules.html │ ├── config_cache.html │ ├── config_refresh.html │ ├── config_auth.html │ ├── config_peers.html │ ├── config_raw.html │ ├── config_paths.html │ ├── audit.html │ ├── backups.html │ ├── change_password.html │ └── error.html └── static/ └── style.css ``` ## 日志格式支持 标准 Squid access.log 格式 (默认): ``` time elapsed client action/code size method URL ident hierarchy content-type ``` 示例: ``` 1783841223.438 2488 172.16.12.232 TCP_MISS_ABORTED/000 0 GET http://169.254.169.254/metadata/instance/compute - HIER_DIRECT/169.254.169.254 - 1783841225.683 4564 172.16.237.9 TCP_TUNNEL/200 10197 CONNECT default.exp-tas.com:443 - HIER_DIRECT/13.107.5.93 - ``` 支持的结果码: - TCP_HIT, TCP_MEM_HIT, TCP_NEGATIVE_HIT, TCP_IMS_HIT, TCP_REFRESH_HIT (命中) - TCP_MISS, TCP_REFRESH_MISS, TCP_CLIENT_REFRESH_MISS (未命中) - TCP_TUNNEL (CONNECT 隧道) - TCP_DENIED, TCP_DENIED_REPLY (拒绝) - TCP_MISS_ABORTED (中断) - TCP_REDIRECT (重定向) - UDP_* (ICP 协议) - NONE (错误) ## 安全建议 1. **修改默认密码** - admin/admin 仅为示例 2. **绑定内网 IP** - 不要暴露到公网,或前置 nginx + Basic Auth 3. **限制文件权限** - 配置文件含敏感信息,确保 600 4. **审计日志** - 定期查看 `/audit` 页面 5. **TLS** - 生产环境建议 nginx 反代 + HTTPS ## 已知限制 - 服务控制 (start/stop/reload) 仅在 Squid 与本平台同机时有效 - `squid -k parse` 校验需要本机有 squid 二进制 - 多 gunicorn worker 下 SQLite 写入有竞态,已用 try/except 兜底 - access.log 解析按需读取 (默认末尾 10000 行),不持久化 ## TLS / HTTPS 部署指南 本 Web 平台本身默认监听 HTTP。在公网或需要 HTTPS 的内网场景下,**强烈不要把本平台直接暴露** 请用 `nginx` 做反向代理 + TLS 终结。 Web UI 提供 **🔐 TLS 证书管理** 页面 (`/config/tls`): ### 1. 自签名证书 (仅用于测试 / 内网) > 进入 **配置管理 → TLS 证书**,填入 Common Name (如 `proxy.example.local`),点击"生成自签名证书"。 > 生成的文件保存在 `ssl_certs/` 目录下,名为 `CN_YYYYMMDD_xxxxxxxx.pem`, > 内含 cert + key,可直接用于 nginx 自测。 > > 浏览器会提示"不受信任",仅用于内网 / 自测 / `curl -k`。 ### 2. 生产部署: nginx 反代 + Let's Encrypt + 强制 HTTPS 最小化的 `nginx` 配置示例 (假设本平台监听 `127.0.0.1:5200`): ```nginx # HTTP -> HTTPS 强制重定向 server { listen 80; server_name proxy.example.com; return 301 https://$host$request_uri; } # HTTPS 终结 server { listen 443 ssl http2; server_name proxy.example.com; # Let's Encrypt 签发的证书 ssl_certificate /etc/letsencrypt/live/proxy.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/proxy.example.com/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:10m; ssl_session_timeout 1d; # 转发到本平台 location / { proxy_pass http://127.0.0.1:5200; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_buffering off; } } ``` 申请 Let's Encrypt 证书: ```bash # 一次性安装 certbot (Debian/Ubuntu) apt install -y certbot # 仅申请证书,不需要 nginx 插件 (webroot 模式) certbot certonly --webroot -w /var/www/html \ -d proxy.example.com \ --email admin@example.com --agree-tos -n # 证书自动存放在 /etc/letsencrypt/live/proxy.example.com/ # 推荐加上 cron 自动续期 echo "0 3 * * * /usr/bin/certbot renew --quiet --post-hook 'systemctl reload nginx'" \ | sudo crontab - ``` 也可以从本平台 **上传** 页面手动上传 `.pem` / `.crt` / `.key` (上限 1 MB): | 字段 | 用法 | |------|------| | 主题 (CN) | 证书绑定的域名,需与 nginx `server_name` 一致 | | 状态 | 绿色=有效 ≥30 天 / 黄色=<30 天 / 红色=已过期 | | SHA-256 指纹 | 审计追踪用,只记录指纹,**绝不写私钥内容** | ### 3. 常见误区 - 不要把 `ssl_certs/*.pem` 加入 git 或公网备份,文件含**私钥** - 不要把 80 / 443 直接绑到 `app.py` 运行端口,务必过 nginx (WAF / 限速 / 防护) - Let's Encrypt 单证书有效期 90 天,务必配置自动续期 - 反代场景下,`app.py` 的 `SECRET_KEY` 必须固定 (环境变量),否则每次重启会话失效