igozhang

——

    yum-apt 代理服务器搭建

    前提:代理服务端统一使用 Ubuntu 20.04172.27.248.66 / igo66),Squid 与 apt-cacher-ng 同机部署;客户端分别为 CentOS 7(yum)与 Ubuntu 20/22(apt)。非 root 用户命令前加 sudo


    一、Ubuntu 20.04 — yum 代理(Squid)

    服务端 172.27.248.66(igo66)

    sudo apt update && sudo apt install -y squid && sudo systemctl enable --now squid
    
    sudo tee /etc/squid/squid.conf > /dev/null <<'EOF'
    http_port 3128
    https_port 3122 tls-cert=/home/igo/ssl/tls.pem tls-key=/home/igo/ssl/tls.key
    cache_dir ufs /var/spool/squid 1024 16 256
    cache_mem 512 MB
    maximum_object_size 4096 MB
    cache_replacement_policy heap LFUDA
    cache_access_log /var/log/squid/access.log
    cache_log /var/log/squid/cache.log
    
    acl localnet src 10.0.0.0/8
    acl localnet src 172.16.0.0/12
    acl localnet src 192.168.0.0/16
    
    http_access allow localnet
    http_access allow all
    http_access deny all
    
    forwarded_for off
    request_header_access Allow allow all
    
    # 66 出网受限时取消下面两行注释,经 10.80.238.40:3128 二级转发出站
    # cache_peer 10.80.238.40 parent 3128 0 no-query default connect-fail-limit=0
    # never_direct allow all
    EOF
    

    TLS 证书权限(Squid 以 proxy 用户运行,私钥不可全局可读):

    sudo chmod 711 /home/igo
    sudo chown root:proxy /home/igo/ssl
    sudo chmod 750 /home/igo/ssl
    sudo chown root:proxy /home/igo/ssl/tls.pem /home/igo/ssl/tls.key
    sudo chmod 644 /home/igo/ssl/tls.pem
    sudo chmod 640 /home/igo/ssl/tls.key
    sudo -u proxy test -r /home/igo/ssl/tls.pem && sudo -u proxy test -r /home/igo/ssl/tls.key \
      && echo "cert/key OK" || echo "cert/key FAIL"
    

    初始化缓存、校验配置、启动并检查状态:

    sudo squid -z && sudo squid -k parse && sudo systemctl enable squid \
      && sudo systemctl restart squid
    sudo systemctl --no-pager status squid
    sudo ufw allow 3128/tcp 2>/dev/null; sudo ufw allow 3122/tcp 2>/dev/null; \
      sudo ss -lntp | grep -E '3128|3122'
    

    https_port 3122 避开 22 端口(易被网络策略拦截或与 SSH 冲突)。

    Squid 就绪后,在客户端配置 HTTP/HTTPS 代理:

    P=172.27.248.66; export http_proxy=http://${P}:3128 https_proxy=http://${P}:3128 HTTP_PROXY=http://${P}:3128 HTTPS_PROXY=http://${P}:3128 no_proxy=localhost,127.0.0.0/8,::1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16; history -d $(history 1 | awk '{print $1}') 2>/dev/null
    

    验证 shell 代理是否生效(自动读取上述环境变量,无需 -x):

    bash <<'EOF'
    echo "proxy: ${http_proxy:-${HTTP_PROXY:-unset}}"
    for u in \
      http://www.google.com/ \
      https://www.google.com/ \
      http://docker.io/ \
      https://docker.io/; do
      curl -sS -o /dev/null -w "${u} HTTP=%{http_code} time=%{time_total}s\n" \
        --connect-timeout 5 --max-time 20 -I "$u" || echo "${u} FAIL"
    done
    EOF
    

    docker pull 走 dockerd 进程,不读 shell 代理;需单独配置:

    P=172.27.248.66
    sudo mkdir -p /etc/systemd/system/docker.service.d
    sudo tee /etc/systemd/system/docker.service.d/http-proxy.conf > /dev/null <<EOF
    [Service]
    Environment="HTTP_PROXY=http://${P}:3128"
    Environment="HTTPS_PROXY=http://${P}:3128"
    Environment="NO_PROXY=localhost,127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16"
    EOF
    sudo systemctl daemon-reload && sudo systemctl restart docker
    sudo systemctl show docker --property=Environment
    history -w; sed -i '/proxy=\|http_proxy\|HTTP_PROXY\|HTTPS_PROXY\|NO_PROXY/d' "${HISTFILE:-$HOME/.bash_history}" 2>/dev/null; history -c; history -r
    

    取消 shell 代理:

    unset http_proxy https_proxy HTTP_PROXY HTTPS_PROXY no_proxy
    

    取消 Docker 代理:

    sudo rm -f /etc/systemd/system/docker.service.d/http-proxy.conf
    sudo systemctl daemon-reload && sudo systemctl restart docker
    

    CentOS 7 客户端

    CentOS 7 已 EOL,官方 mirrorlist.centos.org 常返回 503,需改用阿里云源;yum 流量经 Squid 代理出网。

    1. 经代理测试阿里云源是否可达(可选)

    在客户端执行,HTTP=200 表示可用:

    timeout 20 bash -c 'PROXY=http://172.27.248.66:3128; echo "=== Aliyun Centos-7.repo ==="; timeout 8 curl -x "${PROXY}" -sS -o /dev/null -w "HTTP=%{http_code} time=%{time_total}s\n" --connect-timeout 5 --max-time 8 -I http://mirrors.aliyun.com/repo/Centos-7.repo || echo "FAIL"; echo "=== Aliyun base repomd.xml ==="; timeout 8 curl -x "${PROXY}" -sS -o /dev/null -w "HTTP=%{http_code} time=%{time_total}s\n" --connect-timeout 5 --max-time 8 -I http://mirrors.aliyun.com/centos-vault/7.9.2009/os/x86_64/repodata/repomd.xml || echo "FAIL"'
    

    2. 配置代理 + 阿里云源

    旧文件 centos.repo(小写)不会被 CentOS-*.repo 匹配,仍指向 yum.sunwoda-evb.com 并与阿里云源重复;需按文件名 cent* 忽略大小写 全部移走后再下载新 repo。

    PROXY=http://172.27.248.66:3128
    grep -q '^proxy=' /etc/yum.conf || sudo sed -i "/^\[main\]/a proxy=$PROXY" /etc/yum.conf
    sudo mkdir -p /etc/yum.repos.d/backup
    for file in /etc/yum.repos.d/[Cc]ent*; do
      [ -e "$file" ] || continue
      sudo mv "$file" /etc/yum.repos.d/backup/
    done
    sudo curl -x "$PROXY" -fsSL -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
    sudo curl -x "$PROXY" -fsSL -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
    sudo yum clean all && sudo yum makecache && sudo yum repolist
    history -w; sed -i '/proxy=\|http_proxy\|HTTP_PROXY\|HTTPS_PROXY\|NO_PROXY/d' "${HISTFILE:-$HOME/.bash_history}" 2>/dev/null; history -c; history -r
    

    centos.repo 若含 nginx/zabbix 等内网源,移走后需单独保留或重建对应 .repo;base/epel 仅使用上述阿里云文件即可。

    取消代理:

    sudo sed -i '/^proxy=/d' /etc/yum.conf && sudo yum clean all
    

    二、Ubuntu 20.04 — apt 代理(apt-cacher-ng)

    服务端 172.27.248.66(igo66,与 Squid 同机)

    sudo apt update && sudo apt install -y apt-cacher-ng && sudo systemctl enable --now apt-cacher-ng
    
    sudo tee /etc/apt-cacher-ng/acng.conf > /dev/null <<'EOF'
    Port:3142
    BindAddress:0.0.0.0
    CacheDir:/var/cache/apt-cacher-ng
    LogDir:/var/log/apt-cacher-ng
    ExTreshold:4
    EOF
    
    sudo systemctl restart apt-cacher-ng && sudo ufw allow 3142/tcp 2>/dev/null; \
      sudo ss -lntp | grep 3142
    

    apt-cacher-ng 按请求 URL 自动区分发行版,同一代理可同时服务 Ubuntu 20.04 / 22.04 客户端。

    Ubuntu 20.04 / 22.04 客户端

    配置 apt 代理前,确认 apt-cacher-ng 可用:

    P=172.27.248.66; PROXY=http://${P}:3142
    bash <<EOF
    echo "proxy: $PROXY"
    for u in \
      http://archive.ubuntu.com/ \
      https://archive.ubuntu.com/ \
      http://security.ubuntu.com/ \
      https://security.ubuntu.com/; do
      curl -x "$PROXY" -sS -o /dev/null -w "\${u} HTTP=%{http_code} time=%{time_total}s\n" \
        --connect-timeout 5 --max-time 20 -I "\$u" || echo "\${u} FAIL"
    done
    EOF
    
    PROXY=http://172.27.248.66:3142
    sudo tee /etc/apt/apt.conf.d/01proxy > /dev/null <<EOF
    Acquire::http::Proxy "$PROXY";
    Acquire::https::Proxy "$PROXY";
    EOF
    sudo apt update && sudo apt -s upgrade | head -5
    history -w; sed -i '/proxy=\|http_proxy\|HTTP_PROXY\|HTTPS_PROXY\|Acquire::http/d' "${HISTFILE:-$HOME/.bash_history}" 2>/dev/null; history -c; history -r
    

    取消代理:

    sudo rm -f /etc/apt/apt.conf.d/01proxy && sudo apt update
    

    三、验证与排错

    客户端执行以下聚合命令(脚本内英文输出;兼容 CentOS 7 / Rocky 9 / Ubuntu 20/22)。

    端口 TCP 连通性

    仅检测代理端口能否建立 TCP,不验证证书或代理协议。

    bash <<'EOF'
    P=172.27.248.66
    echo "=== Proxy port TCP check (target: $P) ==="
    for p in 3128 3122 3142; do
      timeout 3 bash -c "echo >/dev/tcp/$P/$p" 2>/dev/null \
        && echo "[OK]   $P:$p" || echo "[FAIL] $P:$p"
    done
    EOF
    

    经代理访问 Google

    3128 为 HTTP 代理,可直接用 IP;3122 为 HTTPS 代理,证书按域名签发,需临时写入 hosts。

    bash <<'EOF'
    P=172.27.248.66; H=igoproxy.sunwoda-evb.com
    grep -qw "$H" /etc/hosts || echo "$P  $H" | sudo tee -a /etc/hosts > /dev/null
    echo "=== Google via HTTP proxy  $P:3128 ==="
    curl -x http://$P:3128 -sS -o /dev/null \
      -w "HTTP=%{http_code} time=%{time_total}s\n" \
      --connect-timeout 5 --max-time 20 -I https://www.google.com/ \
      || echo "FAIL"
    echo "=== Google via HTTPS proxy $H:3122 (hosts required for TLS cert) ==="
    curl --proxy-insecure -x https://$H:3122 -sS -o /dev/null \
      -w "HTTP=%{http_code} time=%{time_total}s\n" \
      --connect-timeout 5 --max-time 20 -I https://www.google.com/ \
      || curl -k -x https://$H:3122 -sS -o /dev/null \
      -w "HTTP=%{http_code} time=%{time_total}s\n" \
      --connect-timeout 5 --max-time 20 -I https://www.google.com/ \
      || echo "FAIL"
    EOF
    

    测完可清理 hosts:sudo sed -i '/igoproxy\.sunwoda-evb\.com/d' /etc/hosts

    单项检查

    检查项 命令
    yum 代理连通 curl -x http://172.27.248.66:3128 -I http://mirrors.aliyun.com/centos-vault/7.9.2009/os/x86_64/repodata/repomd.xml
    apt 代理连通 curl -I http://172.27.248.66:3142/acng-report.html
    Squid 日志 sudo tail -f /var/log/squid/access.log
    apt-cacher 日志 sudo tail -f /var/log/apt-cacher-ng/apt-cacher.log

    常见问题

    • 客户端无法访问:服务端 ufw 放行 3128 / 3122 / 3142,确认 Squid ACL 网段包含客户端 IP。
    • yum mirrorlist.centos.org 503:CentOS 7 已 EOL,改用阿里云源(见第一节客户端步骤),勿再用官方 mirrorlist。
    • yum 报 SSL 错误:CentOS 7 阿里云源多为 HTTP,保持 proxy= 即可;HTTPS 源需 Squid 额外配置 SSL bump(一般内网镜像无需)。
    • apt 慢或 403:确认客户端 /etc/apt/sources.list 使用官方或内网可达镜像源,代理只做缓存转发。

    四、架构示意

    CentOS 7 客户端 ──proxy:3128──► Ubuntu 20.04 172.27.248.66 (Squid) ──► mirrors.aliyun.com
    Ubuntu 20/22 客户端 ──proxy:3142──► Ubuntu 20.04 172.27.248.66 (apt-cacher-ng) ──► 上游 apt 镜像
    

    报错

    1. yum.sunwoda-evb.com / repo 重复:检查是否仍有 /etc/yum.repos.d/centos.repo(小写)未移走,与 CentOS-Base.repo 重复定义 base/epel;按客户端步骤用 [Cc]ent* 全部备份后再 makecache

    2. mirrorlist.centos.org 503:CentOS 7 已 EOL,改用阿里云源,勿再用官方 mirrorlist。

    3. EPEL 404/503(内网源):改用 mirrors.aliyun.com/repo/epel-7.repo;临时装包可 sudo yum --disablerepo=epel -y install <pkg>

    sudo yum --disablerepo=epel -y install mlocate htop
    sudo yum-config-manager --save --setopt=epel.skip_if_unavailable=true
    

    五、出站 TCP 探测(15 站点)

    待测客户端或服务端执行,探测常用 yum/apt/k8s/docker/GitHub/Helm 等站点 80/443 TCP 是否可达(非 HTTP 内容检测)。每端口超时 3s,并行执行,整段上限 12s;无需 root。

    判读: OK 已连通 | refused 主动拒绝 | reset 连接被 RST | unreach 无路由 | timeout 超过 3s 无响应(多为防火墙 DROP)

    timeout 12 bash <<'EOF'
    cfn(){ e="$1"; c="$2"
      [ "$c" -eq 0 ] && echo OK && return
      [ "$c" -eq 124 ] && echo timeout && return
      e=$(printf '%s' "$e" | tr '\n' ' ' | sed 's/  */ /g;s/^bash: //g')
      echo "$e" | grep -qi refused  && echo refused  && return
      echo "$e" | grep -qi reset    && echo reset    && return
      echo "$e" | grep -qi unreachable && echo unreach && return
      echo "$e" | grep -qi 'no route' && echo unreach && return
      echo "$e" | grep -qi timeout  && echo timeout  && return
      printf 'err(%.28s)' "$e"
    }
    p(){ l="$1"; h="$2"; o=""
      for pt in 80 443; do
        e=$(timeout 3 bash -c "echo >/dev/tcp/${h}/${pt}" 2>&1); c=$?
        o="${o} ${pt}:$(cfn "$e" "$c")"
      done
      printf "%-14s %-28s%s\n" "$l" "$h" "$o"
    }
    echo "=== Egress TCP probe (80+443/host, 3s/port, parallel) ==="
    echo "Legend: OK=connected | refused=reject | reset=RST | unreach=no route | timeout=>3s no reply"
    echo ""
    while IFS='|' read -r l h; do p "$l" "$h" & done <<'T'
    Aliyun|mirrors.aliyun.com
    Tsinghua|mirrors.tuna.tsinghua.edu.cn
    Tencent-yum|mirrors.cloud.tencent.com
    Ubuntu-apt|archive.ubuntu.com
    Ubuntu-sec|security.ubuntu.com
    GitHub|github.com
    Google|www.google.com
    DockerHub|registry-1.docker.io
    Docker-pkg|download.docker.com
    K8s|pkgs.k8s.io
    Helm|get.helm.sh
    Quay|quay.io
    Debian|deb.debian.org
    GCS|storage.googleapis.com
    MS-pkg|packages.microsoft.com
    T
    wait
    echo ""
    echo "=== Done ==="
    EOF
    

    MP3