Alpine Linux has one small tool for its proxy, setup-proxy, and one program that really has to get through it: apk, the package manager. On a machine and inside a Docker image alike, three details decide whether apk update works: the variable it reads, the kind of proxy it accepts, and whether doas or docker build pass the setting on.
We did not install Alpine for this page. Every statement comes from Alpine's own code, read on 4 October 2026: setup-proxy from alpine-conf, the download code inside apk-tools 3.0.8 (the apk in Alpine 3.24.2, the same proxy code as apk 2.14), the apk manual, the Alpine 3.24.2 mini root filesystem, and the doas manual.
| Where | What reads the proxy | What it needs |
|---|---|---|
| Terminals and SSH logins | /etc/profile loads /etc/profile.d/proxy.sh | A new login |
| apk | The variables, nothing else | HTTPS_PROXY or https_proxy with an http:// address |
| doas | Nothing, unless the rule keeps the variables | setenv { ... } in the rule |
| docker build | Build arguments | --build-arg HTTPS_PROXY=... |
Used
http://host:port
for http and https mirrors alike
http://user:pass@host:port
login percent-decoded
Dropped without a message
socks5:// and socks5h://
apk connects directly
https://host:port
apk connects directly
host:port without http://
the address does not parse
What you need before you start
One proxy line, four parts
198.51.100.7Host:8080Port:hp_ir4k2Username:9fa2c1Password198.51.100.7:8080:hp_ir4k2:9fa2c1hp_ir4k2:9fa2c1@198.51.100.7:8080http://hp_ir4k2:9fa2c1@198.51.100.7:8080
Alpine takes all four in one address: http://user:pass@host:port. Values shown are examples.
- An HTTP proxy as
host:port, plus a user name and password if it needs a login. A SOCKS5-only proxy will not work with apk (see below). If your provider sent the parts in another order, the proxy format guide sorts them out. - Root, or doas rights.
- For a first test, any HTTP entry from our free proxy list will do. Free entries come and go, so test one first; the check further down shows how.
- Our free proxy setup generator writes the address with the password encoded where it has to be.

Step 1: run setup-proxy
As root:
setup-proxy http://198.51.100.7:8080
With a login: setup-proxy http://hp_ir4k2:9fa2c1@198.51.100.7:8080. Without an address, it asks for one and accepts only answers that start with http:// or https://, or none. setup-alpine asks the same question during installation.
setup-proxy writes this into /etc/profile.d/proxy.sh (1):
export http_proxy=http://198.51.100.7:8080
export https_proxy=http://198.51.100.7:8080
export ftp_proxy=http://198.51.100.7:8080
export no_proxy=localhost
It then installs GNU wget, because, in the script's own words, "busybox wget does not handle http proxies well" (2). That install runs before the new variables are loaded, so behind a network that only lets the proxy out it can fail; run apk add wget again once Step 2 works.
Alpine's /etc/profile loads every .sh file in /etc/profile.d/, so every new login has the variables. For the shell you are in:
. /etc/profile.d/proxy.sh
Writing the file by hand gives the same result: setup-proxy is only a writer for these four lines, and it overwrites them the next time it runs.

Step 2: what apk needs
apk takes the proxy from the environment and from nowhere else. Two rules from its code:
- It reads the variable for the mirror's scheme. Alpine 3.24.2 lists its mirrors as
https://dl-cdn.alpinelinux.org/...(5), so apk readsHTTPS_PROXY, thenhttps_proxy(4). Setting onlyHTTP_PROXY, as many older guides do, leaves apk going direct. Uppercase wins when both are set. - It keeps only an
http://proxy (3). Writehttp://inHTTPS_PROXYtoo: it names the kind of proxy, not the sites. Anhttps://,socks5://orsocks5h://address, or one without a scheme, is dropped without a message and apk connects directly, which looks like the proxy being ignored.
apk update
If it hangs and then reports temporary error (try again later), apk is going direct; check the variables with the commands under "Check that it worked".
/etc/apk/config holds apk's long options, one per line, but has no proxy option. A slow proxy can still use it: timeout 120 raises apk's wait from the default 60 seconds.
A SOCKS5-only proxy
apk has no SOCKS support at all. If all you have is SOCKS5, for example Tor:
- run apk through
torsocks(apk add tor torsocks, thentorsocks apk update), or - run a small local HTTP relay in front of the SOCKS5 proxy and point
https_proxyat it ashttp://127.0.0.1:<port>.
Programs other than apk, such as curl, do accept socks5h:// in the variables, so a SOCKS5 address in all_proxy can serve them while apk uses an HTTP one. HTTP vs SOCKS5 explains the difference.
A password with special characters
Two things read the password. The shell reads /etc/profile.d/proxy.sh with no quotes around the values, and apk percent-decodes the user name and password from the address, where the password ends at the first @ and the address at the first /:
| In the password | What goes wrong | Write it as |
|---|---|---|
@ | apk takes the rest as the host | %40 |
/ | apk ends the address there | %2F |
$ | The shell reads the rest as a variable name | %24 |
| a backquote | The shell runs what follows as a command | %60 |
& or ; | The shell ends the export there | %26, %3B |
| a space | The shell splits the value | %20 |
\ | The shell can take it as an escape and drop it | %5C |
Because apk decodes these, the proxy receives the password you were given. apk can also send a ready-made header from HTTP_PROXY_AUTH, used only when no login is in the address; most people never need it.
doas and sudo
doas starts the command with a fresh environment, so doas apk update runs without the proxy. Keep the variables in your rule, in /etc/doas.conf or a file in /etc/doas.d/:
permit persist setenv { http_proxy https_proxy no_proxy HTTP_PROXY HTTPS_PROXY NO_PROXY } :wheel
keepenv instead of setenv { ... } keeps every variable, which is broader than needed. If you installed sudo instead, sudo -E apk update keeps your variables for one command.
Alpine in Docker
Inside docker build, Alpine has no /etc/profile.d/proxy.sh to load. Pass the proxy as build arguments:
docker build --build-arg HTTP_PROXY=http://198.51.100.7:8080 --build-arg HTTPS_PROXY=http://198.51.100.7:8080 .
HTTP_PROXY, HTTPS_PROXY, FTP_PROXY, NO_PROXY and ALL_PROXY are predefined build arguments, so RUN apk add ... sees them without any ARG or ENV line, and Docker leaves them out of the build cache and of docker history. An ENV HTTPS_PROXY=... line in the Dockerfile works too, but bakes the proxy, and any password in it, into the image.
To set it once for every build, Docker's client config ~/.docker/config.json takes it:
{
"proxies": {
"default": {
"httpProxy": "http://198.51.100.7:8080",
"httpsProxy": "http://198.51.100.7:8080",
"noProxy": "localhost,127.0.0.1"
}
}
}
Exceptions with NO_PROXY
apk reads NO_PROXY, then no_proxy, as a comma-separated list and skips the proxy when:
- the host name ends with an entry (
example.comcoversmirror.example.com), or - the host is an IP address inside a range such as
10.0.0.0/8or192.168.0.0/16.
A range does not match a name that only resolves to an address inside it, and a single * turns the proxy off for everything. Name matching is a plain ending, so example.com also covers badexample.com; write .example.com to require the dot. A local mirror listed by IP address in /etc/apk/repositories is the case where ranges help.
Check that it worked
env | grep -i _proxy
doas env | grep -i _proxy
apk update
apk add curl
curl -s https://www.cloudflare.com/cdn-cgi/trace | grep ^ip=
The first shows your variables, the second what doas passes on, the third proves apk reaches its mirrors, and the last two show the address the internet sees, which should be the proxy's. Our IP lookup tells you who owns it.
Mistakes other guides make
These come up in the pages and answers that rank for Alpine and apk proxy searches:
- Only
HTTP_PROXY. Correct when Alpine's mirrors were http; today they are https and apk readsHTTPS_PROXY. - An
/etc/apk/apk.conffile. apk reads no such file and has no proxy option. https_proxy=https://...orsocks5://...for apk. apk drops both and goes direct.--build-args. The Docker option is--build-arg, once per variable.ENVlines for the proxy. They keep the proxy, and its password, in the image.
Turning it off again
- Run
setup-proxy none. It deletes/etc/profile.d/proxy.sh. - In shells that are already open:
unset http_proxy https_proxy ftp_proxy no_proxy. - Remove the
setenvfrom your doas rule if you added it, and theproxiesblock from~/.docker/config.json.
How we wrote this
We did not install Alpine for this page. We read Alpine's own code on 4 October 2026: setup-proxy from alpine-conf; from apk-tools 3.0.8 (and 2.14.12, which has the same proxy code), the download library's http.c, fetch.c and common.c, the apk manual and the code that loads /etc/apk/config; the /etc/apk/repositories and /etc/profile of the Alpine 3.24.2 mini root filesystem; the doas manual and Alpine's doas package; and Docker's page on proxies. The picture above is our own terminal reading of those sources.
Real problems come from Stack Overflow (questions with 29,842 and 5,258 views), Super User (8,128 views) and Unix & Linux (a question about apk over Tor).
Limits: no command on this page ran on Alpine. BusyBox wget, GNU wget and curl each read the variables their own way and were not traced line by line; this page sticks to apk, the shell, doas and docker build. The Alpine wiki page on setup-proxy could not be fetched.
Sources
All read on 4 October 2026.
- Alpine alpine-conf:
setup-proxy.in(gitlab.alpinelinux.org/alpine/alpine-conf). - Alpine apk-tools v3.0.8 and v2.14.12:
libfetch/http.c,libfetch/fetch.c,libfetch/common.c,src/apk.c;doc/apk.8.scd(gitlab.alpinelinux.org/alpine/apk-tools). - Alpine 3.24.2 mini root filesystem:
/etc/apk/repositories,/etc/profile(dl-cdn.alpinelinux.org). - OpenDoas
doas.conf(5); Alpine aportsmain/doas(itsdoas.confand/etc/doas.d). - Docker Docs: Use a proxy server with the Docker CLI.
- Stack Overflow questions 48277599, 57048320 and 71231895; Super User question 1453107; Unix & Linux question 657929.
- Our terminal reading of setup-proxy, apk 3.0.8 and Alpine 3.24.2, 4 October 2026.


