你刚装好 Ubuntu。你在终端里 set http_proxy,curl google.com 能工作,但 sudo apt update 却失败了。欢迎来到 Linux 代理配置的世界。

Ubuntu(以及 Linux 系统)没有一个所有应用都遵守的、统一的系统级代理设置。与 Windows 或 macOS 不同,你可以在系统偏好设置中 set 一个代理,然后大多数应用都会使用它;Ubuntu 则采用了一种碎片化的方式,没有中央代理开关。

每个工具要么 :

  1. 完全忽略环境变量,或者
  2. 仅在特定条件下使用它们,或者
  3. 需要自己独立的配置。

在 Ubuntu 上 set 代理,实际上意味着要独立配置多个工具。

在这份详细的指南中,我们将涵盖 apt、curl、wget、git、pip、npm、Docker、Snap 和 systemd,并提供可用的配置示例。

你将了解不同的代理类型,以及每个工具的确切配置位置,这样你就能最终一次性 set 好,让所有东西都正常工作。


测试环境: Ubuntu 26.04 LTS (Resolute Raccoon)
等级: 初级到高级


为什么在 Ubuntu Linux 上配置代理很棘手

-sp

有一件事会让大多数 Ubuntu 新用户感到惊讶:没有一个能处处生效的单一代理 set。

与 Windows 不同,Ubuntu 没有一个中央代理开关。相反,每个工具,如 apt、curl、wget、git、pip、npm、Docker、Snap、你的浏览器和你的终端,都独立管理自己的代理配置。所以,当你在 GNOME 设置中 set 了一个代理,你的终端会完全忽略它。当你 set 了一个环境变量,APT 会完全忽略它。除此之外,sudo 会在运行命令前剥离你的环境变量,而 systemd 服务则根本看不到它们。

这种脱节让很多人感到沮丧,因为他们在某个地方 set 了代理,然后不明白为什么在其他地方它仍然不工作。

在这篇全面的文章中,我们将准确解释在 Ubuntu 上为每个主要工具配置代理的位置,以及为什么每个工具的行为方式如此。

让我们从头开始。

理解代理类型

在开始配置之前,你需要知道你正在使用哪种代理。不同类型的代理行为不同,选择错误的类型可能导致连接失败。

数据中心代理

数据中心代理来自托管在数据中心的服务器。它们速度快且便宜,但网站通常可以检测并阻止它们,因为它们的 IP 地址看起来不像真正的家庭互联网连接。

因此,它们最适合高容量、低风险的任务(如抓取公共数据 set、监控你自己的基础设施或负载测试),在这些任务中,速度比不被发现更重要。

住宅代理

住宅代理使用由真实互联网服务提供商(ISP)分配给真实家庭设备的 IP 地址。因此,网站将来自住宅代理的流量视为来自普通用户的流量。

这使得它们对于网页抓取、地理测试以及数据中心 IP 被屏蔽的任务非常有用。

HTTP 与 HTTPS 代理

HTTP 代理处理标准的网络流量。HTTPS 代理在你设备和代理服务器之间的连接上增加了加密,这意味着你的凭据和请求元数据在本地网络中受到保护,不会被窥探。大多数现代代理 set 都使用 HTTPS,所以请始终检查你的提供商 port 什么协议。

关于 HTTP 和 HTTPS 代理在协议层面如何工作的更深入技术解释,包括 CONNECT 方法如何创建隧道以及 PAC 文件的作用,MDN Web 文档对此有详尽的介绍。

SOCKS5 代理

SOCKS5 代理在比 HTTP/HTTPS 代理更低的层次上工作。与只处理网络流量的 HTTP 代理不同,SOCKS5 路由所有网络流量,包括 UDP、FTP 和非 HTTP 协议,这使其成为更灵活、更注重隐私的选择。Ubuntu 上的许多工具原生 port SOCKS5,包括 curl、ssh 和大多数 BT 客户端。

现在你已经了解了这些类型,让我们进入实际的配置。

方法 1:环境变量

环境变量是 Ubuntu 最接近通用代理 set 的东西。许多命令行工具会自动检查这些变量,因此 set 它们始终是最好的起点。

关键变量

Ubuntu 识别这些标准的代理环境变量:

http_proxy      # Proxy for HTTP traffic
https_proxy     # Proxy for HTTPS traffic
ftp_proxy       # Proxy for FTP traffic
no_proxy        # Comma-separated list of hosts to bypass
ALL_PROXY       # Fallback proxy for tools that ignore the others

始终使用 小写 的变量名。大写版本(HTTP_PROXY、HTTPS_PROXY)在 CGI 环境中存在一个已知的安全漏洞,称为 httpoxy(VU#797896)。

攻击者可以发送一个精心构造的 HTTP Proxy: 请求头,CGI 网络服务器会将其提升为 HTTP_PROXY 环境变量,然后将你应用程序的出站流量重定向到攻击者的服务器。

小写变量不受此攻击影响,因为 CGI 规范(RFC 3875)只将 HTTP 请求头提升为大写环境变量。因此,虽然两种大小写在大多数情况下都有效,但小写是更安全的标准,也是你应该始终使用的。

还要注意 ALL_PROXY 变量。许多工具,包括 curl、git 和各种 Python 库,在找不到协议特定变量时会回退到 ALL_PROXY。包含它会使你的配置更健壮,而且几乎不需要额外的工作。

仅为当前会话设置变量

如果你想快速测试代理而不做永久更改,在你的终端中运行这些命令:

export http_proxy="http://proxyhost:port"
export https_proxy="http://proxyhost:port"
export ftp_proxy="http://proxyhost:port"
export ALL_PROXY="http://proxyhost:port"
export no_proxy="localhost,127.0.0.1,::1"

将 proxyhost 替换为你代理服务器的实际 IP 地址或主机名,将 port 替换为 port 号。这些 set 在你关闭终端窗口后就会消失,因此非常适合快速测试。

为你的用户账户永久设置变量

为了在每次打开终端时都保留代理 set,将以下行添加到你的 ~/.bashrc 文件中:

nano ~/.bashrc

滚动到底部并添加:

# Proxy settings
export http_proxy="http://proxyhost:port"
export https_proxy="http://proxyhost:port"
export ftp_proxy="http://proxyhost:port"
export ALL_PROXY="http://proxyhost:port"
export no_proxy="localhost,127.0.0.1,::1"

用 Ctrl+O 保存,按 Enter,然后用 Ctrl+X 退出。立即重新加载:

source ~/.bashrc

为所有用户进行系统级设置

如果你需要机器上的每个用户都使用同一个代理,你有两个不错的选择。

选项 1:/etc/environment

这是最简单的方法。它是一个静态的键值文件,PAM 在登录时读取它,并应用于每个用户和每个会话:

sudo nano /etc/environment

在底部添加这些行。注意,/etc/environment 不 使用 export 关键字,并且 不 支持变量扩展。你不能在其中引用 $HOME 或其他变量:

http_proxy="http://proxyhost:port"
https_proxy="http://proxyhost:port"
ftp_proxy="http://proxyhost:port"
ALL_PROXY="http://proxyhost:port"
no_proxy="localhost,127.0.0.1,::1"

保存并重启,以使更改应用于所有用户。

选项 2:/etc/profile.d/proxy.sh

当你需要动态逻辑时,这是更好的选择——例如,如果你的代理地址依赖于环境变量、主机名查找或某个条件。与 /etc/environment 不同,/etc/profile.d/ 中的 shell 脚本支持完整的 bash 语法:

sudo nano /etc/profile.d/proxy.sh

添加:

#!/bin/bash
# System-wide proxy settings
PROXY_HOST="proxyhost"
PROXY_PORT="port"
export http_proxy="http://${PROXY_HOST}:${PROXY_PORT}"
export https_proxy="http://${PROXY_HOST}:${PROXY_PORT}"
export ftp_proxy="http://${PROXY_HOST}:${PROXY_PORT}"
export ALL_PROXY="http://${PROXY_HOST}:${PROXY_PORT}"
export no_proxy="localhost,127.0.0.1,::1"

使其可执行:

sudo chmod +x /etc/profile.d/proxy.sh

这个脚本为系统上的每个交互式登录 shell 运行。这是管理多用户服务器的管理员的首选方法。

重要提示: 即使环境变量对许多 CLI 工具有效,apt、sudo、systemd 服务和 Snap 包都会忽略它们。每个都需要自己的专用配置,下面的章节会详细介绍。

方法 2:APT 代理配置

APT 有自己的代理系统。它根本不读取你的环境变量。因此,即使你正确 set 了 http_proxy,APT 仍然会绕过代理,除非你直接配置它。

配置 APT 代理的正确方法

为 APT 创建一个专用的代理配置文件:

sudo nano /etc/apt/apt.conf.d/proxy.conf

这个文件默认不存在,所以你在创建一个新文件。添加这些行:

Acquire::http::Proxy "http://proxyhost:port";
Acquire::https::Proxy "http://proxyhost:port";
Acquire::ftp::Proxy "ftp://proxyhost:port";

保存文件并退出。从现在开始,每个 apt 命令都会自动通过你的代理路由。你不需要重启任何东西。

测试 APT 是否使用代理

运行一个简单的更新来确认代理正在工作:

sudo apt update

如果 APT 连接并下载软件包列表而没有错误,你的代理配置就是正确的。

为特定主机禁用 APT 代理

有时你希望 APT 绕过某些内部服务器的代理:

Acquire::http::Proxy {
"internal.server.local" DIRECT;
};

这告诉 APT 直接连接到 internal.server.local,同时仍然通过代理路由所有其他流量。

移除 APT 代理

要停止 APT 使用代理,删除配置文件:

sudo rm /etc/apt/apt.conf.d/proxy.conf

方法 3:curl

curl 是 Ubuntu 上使用最广泛的命令行工具之一。配置它使用代理很简单,但理解它如何 find 配置文件可以节省大量调试时间。

为单个 curl 命令使用代理

添加 -x 标志:

curl -x http://proxyhost:port https://example.com

为你的用户永久设置代理

将你的代理 set 保存在 curl 的用户配置文件中:

nano ~/.curlrc

添加:

proxy = http://proxyhost:port

从现在开始,你运行的每个 curl 命令都会自动使用这个代理。curl 会依次查找 $CURL_HOME/.curlrc、$XDG_CONFIG_HOME/.curlrc 和 ~/.curlrc 中的这个文件。

让 curl 在系统范围内使用代理

curl 在 Linux 上没有标准的系统级配置文件路径。让 curl 为系统上所有用户使用代理的最可靠方法是在 /etc/profile.d/proxy.sh 中 set 环境变量(在方法 1 中已介绍)。curl 会自动以最低优先级读取 http_proxy 和 https_proxy,因此系统级环境变量是这里正确的方法。

如果你需要为特定用户或脚本覆盖代理,你可以使用 -K 标志让 curl 指向任何配置文件:

curl -K /path/to/curlconfig https://example.com

为单个命令覆盖代理

curl --noproxy "*" https://internal.server.local

SSL 证书注意事项

如果你的组织使用检查 HTTPS 流量的拦截代理,curl 会抛出 SSL 证书错误。在生产环境中 永远不要 使用 -k(不安全模式)。它会禁用所有证书验证。相反,请将你组织的根 CA 证书安装到 Ubuntu 的信任存储中。这将在“企业 CA 证书”部分详细介绍。

方法 4:wget

wget 有自己的配置文件,并且不继承 APT 的代理 set。

为单个 wget 命令使用代理

wget -e use_proxy=yes -e http_proxy=http://proxyhost:port https://example.com

为你的用户永久设置代理

nano ~/.wgetrc

添加:

http_proxy = http://proxyhost:port
https_proxy = http://proxyhost:port
ftp_proxy = ftp://proxyhost:port
use_proxy = on

为所有用户进行系统级设置

sudo nano /etc/wgetrc

找到与代理相关的行(默认情况下它们被注释掉了)。从每行中移除 # 并填入你的代理详细信息:

http_proxy = http://proxyhost:port
https_proxy = http://proxyhost:port
ftp_proxy = ftp://proxyhost:port
use_proxy = on

为特定域名绕过代理

在 ~/.wgetrc 中添加一个 no_proxy 行:

no_proxy = localhost,127.0.0.1,.internal.company.com

方法 5:GNOME 桌面设置

Ubuntu 26.04 默认使用 GNOME 50 作为其桌面环境。GNOME 包含一个易于使用的内置代理面板,但它有一个关键的限制。

如何访问 GNOME 代理设置

  1. 从应用菜单或右上角的系统托盘中打开 设置。
  2. 点击左侧边栏中的 网络。
  3. 向下滚动到 代理 并点击齿轮图标。

在下一个窗口中,将“网络代理”开关切换到“开”位置。然后,在“配置”部分选择“手动”。

分别为 HTTP、HTTPS、FTP 和 SOCKS 设置代理地址。

GNOME 代理设置的关键限制

GNOME 代理 set 仅适用于 GNOME 应用程序。 你的浏览器、文件应用和其他 GUI 应用会遵守这些 set。但是你的终端、apt、curl、wget、git 以及所有其他命令行工具会完全忽略它们。

这是一个非常常见的困惑来源。许多人在 GNOME 设置中 set 了代理,打开终端,然后 find 发现 curl 仍然直接连接。解决方案是始终将 GNOME 设置与环境变量结合使用,以获得全面覆盖。

何时 GNOME 设置就足够了

如果你只需要为你的网络浏览器和桌面应用提供代理 port,那么仅使用 GNOME 设置就足够了。否则,请将其与本指南中的方法一起使用。

方法 6:Git

几乎每个开发者和管理员都使用 Git。Git 内部使用 libcurl 来处理所有网络连接(包括 HTTP 和 HTTPS),这意味着它有自己独立于系统环境变量的代理配置。

设置全局 Git 代理

Git 的 http.proxy 配置键涵盖 HTTP 和 HTTPS 连接。你只需要 set 一个键:

git config --global http.proxy http://proxyhost:port

验证 set 已保存:

git config --global --list | grep proxy

为单个仓库设置代理

如果你只需要为某个特定仓库使用代理,在该仓库的目录内运行:

git config http.proxy http://proxyhost:port

为内部 Git 服务器绕过代理

如果你有一个应该直接连接的内部 GitLab 或 Gitea 服务器,告诉 Git 跳过该特定 URL 的代理:

git config --global http.https://gitlab.internal.company.com.proxy ""

移除 Git 代理

git config --global --unset http.proxy

Git 存储这些设置的位置

Git 将代理 set 写入 ~/.gitconfig。你也可以直接编辑这个文件:

nano ~/.gitconfig

它看起来像这样:

[http]
proxy = http://proxyhost:port

注意: Git 的 http.proxy 涵盖 HTTP 和 HTTPS 仓库 URL,因为 Git 内部对所有 port 都使用 libcurl。你不需要(也不应该 set)一个单独的 https.proxy 键,因为它不是一个有文档记录的 git 配置选项。

方法 7:pip(Python)

Python 的包管理器 pip 有自己的代理配置。虽然 pip 确实会读取 http_proxy 和 https_proxy 环境变量,但一个永久的 pip.conf 文件更可靠,并且无论 shell 环境如何 set 都能工作。

为单个 pip 命令设置代理

pip install requests --proxy http://proxyhost:port

为你的用户永久设置代理

创建 pip 配置目录和文件:

mkdir -p ~/.config/pip
nano ~/.config/pip/pip.conf

添加:

[global]
proxy = http://proxyhost:port

为所有用户进行系统级设置

pip 在 Linux 上检查 /etc/pip.conf 以获取全局 set:

sudo nano /etc/pip.conf

添加相同的内容:

[global]
proxy = http://proxyhost:port

在虚拟环境中的 pip

如果你使用 Python 虚拟环境,来自全局或用户 pip.conf 的代理仍然适用。但是,如果你需要每个项目使用不同的代理,在虚拟环境内部创建一个 pip.conf:

nano /path/to/venv/pip.conf

添加相同的 [global] 块,并填入项目特定的代理。

方法 8:npm(Node.js)

npm 将其代理配置与环境变量分开存储。你使用 npm config 命令来设置它,该命令会写入 ~/.npmrc。

设置 npm 代理

npm config set proxy http://proxyhost:port
npm config set https-proxy http://proxyhost:port

验证 npm 代理设置

npm config get proxy
npm config get https-proxy

移除 npm 代理

npm config delete proxy
npm config delete https-proxy

系统级 npm 代理

要将代理应用于机器上的所有用户,编辑全局 npmrc 文件:

sudo npm config set proxy http://proxyhost:port --global
sudo npm config set https-proxy http://proxyhost:port --global

与 npm 相关的 SSL 证书问题

如果 npm 在拦截代理后面抛出 SSL 错误,在安装你的企业证书后(详情请参见 CA 证书部分),将 npm 指向 Ubuntu 的系统 CA 包:

npm config set cafile /etc/ssl/certs/ca-certificates.crt

方法 9:Docker

Docker 需要在两个独立的地方进行代理配置,混淆它们是常见的错误之一。一个配置控制 Docker 守护进程本身(用于拉取镜像)。另一个控制 Docker 客户端操作,包括构建。

第 1 部分:Docker 守护进程的代理(拉取镜像)

Docker 守护进程作为 systemd 服务运行,因此它需要一个 systemd drop-in 文件。官方 Docker 文档建议创建一个特定名称的文件:

sudo mkdir -p /etc/systemd/system/docker.service.d
sudo nano /etc/systemd/system/docker.service.d/http-proxy.conf

添加:

[Service]
Environment="HTTP_PROXY=http://proxyhost:port"
Environment="HTTPS_PROXY=http://proxyhost:port"
Environment="NO_PROXY=localhost,127.0.0.1,.internal.company.com"

或者,sudo systemctl edit docker 会创建一个名为 override.conf 的相同目录结构。两种方法效果相同,因为 systemd 会读取目录中的所有 .conf 文件。

保存并退出,然后重新加载并重启 Docker:

sudo systemctl daemon-reload
sudo systemctl restart docker

确认环境变量已生效:

sudo systemctl show --property=Environment docker

第 2 部分:Docker 客户端的代理(构建、拉取等)

~/.docker/config.json 中的 Docker 客户端代理配置控制着代理 set 如何在 Docker CLI 操作期间被传递——包括 docker build、docker pull 以及在运行时需要代理访问的容器。在此处配置:

nano ~/.docker/config.json

添加或合并此块:

{
"proxies": {
"default": {
"httpProxy": "http://proxyhost:port",
"httpsProxy": "http://proxyhost:port",
"noProxy": "localhost,127.0.0.1,.internal.company.com"
}
}
}

Docker 会自动将这些值作为构建参数传递给每个 docker build 命令。你不需要手动添加 --build-arg。

注意: ~/.docker/config.json 中的代理 set 适用于 Docker CLI 客户端操作。它们会在 docker build 期间作为构建时 ARG 注入,并为遵守它们的操作 set 环境变量。但是,它们 不 会自动为使用 docker run 启动的长期运行容器 set 环境变量。这些容器需要它们自己的显式 -e 标志或它们自己的应用级代理配置。

方法 10:Snap 软件包

Ubuntu 26.04 将许多应用程序作为 Snap 软件包提供。Snap 完全忽略系统环境变量、/etc/environment 以及到目前为止涵盖的所有其他内容。它有自己的通过 snapd 管理的代理系统。

设置 Snap 代理

sudo snap set system proxy.http="http://proxyhost:port"
sudo snap set system proxy.https="http://proxyhost:port"

验证 Snap 代理

sudo snap get system proxy

你应该会看到类似这样的输出:

Key           Value
proxy.http    http://proxyhost:port
proxy.https   http://proxyhost:port

移除 Snap 代理

sudo snap unset system proxy.http
sudo snap unset system proxy.https

更改后重启 snapd

set 代理后,重启 snapd 服务以使更改立即生效:

sudo systemctl restart snapd

方法 11:Systemd 服务

任何作为 systemd 服务运行的应用程序(网络服务器、scraper 守护进程、计划任务)都 不 会从 /etc/environment、~/.bashrc 或任何用户级配置继承代理 set。

Systemd 服务在其自己的隔离环境中运行。许多管理员第一次遇到这种情况时会感到惊讶。

正确的方法是使用 systemd drop-in 覆盖文件,这可以使你的更改与原始单元文件分开,这样软件包更新就不会覆盖它们。

为任何服务创建 Drop-In 覆盖

将 servicename 替换为服务的实际名称(例如,nginx、myapp 或 scraper):

sudo systemctl edit servicename

这会在 /etc/systemd/system/servicename.service.d/override.conf 创建一个覆盖文件。添加:

[Service]
Environment="http_proxy=http://proxyhost:port"
Environment="https_proxy=http://proxyhost:port"
Environment="no_proxy=localhost,127.0.0.1,.internal.company.com"

保存并退出,然后重新加载 systemd 并重启服务:

sudo systemctl daemon-reload
sudo systemctl restart servicename

验证服务拥有正确的环境

sudo systemctl show servicename --property=Environment

一次性为所有服务应用代理

如果你希望机器上的每个 systemd 服务都使用同一个代理,创建一个 systemd 读取的全局环境文件:

sudo nano /etc/systemd/system.conf

找到 [Manager] 部分并添加或取消注释:

DefaultEnvironment="http_proxy=http://proxyhost:port" "https_proxy=http://proxyhost:port"

然后重新加载 systemd:

sudo systemctl daemon-reload

谨慎使用此方法。它会将代理应用于机器上的每一个服务,这很少是你想要的。

处理代理认证

许多代理服务器,特别是住宅和企业代理,需要用户名和 pass。将凭据添加到你的代理 URL 很简单,但有一些边缘情况需要小心处理。

基本认证格式

http://username:password@proxyhost:port

例如:

export http_proxy="http://john:[email protected]:8080"

用于 临时使用,在脚本中而不永久存储凭据:

read -sp "Proxy password: " PROXY_PASS
export http_proxy="http://username:${PROXY_PASS}@proxyhost:port"
unset PROXY_PASS  # Clear after use

密码中的特殊字符

如果你的 pass 包含特殊字符,如 @、:、/ 或 #,你必须对其进行 URL 编码。否则代理 URL 会出错,因为这些字符在 URL 中具有特殊含义。

例如,如果你的 pass 是 p@ss:word,在代理 URL 中将其写为 p%40ss%3Aword。

保护你的凭据

在 .bashrc 或 /etc/environment 中以明文形式存储 pass 是一种安全风险。这里有两种更好的方法:

选项 1:限制文件权限

创建一个只保存你的代理凭据的单独文件:

nano ~/.proxy_credentials

添加:

export http_proxy="http://username:password@proxyhost:port"
export https_proxy="http://username:password@proxyhost:port"
export ALL_PROXY="http://username:password@proxyhost:port"

锁定文件,以便只有你的用户可以读取它:

chmod 600 ~/.proxy_credentials

然后从你的 .bashrc 中引用它:

source ~/.proxy_credentials

选项 2:使用密钥管理器

对于生产服务器,考虑使用像 pass(标准的 Unix pass 管理器)或 HashiCorp Vault 这样的工具来在运行时存储和注入代理凭据。这种方法将凭据完全排除在配置文件之外,是任何拥有多个用户或自动化部署的服务器的正确选择。

安装企业 CA 证书

在企业环境中,代理服务器通常使用 TLS 检查。它们拦截你的 HTTPS 连接,并用它们自己的根证书重新签名。在你将该根证书安装到 Ubuntu 的系统信任存储之前,每个 CLI 工具都会抛出 SSL 错误。

这是正确的、永久的修复方法。永远不要 使用 -k(在 curl 中)或 --no-check-certificate(在 wget 中)作为变通方法。这些标志会禁用所有证书验证,使你暴露于来自任何来源的中间人攻击,而不仅仅是你的代理。

步骤 1:获取企业 CA 证书

向你的 IT 或网络团队索要根 CA 证书文件。它通常是 .crt 或 .pem 格式。如果你无法直接获取文件,你可以从已经信任该代理的浏览器中 export 它。

步骤 2:将证书复制到正确的位置

sudo cp your-corporate-ca.crt /usr/local/share/ca-certificates/

文件必须具有 .crt 扩展名。如果你的证书是 .pem 格式,请先重命名它:

sudo cp your-corporate-ca.pem /usr/local/share/ca-certificates/your-corporate-ca.crt

步骤 3:重建系统 CA 包

sudo update-ca-certificates

你应该会看到类似这样的输出,确认证书已添加:

Updating certificates in /etc/ssl/certs...
1 added, 0 removed; done.

之后,curl、wget、apt、git、pip、npm 和大多数其他工具将自动信任你的企业代理的证书。你不需要单独配置每个工具。

步骤 4:验证证书是否被信任

通过你的代理使用一个简单的 curl 请求进行测试:

curl -x http://proxyhost:port https://example.com

如果你不再看到 SSL 错误,则证书安装成功。

Java 和 Python SSL 存储

请注意,Java 和一些 Python 库维护它们自己独立的证书存储,并且不会自动读取 Ubuntu 的系统包。

对于 Java,cacerts 文件的位置取决于你安装的 JVM 版本。首先找到它,然后 port:

# Step 1 — Find your Java cacerts file
find /usr/lib/jvm -name "cacerts" 2>/dev/null
# Step 2 — Import your corporate CA (replace the path with the one found above)
sudo keytool -import -alias corporate-ca \
-file /usr/local/share/ca-certificates/your-corporate-ca.crt \
-keystore /usr/lib/jvm/java-21-openjdk-amd64/lib/security/cacerts \
-storepass changeit -noprompt

find 命令是必不可少的,因为路径会随着每个 JVM 版本和安装方法而变化。使用硬编码路径会在你的 JVM 安装方式不同时静默失败。

每个管理员都会遇到的 sudo 问题

这是 Ubuntu 上最常见的一个代理故障,即使是经验丰富的管理员也会遇到。

当你使用 sudo 运行任何命令时,sudo 默认会剥离你的环境变量,这是一种安全措施。这意味着 http_proxy、https_proxy 以及你 set 的所有其他代理变量都会对该命令消失,即使它们在你的 shell 中配置正确。

所以,当你 set 好环境变量然后运行 sudo apt update 时,APT 并不是因为 APT 忽略环境变量(它确实忽略)而忽略你的代理。更深层次的问题是,sudo 在 APT 启动之前就已经剥离了它们。

快速修复:为单个命令使用 sudo -E

-E 标志告诉 sudo 保留你的环境变量:

sudo -E curl https://example.com
sudo -E pip install requests

然而,这只对该命令有效,并且它不能修复 apt,因为 APT 无论如何都有自己的代理配置。

永久修复:配置 sudoers 以保留代理变量

正确的永久解决方案是告诉 sudo 要为所有命令保留哪些变量。使用 visudo 安全地编辑 sudoers 文件:

sudo visudo

找到 Defaults 部分并添加这一行:

Defaults env_keep += "http_proxy https_proxy ftp_proxy no_proxy ALL_PROXY HTTP_PROXY HTTPS_PROXY NO_PROXY"

保存并退出。从现在开始,sudo 将为每个命令保留你的代理环境变量。

验证 sudo 保留了变量

测试它是否工作:

export http_proxy="http://proxyhost:port"
sudo printenv http_proxy

如果你看到打印出了代理地址,那么 sudo 现在正确地保留了该变量。

安全说明: 在 sudoers 中保留代理环境变量在大多数环境中是安全的。但是,请注意,在高度敏感的系统中,代理变量理论上可能被操纵以重定向特权流量。在这种情况下,请为每个特权工具(APT、系统级 pip 等)配置其自己的专用配置文件,而不是依赖继承的环境变量。

验证你的代理是否真的在工作

检查变量是否已 set 和确认代理是否实际路由你的流量之间有一个重要区别。

运行 echo $http_proxy 只能确认该变量存在于你的 shell 中。它不能告诉你代理是否可达或正在工作。

使用这些命令来确认真正的代理连接。

检查世界看到的 IP

这是最可靠的测试。它通过你的代理发送一个请求,并返回目标服务器看到的 IP 地址:

curl -x http://proxyhost:port https://httpbin.org/ip

如果代理正在工作,响应中的 IP 地址应该匹配你的代理服务器的 IP,而不是你本地机器的 IP。如果它显示你的真实 IP,则代理被绕过了。

在详细模式下观察代理握手

-v 标志精确地显示了 curl 正在逐步做什么:

curl -v -x http://proxyhost:port https://example.com

在顶部附近寻找类似 Connected to proxyhost 的行。如果你看到 Connected to example.com,则 curl 正在绕过代理。

测试 sudo 是否保留了代理

export http_proxy="http://proxyhost:port"
sudo -E curl -x $http_proxy https://httpbin.org/ip

单独测试 APT

APT 不使用环境变量,所以独立测试它:

sudo apt update -o Acquire::http::proxy="http://proxyhost:port"

如果这个能工作,但你正常的 sudo apt update 不能,那么你的 APT 配置文件有问题。

测试 systemd 服务的网络路径

要确认一个服务是否通过代理路由,检查它实际看到的环境:

sudo systemctl show myservice --property=Environment

用于 Docker 守护进程代理验证

sudo systemctl show docker --property=Environment

Shell 兼容性:bash、zsh 和 fish

本指南通篇使用 bash 语法,因为 Ubuntu 26.04 默认使用 bash。然而,许多开发者使用 zsh 或 fish,并且 set 环境变量的语法因它们而异。

bash

添加到 ~/.bashrc(交互式 shell)或 ~/.bash_profile(登录 shell):

export http_proxy="http://proxyhost:port"
export https_proxy="http://proxyhost:port"
export no_proxy="localhost,127.0.0.1"

zsh

语法与 bash 相同。添加到 ~/.zshrc:

export http_proxy="http://proxyhost:port"
export https_proxy="http://proxyhost:port"
export no_proxy="localhost,127.0.0.1"

fish

Fish 使用完全不同的语法。添加到 ~/.config/fish/config.fish:

set -x http_proxy "http://proxyhost:port"
set -x https_proxy "http://proxyhost:port"
set -x no_proxy "localhost,127.0.0.1"

Fish 不使用 export。相反,-x 标志在 set 上将变量标记为 export 到子进程——这是 fish 中 export 的等价物。

注意: 无论你使用哪个 shell,系统级配置(/etc/environment、/etc/profile.d/proxy.sh、APT、curl、wget、Git、pip、npm、Docker、Snap 和 systemd)保持不变。Shell 语法只影响用户级的 ~/.*rc 文件。

理解变量优先级

当多个代理 set 同时存在时(一个环境变量、一个工具配置文件和一个命令行标志),哪个会胜出?理解这个顺序可以防止在 set 似乎没有生效时花费数小时进行调试。

curl 优先级(从高到低)

命令行标志总是胜出。如果你在 ~/.curlrc 中 set 了一个代理,但随后运行 curl --noproxy "*",该标志会完全覆盖配置文件。请注意,curl 在 Linux 上没有系统级配置文件——环境变量是系统级机制。

wget 优先级(从高到低)

git 优先级(从高到低)

pip 优先级(从高到低)

实际的要点是:命令行标志总是胜出,环境变量总是输。 如果一个工具没有使用你的代理,请检查某个地方的配置文件是否用不同的 set 覆盖了你的环境变量。

no_proxy 格式指南

no_proxy 变量告诉工具哪些主机应该直接连接,绕过代理。然而,不同的工具对其解释不同。如果你格式错误,你要么会将内部流量路由通过代理,要么会绕过本应使用代理的主机。

最兼容的格式

这种格式在大多数工具中都能正确工作:

export no_proxy="localhost,127.0.0.1,::1,.company.internal,10.0.0.0/8,192.168.0.0/16"

关键规则:

  • 使用 逗号 分隔条目——大多数工具中逗号后不要有空格。
  • 使用 前导点(.company.internal)来匹配一个域名及其所有子域名。没有点,大多数工具只匹配确切的主机名。
  • 你可以为 IP 范围包含 CIDR 表示法,但并非所有工具都 port——curl 和 wget 支持;较旧的工具可能不支持。
  • 始终显式包含 localhost 和 127.0.0.1。

工具特定差异

常见错误:缺少前导点

没有前导点,company.internal 只会绕过确切主机名 company.internal 的代理。像 gitlab.company.internal 这样的子域名仍然会通过代理。始终使用 .company.internal 来覆盖域名及其所有子域名。

常见问题故障排除

即使在仔细配置之后,有时事情也会出错。以下是最常见的问题及其解决方案。

1. 我的代理在浏览器中工作,但在终端中不工作。

GNOME 代理 set 仅适用于 GUI 应用。打开 ~/.bashrc 并添加方法 1 中所示的代理环境变量。然后运行 source ~/.bashrc。

2. 我 set 了环境变量,但 APT 仍然失败。

APT 设计上忽略环境变量。按照方法 2 中的描述创建 /etc/apt/apt.conf.d/proxy.conf。

3. 我 set 了环境变量,但 sudo 命令仍然绕过代理。

sudo 默认会剥离环境变量。要么对单个命令使用 sudo -E,要么使用 sudo visudo 将代理变量添加到 /etc/sudoers 中的 env_keep 列表。请参阅上面的 sudo 问题部分。

4. curl 工作,但 wget 不工作。

它们使用不同的配置文件。按照方法 4 中的描述将你的代理添加到 ~/.wgetrc。

5. 我什么都设置了,但 HTTPS 连接仍然因 SSL 错误而失败。

你位于一个重新签名证书的拦截代理后面。使用 CA 证书部分中的步骤安装你组织的根 CA 证书。永远不要 使用 -k 或 --no-check-certificate 作为永久修复。

6. 我的 systemd 服务仍然绕过代理。

服务不继承环境变量。使用 sudo systemctl edit servicename 创建一个带有显式 Environment= 行的 drop-in 覆盖。请参阅方法 11。

7. Snap 应用忽略我的代理 set。

Snap 有自己的代理系统。运行 sudo snap set system proxy.http="http://proxyhost:port" 和 sudo snap set system proxy.https="...",然后重启 snapd。请参阅方法 10。

8. Git clone 失败,即使 curl 工作正常。

Git 不会可靠地继承系统环境变量用于代理。使用 git config --global http.proxy http://proxyhost:port 显式设置代理。请注意,这个单一的键涵盖 HTTP 和 HTTPS 连接。请参阅方法 6。

9. pip 在代理后面安装失败。

创建 ~/.config/pip/pip.conf 并添加一个 [global] proxy = ... 行。请参阅方法 7。

10. Docker 无法拉取镜像。

Docker 守护进程是一个 systemd 服务,因此它需要自己的 drop-in 文件。请参阅方法 9,第 1 部分。这与 ~/.docker/config.json 中的 Docker 客户端配置是分开的。

11. 我的环境变量在我注销后消失了。

在终端中使用 export 设置的变量仅在该会话期间有效。将它们添加到你的用户的 ~/.bashrc,或所有用户的 /etc/environment 或 /etc/profile.d/proxy.sh。

12. 我的代理 set 有效,但某些内部服务器无法访问。

检查你的 no_proxy 变量。确保内部主机名有一个前导点(.company.internal),并且你已经包含了相关的 IP 范围。请参阅上面的 no_proxy 格式指南。

13. 我收到认证错误,即使我的凭据是正确的。

检查你的 pass 中是否有特殊字符。对任何 @、:、/ 或 # 字符进行 URL 编码。请参阅上面的认证部分。

快速参考表

以下是本指南涵盖的每个工具的完整摘要。

最终总结

在 Ubuntu 26.04 上配置代理比大多数人预期的要花更多功夫,但一旦你理解了,模式是一致的:每个工具管理自己的代理,环境变量只是一个起点,而不是完整的解决方案。

从本指南中需要记住的最重要的事情是:

  • 从 ~/.bashrc 和 /etc/environment 中的环境变量开始。它们以最少的努力覆盖了最广泛的工具。
  • 始终单独配置 APT。它从不读取环境变量。
  • 记住 sudo 会剥离你的环境。要么使用 sudo -E,要么在 sudoers 中配置 env_keep。
  • Systemd 服务和 Snap 包有完全独立的代理系统,忽略其他一切。
  • 将你组织的 CA 证书安装到 Ubuntu 的信任存储中一次,大多数 HTTPS 问题就会在所有工具中同时消失。
  • 始终使用小写的代理变量名。它们被广泛 port,并且避免了 httpoxy 安全漏洞。
  • Git 的 http.proxy 涵盖 HTTP 和 HTTPS 连接。你只需要 set 一次。
  • curl 在 Linux 上没有系统级配置文件;通过 /etc/profile.d/proxy.sh 使用环境变量来实现系统级的 curl 代理。

通过在整个堆栈的每一层进行正确的配置,你的 Ubuntu 机器将每次都准确地将流量路由到你想要的地方。

本指南对你有帮助吗?与正在处理同样代理问题的 Linux 管理员同事分享吧。