Why?

If you’re reading this — you probably already know why you need it. But just to be clear:

Public Cloud

If you’re a compute provider or host virtual machines for customers, you might want to reduce outbound bandwidth usage by caching package downloads.

CI/CD

If your CI pipeline runs non-cached Docker builds, you could benefit from caching APT (Debian) packages — again, saving bandwidth and speeding up builds.

Examples

Used by:

  1. OvH
  2. Hetzner
  3. Smaller vendors

Plan

V " M 2 < c a c a h p e V t d " M 1 < u r p e d s a a p p r t o t e e n s s u p e p o d n a s t e e N G I N X > > P < < < r o x s y t c c o c h a r h c e c e e a c h c c k e i k h n e c m c a i c a h c s a c i h s F c h t e o h e r e N w G a I r r N d e X > i s > > n p C g o a n c r s h e e e q u e s t d e b . d e b > i a n . o r g

Setup

Requirements

  1. Machine running NGINX (can be a container)
  2. Machines for testing (clients pulling APT packages)

Execution

Docker

Download the setup:

📦Docker.zip

nginx.dockerfile

FROM debian:stable-slim
LABEL maintainer="devs.boo"
LABEL description="Debian Caching Mirror via NGINX"
LABEL version="1.0"

RUN apt update
RUN apt install -y nginx

RUN mkdir /var/cache/nginx
RUN chown -R www-data:www-data /var/cache/nginx

ADD nginx.conf /etc/nginx/nginx.conf
ADD *_cache /etc/nginx/sites-enabled/

CMD ["nginx", "-g", "daemon off;"]

nginx.conf

user www-data;
worker_processes auto;
pid /run/nginx.pid;
error_log /var/log/nginx/error.log;
include /etc/nginx/modules-enabled/*.conf;

events {
    worker_connections 2048;
}

http {


    sendfile on;
    tcp_nopush on;
    types_hash_max_size 2048;


    include /etc/nginx/mime.types;
    default_type application/octet-stream;


    ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
    ssl_prefer_server_ciphers on;

    gzip on;

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}

deb_debian_cache

proxy_cache_path /var/cache/nginx/deb_debian_cache levels=1:2 keys_zone=deb_debian_cache:10m max_size=20g inactive=24h use_temp_path=off;

server {
    listen 80;
    server_name deb.debian.local;

    location /debian/ {
        proxy_pass https://deb.debian.org/debian/;
        proxy_set_header Host deb.debian.org;

        proxy_cache deb_debian_cache;
        proxy_cache_valid 200 302 24h;
        proxy_cache_use_stale error timeout updating;
        add_header X-Cache-Status $upstream_cache_status;
    }

    location / {
        add_header Content-Type text/plain;
        return 200 'deb.debian.org cache\n';
    }
}

security_debian_cache

proxy_cache_path /var/cache/nginx/security_debian_cache levels=1:2 keys_zone=security_debian_cache:10m max_size=20g inactive=24h use_temp_path=off;

server {
    listen 80;
    server_name security.debian.local;

    location /debian-security/ {
        proxy_pass https://security.debian.org/debian-security/;
        proxy_set_header Host deb.debian.org;

        proxy_cache security_debian_cache;
        proxy_cache_valid 200 302 24h;
        proxy_cache_use_stale error timeout updating;
        add_header X-Cache-Status $upstream_cache_status;
    }

    location / {
        add_header Content-Type text/plain;
        return 200 'security.debian.org cache\n';
    }
}

Testing

Run this inside a Debian container to test:

docker run --network=host -it debian:stable-slim bash
sed -i "s|debian.org|debian.local|g" /etc/apt/sources.list.d/*
echo "127.0.0.1 deb.debian.local security.debian.local" >> /etc/hosts

Now you can run apt update && apt install ... as usual — and watch your local cache kick in.