APT Proxy

Caching proxy for APT (Ubuntu/Debian), YUM (CentOS), and APK (Alpine). Speeds up repeated package downloads by serving them from a local cache. Drop-in replacement for apt-cacher-ng.
π Quick Start
# Docker
docker run -d -p 3142:3142 -v apt-proxy-cache:/app/.aptcache tuzelko/apt-proxy
# Or download the binary from the releases page
./apt-proxy
The proxy starts immediately and benchmarks mirrors in the background, switching to the fastest one for your network once the benchmark completes.
| OS |
Architectures |
| Linux |
x86_64, x86_32, ARM64, ARM32v6, ARM32v7 |
| macOS |
x86_64, Apple Silicon (ARM64) |
π§ Usage
Ubuntu / Debian
# One-off
http_proxy=http://your-host:3142 apt-get update
http_proxy=http://your-host:3142 apt-get install vim -y
# Persistent β /etc/apt/apt.conf.d/01proxy
Acquire::http::Proxy "http://your-host:3142";
CentOS 7
sed -i \
-e 's/mirrorlist.*$//' \
-e 's/#baseurl/baseurl/' \
-e 's#http://mirror.centos.org#http://your-host:3142#' \
/etc/yum.repos.d/CentOS-Base.repo
yum update
CentOS 8
sed -i \
-e 's#mirror.centos.org#http://your-host:3142#g' \
-e 's/#baseurl/baseurl/' \
-e 's#\$releasever/#8-stream/#' \
/etc/yum.repos.d/CentOS-*
yum update
Alpine
sed -i 's#https://.*.alpinelinux.org#http://your-host:3142#' /etc/apk/repositories
apk update
βοΈ Configuration
Priority (highest first): CLI flags β environment variables (APT_PROXY_*) β YAML file β defaults.
| Flag |
Env var |
Default |
Description |
-host |
APT_PROXY_HOST |
0.0.0.0 |
Interface to bind |
-port |
APT_PROXY_PORT |
3142 |
Port to listen on |
-mode |
APT_PROXY_MODE |
all |
all, ubuntu, ubuntu-ports, debian, centos, alpine |
-cachedir |
APT_PROXY_CACHEDIR |
./.aptcache |
Cache directory |
-cache-max-size |
APT_PROXY_CACHE_MAX_SIZE |
10 |
Max cache size, GB (0 = unlimited, LRU eviction) |
-cache-ttl |
APT_PROXY_CACHE_TTL |
168 |
Cache TTL, hours (0 = no expiry) |
-cache-cleanup-interval |
APT_PROXY_CACHE_CLEANUP_INTERVAL |
60 |
Cleanup interval, minutes |
-ubuntu / -debian / etc. |
APT_PROXY_UBUNTU / β¦ |
auto |
Mirror URL or shortcut |
-distributions-config |
APT_PROXY_DISTRIBUTIONS_CONFIG |
(search paths) |
Path to distributions.yaml |
-disable-builtin-distros |
APT_PROXY_DISABLE_BUILTIN_DISTROS |
false |
Disable built-in distributions; use only those defined in distributions.yaml |
-async-benchmark |
APT_PROXY_ASYNC_BENCHMARK |
true |
Benchmark mirrors in background on startup |
-api-key |
APT_PROXY_API_KEY |
β |
Key for management API endpoints |
-tls / -tls-cert / -tls-key |
APT_PROXY_TLS_* |
β |
HTTPS support |
-config |
APT_PROXY_CONFIG_FILE |
β |
Path to YAML config file |
-debug |
APT_PROXY_DEBUG |
false |
Verbose logging |
-version |
β |
β |
Print version and exit |
Mirror shortcuts
cn:tsinghua Β· cn:ustc Β· cn:163 Β· cn:aliyun Β· cn:huaweicloud Β· cn:tencent
./apt-proxy --ubuntu=cn:tsinghua --debian=cn:ustc
YAML config
Config file search paths: ./apt-proxy.yaml β /etc/apt-proxy/apt-proxy.yaml β ~/.config/apt-proxy/apt-proxy.yaml β ~/.apt-proxy.yaml
server:
host: 0.0.0.0
port: 3142
debug: false
cache:
dir: /var/cache/apt-proxy
max_size_gb: 20
ttl_hours: 168
cleanup_interval_min: 60
mirrors:
ubuntu: cn:tsinghua
debian: cn:ustc
security:
api_key: ${APT_PROXY_API_KEY}
enable_api_auth: true
π Distributions and Mirrors (distributions.yaml)
Mirror lists and distribution settings are defined in distributions.yaml. You can extend or override them without recompiling.
Search paths: ./config/distributions.yaml β ./distributions.yaml β /etc/apt-proxy/ β ~/.config/apt-proxy/
distributions:
- id: ubuntu
name: Ubuntu
type: 1
url_pattern: "/ubuntu/(.+)$"
benchmark_url: "dists/noble/main/binary-amd64/Release"
geo_mirror_api: "http://mirrors.ubuntu.com/mirrors.txt"
cache_rules:
- pattern: "deb$"
cache_control: "max-age=100000"
rewrite: true
mirrors:
official:
- "mirrors.tuna.tsinghua.edu.cn/ubuntu/"
aliases:
tsinghua: "mirrors.tuna.tsinghua.edu.cn/ubuntu/"
After editing, reload without restart:
kill -HUP $(pgrep apt-proxy)
# or
curl -X POST -H "X-API-Key: $KEY" http://localhost:3142/api/mirrors/refresh
β οΈ Hot reload applies to distributions and mirrors only. Host/port, TLS, and API key require a full restart.
Caching third-party APT repositories
Any HTTP-based APT repository can be proxied and cached. Examples β Docker CE and Proxmox VE:
distributions:
- id: docker-debian
name: Docker CE (Debian)
type: 1
url_pattern: "/linux/debian/(.+)$"
benchmark_url: "dists/bookworm/stable/binary-amd64/Release"
cache_rules:
- pattern: "\\.deb$"
cache_control: "max-age=100000"
rewrite: true
mirrors:
official:
- "download.docker.com/linux/debian/"
- id: proxmox-ve
name: Proxmox VE
type: 1
url_pattern: "/debian/pve/(.+)$"
benchmark_url: "dists/bookworm/pve-no-subscription/binary-amd64/Release"
cache_rules:
- pattern: "\\.deb$"
cache_control: "max-age=100000"
rewrite: true
mirrors:
official:
- "download.proxmox.com/debian/pve/"
Point sources.list at the proxy:
deb http://your-proxy:3142/linux/debian bookworm stable
deb http://your-proxy:3142/debian/pve bookworm pve-no-subscription
The same approach works for any APT-based repo: Grafana, Kubernetes, HashiCorp, etc.
π‘ If you only need custom repositories and want to disable Ubuntu/Debian/CentOS/Alpine entirely, use --disable-builtin-distros (or APT_PROXY_DISABLE_BUILTIN_DISTROS=true).
π³ Docker
docker run -d \
--name apt-proxy \
-p 3142:3142 \
-v apt-proxy-cache:/app/.aptcache \
tuzelko/apt-proxy
# Use inside another container
http_proxy=http://host.docker.internal:3142 apt-get install -y vim
See example/ for Docker Compose configurations.
Image tags: latest, 0, 0.11, 0.11.0 β all multi-arch (amd64, arm64, armv7).
π API
Public: GET /healthz, /livez, /readyz, /version, /metrics (Prometheus).
Protected (require X-API-Key header or Authorization: Bearer <key>):
| Method |
Path |
Description |
| GET |
/api/cache/stats |
Size, hit rate, item count |
| POST |
/api/cache/purge |
Clear all cached items |
| POST |
/api/cache/cleanup |
Remove stale entries |
| POST |
/api/mirrors/refresh |
Reload distributions + re-benchmark |
curl -H "X-API-Key: your-key" http://localhost:3142/api/cache/stats
π Observability
The /metrics endpoint exposes Prometheus metrics:
| Metric |
Description |
apt_proxy_cache_* |
Hits, misses, size, item count, evictions |
apt_proxy_cache_upstream_* |
Upstream request duration and error rate |
apt_proxy_cache_request_duration_seconds |
Request latency by distro and cache status |
Health endpoints (/healthz, /readyz) are suitable for Kubernetes probes.
π Architecture
Client β apt-proxy β Cache hit β Client
β Cache miss β upstream mirror β Cache β Client
- URL rewriting β rewrites request URLs to the target mirror; no transparent forwarding
- Async benchmarking β mirrors benchmarked in background on startup (24h TTL); proxy serves immediately and upgrades once done
- Dynamic distributions β add any distro via
distributions.yaml without code changes
- Retryable transport β 3 retries, exponential backoff (100ms initial, 2Γ multiplier, 2s max)
- LRU eviction β when
cache-max-size is exceeded, least recently used files are evicted first
- State β thread-safe singleton (
sync.Once + sync.RWMutex), updated at startup and on hot reload
π Development
make build # build binary β ./apt-proxy
make test # run tests
make coverage # test + coverage summary
make coverage-html # open coverage report in browser
make vet # go vet
π Troubleshooting
Packages not being cached β verify the proxy URL is reachable from the client and the URL pattern in distributions.yaml matches the repository path.
Slow first download β expected: the first request populates the cache. Subsequent requests are served locally.
Cache growing too large β set --cache-max-size or call POST /api/cache/cleanup.
Debug logging:
./apt-proxy --debug
# or
APT_PROXY_DEBUG=true ./apt-proxy
π License
Apache License 2.0
π Acknowledgements
Maintainer: Eugene Frost Β· Repository: GitHub Β· Registry: Docker Hub
β€οΈ Issues and pull requests are welcome!