Configuring a Proxy on Ubuntu and Debian, Layer by Layer

Updated:

An Ubuntu proxy setup is really four small setups, because Linux has no single proxy switch. Your shell reads environment variables, APT reads its own config directory, systemd services read unit drop-ins, and the GNOME desktop uses gsettings. Configure only the layers you use; the snippets below assume a ProxyV4 HTTP(S) proxy with a username and password.

Ubuntu / Linux · HTTP Proxy Format
export http_proxy=http://user:pass@ip:port https_proxy=http://user:pass@ip:port

Which file controls which program

Most "my proxy is ignored" reports on Linux come from setting the right value in the wrong place. Two rules explain nearly all of them: sudo drops your user's environment by default, and systemd services never read ~/.bashrc.

LayerWhere it is setWho reads itLasts
Login shells~/.bashrc or /etc/profile.d/proxy.shcurl, wget, python, git, nodeEvery new login shell
PAM sessions/etc/environmentAll user sessionsAcross reboots
APT/etc/apt/apt.conf.d/80proxyapt update, apt installPermanently, for APT
systemd units/etc/systemd/system/<svc>.service.d/proxy.confDocker daemon, your own servicesAfter daemon-reload and restart

Shell and APT configuration

Define the variables in both lower and upper case: curl and wget look at http_proxy, while other runtimes only check HTTP_PROXY. The no_proxy list keeps loopback and private ranges off the proxy.

bash # /etc/profile.d/proxy.sh - shells and CLI tools sudo tee /etc/profile.d/proxy.sh > /dev/null << 'EOF' export http_proxy="http://USER:PASS@IP:PORT" export https_proxy="http://USER:PASS@IP:PORT" export HTTP_PROXY="http://USER:PASS@IP:PORT" export HTTPS_PROXY="http://USER:PASS@IP:PORT" export no_proxy="localhost,127.0.0.1,::1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16" export NO_PROXY="$no_proxy" EOF source /etc/profile.d/proxy.sh # /etc/apt/apt.conf.d/80proxy - package manager sudo tee /etc/apt/apt.conf.d/80proxy > /dev/null << 'EOF' Acquire::http::Proxy "http://USER:PASS@IP:PORT/"; Acquire::https::Proxy "http://USER:PASS@IP:PORT/"; EOF

If the password contains characters such as @, : or #, percent-encode them in these URLs.

Services managed by systemd

A daemon started by systemd only sees variables declared in its unit. Put them in a drop-in, reload, and restart the service. The Docker guide covers the Docker daemon and containers in detail.

bash # /etc/systemd/system/<svc>.service.d/proxy.conf [Service] Environment="HTTP_PROXY=http://USER:PASS@IP:PORT" Environment="HTTPS_PROXY=http://USER:PASS@IP:PORT" Environment="NO_PROXY=localhost,127.0.0.1" sudo systemctl daemon-reload sudo systemctl restart <svc>

sudo, shared servers and the desktop

  • sudo: run sudo -E curl ... to keep your exported variables, or make it permanent with Defaults env_keep += "http_proxy https_proxy HTTP_PROXY HTTPS_PROXY no_proxy NO_PROXY" added through sudo visudo.
  • Credentials on multi-user machines: these files hold the proxy password in plain text. Lock them down, for example sudo chmod 600 /etc/apt/apt.conf.d/80proxy.
  • GNOME desktop: Settings → Network → Network Proxy → Manual, or gsettings set org.gnome.system.proxy mode 'manual' plus the host and port keys under org.gnome.system.proxy.http.

Testing and troubleshooting

After sourcing the profile, curl -s https://api.ipify.org should print the proxy IP rather than the server's own address. For a full report on country and owner, paste the IP into IP lookup. The curl and Python requests guides show per-command alternatives when you would rather not proxy the whole shell.

  • `407 Proxy Authentication Required`: wrong credentials or an unencoded special character in the password; see the 407 page.
  • apt works only with sudo -E: the 80proxy file is missing or has a syntax error (each line ends in a semicolon).
  • Connections hang: outbound access to the proxy port may be blocked by the server's firewall; check firewall causes.

Step by step

  1. 1

    Write /etc/profile.d/proxy.sh

    Export http_proxy, https_proxy and no_proxy in lower case and HTTP_PROXY, HTTPS_PROXY and NO_PROXY in upper case so every CLI tool finds them.

  2. 2

    Give APT its own proxy file

    Because sudo apt update ignores your shell variables, create /etc/apt/apt.conf.d/80proxy with Acquire::http::Proxy and Acquire::https::Proxy.

  3. 3

    Add systemd drop-ins where needed

    For each daemon that must use the proxy, create a proxy.conf drop-in with Environment lines, then run daemon-reload and restart it.

  4. 4

    Confirm the exit IP

    Run source /etc/profile.d/proxy.sh and then curl -s https://api.ipify.org; the output should be your proxy's IP.

Frequently asked questions

Do I really need both http_proxy and HTTP_PROXY?

Yes. Some tools such as curl and wget check the lowercase name, others only the uppercase one. Setting both avoids inconsistent behaviour.

Why does sudo apt update not use my proxy?

sudo resets the environment unless you pass -E. A file in /etc/apt/apt.conf.d/ makes APT use the proxy regardless.

How do I set the proxy in the Ubuntu desktop GUI?

Open Settings → Network → Network Proxy and choose Manual, or set it with gsettings under org.gnome.system.proxy.

Is a static proxy useful on a Linux server?

Yes, when a remote API or partner allowlists your IP. A private IPv4 keeps the same address for as long as you renew it, so the allowlist entry stays valid.

Fixed-IP proxies for servers and scripts

HTTP(S) with username and password, unlimited bandwidth on private IPv4, and the same address on every renewal.

Compare prices

Related articles

Proxy setup
Running Docker containers behind an authenticated HTTP proxy
Send Docker container, build and image pull traffic through an authenticated HTTP(S) proxy, keep service-to-service calls local with NO_PROXY and verify the IP.
Proxy setup
Using cURL with an authenticated proxy: commands that prove it works
Send cURL requests through an authenticated HTTP(S) proxy with -x and -U, confirm the exit IP, read the CONNECT handshake and time each request on any OS.
Proxy setup
Python requests through an authenticated proxy, step by step
Send Python requests through an authenticated HTTP(S) proxy: build the proxies dict, attach it to a Session, encode odd passwords, rotate a list, check the IP.
Free tools
Check proxies in bulk: status, exit IP and latency
Free online proxy checker: paste up to 100 ip:port:user:pass lines and see which proxies work, their exit IP and latency, plus what each failure result means.
Proxies by platform
Proxies for web scraping: a fixed pool of IPs with unmetered traffic
Web scraping proxies for Python, Scrapy, Playwright and Selenium: a pool of private IPv4 and static ISP addresses, unlimited bandwidth, flat per-IP pricing.
Proxies by platform
Airdrop and Grass proxies: a separate IPv4 for every wallet and node
Airdrop and Grass proxies that give each wallet and DePIN node its own IPv4. Static ISP for Grass, Dawn and Nodepay; private IPv4 for quests and testnets.
Proxies by platform
Proxies for SEO rank tracking: see the results page a local searcher sees
SEO rank tracking proxies with a private IPv4 in the US, UK, Vietnam, Japan and four more markets, so rankings, local packs and ads match what locals see.
IPV4 · united states
Build a US IP Pool for Scraping, Rank Tracking and Ad Checks
Buy US private IPv4 proxies: static American datacenter IPs, one customer per IP, unlimited bandwidth. Built for scraping, SERP tracking and US ad checks.