A proxy exported from /etc/profile.d reaches your login shell and very little else. In our tests on Ubuntu and Debian, sudo, commands run over SSH and every systemd service went straight past it, and on Debian even /etc/environment doesn’t reach sudo apt. Where you put the proxy decides which of those programs actually use it.
This guide shows you how to set a system-wide proxy on Ubuntu and Debian that holds up. You’ll use /etc/environment for users and sudo, an APT proxy file for package installs (with a password, if your proxy needs one) and a systemd drop-in for services, then cover the snap proxy and the GNOME network proxy panel on desktops. Every claim below was checked against a Squid proxy’s access log from fresh Ubuntu 26.04 and 24.04 VMs and Debian 13 in October 2026, with Debian 12’s sudo checked in a container.
Where each Ubuntu and Debian proxy setting applies
No single file covers everything, so start by deciding which programs need the proxy. We set each method on its own and checked whether the request showed up in Squid’s log:
| Setting | Login shell | ssh host cmd | sudo on Ubuntu | sudo on Debian | systemd services |
|---|---|---|---|---|---|
/etc/profile.d/proxy.sh | Yes | No | No | No | No |
/etc/environment | Yes | Yes | Yes | No | No (snapd is the exception) |
/etc/apt/apt.conf.d/95proxy | APT only | APT only | APT only | APT only | APT only |
systemd DefaultEnvironment | No | No | No | No | Yes |
/etc/environment is the best base because PAM reads it at login, for interactive and non-interactive SSH sessions alike, and Ubuntu’s /etc/pam.d/sudo reads it again for every sudo command. Debian’s sudo PAM file has no pam_env line: on Debian 13 dpkg -V sudo confirmed the shipped file was untouched and sudo env showed no proxy variables, and a fresh Debian 12 sudo install has the same file. Debian servers need the APT file as well. Services need their own setting on both, because systemd never reads login files.
For most servers that means three files, which the rest of this guide sets up in order:
/etc/environmentfor users, SSH commands and (on Ubuntu) sudo/etc/apt/apt.conf.d/95proxyso package installs work on Debian and with an authenticated proxy- a systemd drop-in for any service that has to reach the internet
The examples use a proxy at 10.0.1.10 on port 3128, the Squid default. Replace both with your proxy’s address and port. If you do not have a proxy yet, our Squid on Ubuntu 26.04 guide sets one up. On a new server, do this right after the first steps in our Ubuntu 26.04 server checklist, because the very first apt update needs it.
Set the proxy in /etc/environment
/etc/environment isn’t a shell script, so it takes plain NAME="value" lines with no export. Open it:
sudo vim /etc/environment
Keep the existing PATH line and add the proxy variables below it, in both lowercase and uppercase:
http_proxy="http://10.0.1.10:3128/"
https_proxy="http://10.0.1.10:3128/"
no_proxy="localhost,127.0.0.1,::1"
HTTP_PROXY="http://10.0.1.10:3128/"
HTTPS_PROXY="http://10.0.1.10:3128/"
NO_PROXY="localhost,127.0.0.1,::1"
You need both cases because tools disagree. curl and wget only read the lowercase http_proxy; given only HTTP_PROXY, both connected directly and Squid logged nothing. curl does accept uppercase HTTPS_PROXY and NO_PROXY, and many other programs read either form, so setting both case variants is the safe default. Add your internal domains and subnets to both no_proxy lines, and read the no_proxy section below first, because a subnet written as a CIDR only works for some tools.
Nothing changes for sessions that are already open, because PAM reads the file at login. Log out and back in, then check what your shell, sudo and a service see. On Ubuntu 26.04 the variables reached the shell and sudo, while a transient systemd unit saw none, and the Via header proves curl went through Squid:

Ubuntu 26.04 ships sudo-rs as its sudo, and it does not support -E. The old advice to run sudo -E apt update prints preserving the entire environment is not supported, '-E' is ignored there. That is another reason to rely on /etc/environment, which sudo reads through PAM, instead of carrying your shell’s variables across. Ubuntu 24.04 still has classic sudo, where -E works.
Configure an APT proxy
APT reads its own proxy setting from /etc/apt/apt.conf.d/, and it applies to apt however you run it: through sudo, from cron or from unattended-upgrades. On Debian this file is the simplest way to get sudo apt through a proxy, and on Ubuntu it is still the right place for proxy credentials. Create the file:
sudo vim /etc/apt/apt.conf.d/95proxy
Add one line per protocol. The https line still uses an http:// proxy URL, because APT tunnels HTTPS through the proxy with CONNECT:
Acquire::http::Proxy "http://10.0.1.10:3128/";
Acquire::https::Proxy "http://10.0.1.10:3128/";
Run an update and watch the proxy’s log. On both Ubuntu releases every InRelease file showed up in Squid’s log, and Debian 13’s HTTPS mirrors went through as CONNECT tunnels to deb.debian.org:
sudo apt update
On Ubuntu, apt update also opened a tunnel to esm.ubuntu.com for Ubuntu Pro on both releases, although neither VM was attached to Pro, so allow that host on the proxy if it filters destinations.
Proxy with a username and password
Put the credentials in the URL, with any @, : or / in the password percent-encoded, so a password of P@ss:word1 becomes P%40ss%3Aword1. APT happened to parse the raw P@ss:word1 correctly in our test, but curl rejected the same URL (the error is below), so encode it once and the URL works everywhere:
Acquire::http::Proxy "http://proxyuser:P%40ss%[email protected]:3128/";
Acquire::https::Proxy "http://proxyuser:P%40ss%[email protected]:3128/";
The file now holds a password, so make it readable by root only:
sudo chmod 600 /etc/apt/apt.conf.d/95proxy
sudo apt keeps working after that. Commands you run as a normal user that read APT’s configuration, such as apt-config dump or apt list, print a warning that is safe to ignore:
W: Unable to read /etc/apt/apt.conf.d/95proxy - open (13: Permission denied)
The same encoded URL works in /etc/environment if every program on the machine should authenticate, but then any user can read the password from their environment, so keep credentials in the APT file where you can.
Error: “407 Proxy Authentication Required”
APT prints this for each repository when the proxy wants credentials it didn’t get or did not accept:
Err:1 http://archive.ubuntu.com/ubuntu resolute InRelease
407 Proxy Authentication Required [IP: 10.0.1.10 3128]
Either the URL has no username and password, or the proxy rejected them. Squid logs the same request as TCP_DENIED/407 with the username it was given, which tells you whether a username reached it at all.
Error: “Port number was not a decimal number between 0 and 65535”
curl prints this when a proxy URL holds an unencoded : or @ in the password:
curl: (5) Unsupported proxy syntax in 'http://proxyuser:P@ss:[email protected]:3128': Port number was not a decimal number between 0 and 65535
curl split the URL at the first @, so it read ss:[email protected]:3128 as the host and port. With the password written as P%40ss%3Aword1 the same request returned HTTP 200 through the proxy.
Set the proxy for systemd services
Services started by systemd don’t read /etc/environment or anything in /etc/profile.d, so a daemon that downloads updates, pulls images or calls an API goes direct even when every shell on the box uses the proxy. You have two choices, and which one fits depends on how many services need it.
For one service, add a drop-in with sudo systemctl edit <service>, which creates /etc/systemd/system/<service>.service.d/override.conf, and put the variables under [Service]:
[Service]
Environment="http_proxy=http://10.0.1.10:3128/" "https_proxy=http://10.0.1.10:3128/" "no_proxy=localhost,127.0.0.1,::1"
To give every service the proxy, set it in the systemd manager instead. That reaches every daemon on the box, container runtimes and monitoring agents included, so add your internal domains and subnets to this no_proxy too, or those services will start sending internal traffic to the proxy. Create the directory and the drop-in file:
sudo mkdir -p /etc/systemd/system.conf.d
sudo vim /etc/systemd/system.conf.d/proxy.conf
Add the variables as DefaultEnvironment:
[Manager]
DefaultEnvironment="http_proxy=http://10.0.1.10:3128/" "https_proxy=http://10.0.1.10:3128/" "no_proxy=localhost,127.0.0.1,::1"
Reload systemd, then confirm the manager picked it up:
sudo systemctl daemon-reload
systemctl show-environment | grep -i proxy
A daemon-reload was enough on Ubuntu 26.04 and 24.04; no reboot or daemon-reexec needed. Services that are already running keep their old environment until you restart them, so restart the ones that need the proxy. A test unit started after the reload showed up in Squid’s log, while the same request from a unit started before the change never reached Squid. Setting DefaultEnvironment changes nothing for your shell, SSH commands or sudo, which all still showed no proxy variables. Per-user services run under a separate manager, and on our 26.04 VM systemctl --user show-environment still listed proxy variables picked up at login, so check that one too if you run systemctl --user units.
Know what no_proxy actually matches
no_proxy is a comma-separated list, and each tool parses it its own way. With the proxy in http_proxy, we sent requests that should have bypassed it and checked Squid’s log for each:
no_proxy entry | curl | wget |
|---|---|---|
.ubuntu.com (domain suffix) | Bypassed | Bypassed |
10.0.1.0/24 (CIDR) | Bypassed | Sent through the proxy |
wget does not understand CIDR notation, so a request to a host inside the subnet still went through Squid. If you have internal hosts that only wget, or another tool with the same limitation, has to reach, list them by name or domain suffix as well as by subnet. Servers on a fixed internal range, like the ones in our netplan static IP guide, are the usual case. For a one-off download, wget --no-proxy skips the proxy entirely.
Set the proxy for snap packages
snapd runs as a systemd service, so it can’t see a proxy you set for users. Give it its own setting:
sudo snap set system proxy.http="http://10.0.1.10:3128/" proxy.https="http://10.0.1.10:3128/"
Reading the setting back also needs sudo; without it, snap answers error: access denied (try with sudo). The -d flag keeps the JSON format that newer snapd warns it will change:
sudo snap get -d system proxy
The output shows both values:
{
"proxy": {
"http": "http://10.0.1.10:3128/",
"https": "http://10.0.1.10:3128/"
}
}
After that, snap info reached api.snapcraft.io through Squid on both Ubuntu releases, and on 26.04 a snap install hello pulled from the snap CDN through the proxy as well. snapd’s unit file also loads /etc/environment with EnvironmentFile=, but only when the service starts. If you change the proxy on a running system, snap set is the cleaner route.
Set the proxy on a GNOME desktop
On Ubuntu Desktop and Debian with GNOME, open Settings, go to Network and open the network proxy setting, set it to Manual and enter the proxy host and port for HTTP and HTTPS. GNOME’s help page describes the steps; the exact labels move a little between GNOME releases. Applications that follow GNOME’s proxy setting use it straight away.
The panel stores GNOME settings, not session-wide environment variables. GNOME’s terminal apps, Ptyxis and GNOME Terminal, read those settings and export http_proxy and friends into the shells they open, but sudo, SSH sessions and systemd services never see them. The same settings can be scripted with gsettings, which is handy for provisioning desktops:
gsettings set org.gnome.system.proxy mode 'manual'
gsettings set org.gnome.system.proxy.http host '10.0.1.10'
gsettings set org.gnome.system.proxy.http port 3128
gsettings set org.gnome.system.proxy.https host '10.0.1.10'
gsettings set org.gnome.system.proxy.https port 3128
gsettings set org.gnome.system.proxy ignore-hosts "['localhost', '127.0.0.0/8', '::1', '10.0.0.0/8', '*.example.com']"
We read the keys back with gsettings get to confirm them. A desktop that also runs sudo apt or background services still needs the /etc/environment lines and the APT file from earlier sections.
Remove the proxy settings
When the machine moves off the proxy network, a stale setting breaks apt and every download with a connection timeout, so remove each layer you added:
- Delete the proxy lines from
/etc/environment, then log out and back in. - Delete
/etc/apt/apt.conf.d/95proxy. - Delete
/etc/systemd/system.conf.d/proxy.confand any service drop-ins, runsudo systemctl daemon-reloadand restart the affected services. - Run
sudo snap unset system proxy.http proxy.https. - Set GNOME back with
gsettings set org.gnome.system.proxy mode 'none'.
env | grep -i proxy and systemctl show-environment | grep -i proxy coming back empty after a fresh login, and sudo apt update reaching the mirrors directly, confirm the machine is clean. For the proxy server side, our Squid guide for Rocky Linux and RHEL and the overview of proxy server types cover what sits at the other end of these settings. The apt.conf manual lists every Acquire:: proxy option, including per-host overrides.
How to set proxy for pacman ? I am arch user
export http proxy didnt work,
Hi, We will work on arch article and share link with you. Thanks
Hi
How to disable proxy that set via CLI?
Thanks for these – they saved me a lot of time.
I did spot a slight bug, though. In the proxy.sh file, the https_proxy/HTTPS_PROXY lines should use “https” in the proxy URL, not “http”.
U can use GUI settings or set it up by using proxyman