Run setup-proxy http://host:port as root to set a proxy on Alpine Linux; it writes the proxy variables to /etc/profile.d/proxy.sh. The package manager, apk, reads only HTTPS_PROXY or https_proxy for Alpine's https mirrors, and keeps only an http:// proxy address. For doas and docker build, pass the variables on explicitly.
Three details decide whether apk update works, on a machine and inside a Docker image alike. They are 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 October 4, 2026. The sources are setup-proxy from alpine-conf, the download code inside apk-tools 3.0.8, the apk manual, the Alpine 3.24.2 mini root filesystem and the doas manual. That apk was the one in Alpine 3.24.2, with the same proxy code as apk 2.14. On November 7, 2026, we checked the newer releases. Alpine 3.24.4 ships apk-tools 3.0.9, whose changes since 3.0.8 leave the download code untouched, and its mirrors are still https.
| 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. 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. The tool only writes 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 and 3.24.4 list their 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. 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. It 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. A RUN apk add ... line 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 and the second what doas passes on. The third proves apk reaches its mirrors. The last two show the address the internet sees, which should be the proxy's. Our IP lookup tells you who owns it.
Where people get stuck
Five questions on Stack Exchange show where Alpine users get stuck behind a proxy. Together they had been viewed 45,931 times by November 7, 2026.
Each one maps to a section above:
- pip inside an Alpine 3.7 Dockerfile, built behind a proxy (29,866 views): see "Alpine in Docker".
setup-alpineanswering "403 Forbidden" while it scanned the mirror list through a proxy (8,196 views): see Step 1, and test the proxy itself first.- git in an Alpine image behind a corporate proxy, ending in apk's
temporary error (try again later)(5,260 views): see Step 2. - apk over Tor, through a SOCKS5 proxy (2,317 views): see "A SOCKS5-only proxy".
apk add opensshbehind a proxy, from a corporate mirror (292 views): see "Exceptions with NO_PROXY".
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 October 4, 2026. From alpine-conf we read setup-proxy. From apk-tools 3.0.8 (and 2.14.12, which has the same proxy code) we read the download library's http.c, fetch.c and common.c, the apk manual and the code that loads /etc/apk/config. From the Alpine 3.24.2 mini root filesystem we read /etc/apk/repositories and /etc/profile. We also read the doas manual, 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 five questions on Stack Overflow, Super User and Unix & Linux, shown in the chart above. On November 7, 2026, we compared apk-tools 3.0.8 with 3.0.9 and read the Alpine 3.24.4 mini root filesystem.
What this page could not check
No command on this page ran on Alpine. BusyBox wget, GNU wget and curl each read the variables their own way, and we did not trace them 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. The view counts show how many people opened each question, not how many had the same problem. This page is due for a check when Alpine 3.25 comes out, and by January 7, 2027, at the latest.
Sources
All read on October 4, 2026, unless a line says otherwise.
- 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, October 4, 2026.
- Alpine apk-tools: the comparison of v3.0.8 with v3.0.9, and the apk-tools package of Alpine v3.24 (3.0.9-r0), read November 7, 2026.
- Alpine 3.24.4 mini root filesystem, released November 5, 2026:
/etc/apk/repositories,/etc/profile, read November 7, 2026. - Stack Exchange API: the view counts of the five questions, read November 7, 2026.



