Files
squid-manager/README.md
T
Hermes Agent a875d790b0 docs: 新增部署后必做章节 - Squid 服务端 ACL 放行
踩坑记录: Squid 默认配置里 localnet ACL 定义了 10/8, 172.16/12,
192.168/16 等内网段,但 'http_access allow localnet' 默认被注释掉,
导致内网客户端所有代理请求返回 403 TCP_DENIED。

新增 '⚠️ 部署后必做' 章节,提供:
- 症状描述
- 两种修复方式 (Web UI / 命令行)
- 验证方法
- 安全警告 (不要 allow all,会被全球黑名单)
2026-07-15 13:26:12 +08:00

11 KiB

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 (可选)

快速开始

安装依赖

cd /root/squid-manager
pip install -r requirements.txt --break-system-packages

直接运行 (开发)

python3 app.py
# 默认监听 0.0.0.0:5200,调试模式

生产部署 (gunicorn + systemd)

# 初始化数据库
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:

[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
systemctl daemon-reload
systemctl enable --now squid-manager

默认账号

  • 用户名: admin
  • 密码: admin

首次登录后请立即修改密码 (左侧导航 → 修改密码)。

⚠️ 部署后必做:Squid 服务端 ACL 放行

Squid 安装后默认配置里 localnet ACL 虽然定义了 10.0.0.0/8172.16.0.0/12192.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

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                        # 让新配置生效

验证生效

# 从另一台内网机器(比如你的 Windows 10.168.1.201)
curl -x http://<squid-server>: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):

# 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 证书:

# 一次性安装 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.pySECRET_KEY 必须固定 (环境变量),否则每次重启会话失效