How To Host Your Own APT Mirror
In this post I will describe the necessary steps to host your own APT mirror that you can use in your local network to speed up package installations and updates, and save bandwidth.
Requirements
- A Debian server/VM
- See my post about remotely setting up an encrypted Debian server
- This guide might work with Ubuntu as well, although I don’t use it and didn’t test this guide with it.
- About ~750GB of HDD space (more if you want to host multiple architectures and/or more repositories)
Installation
Installing the system itself is outside the scope of this post, you can refer to the post linked above for a guide on installing Debian remotely, you can use a different method if you prefer, as long as you have a functioning system in the end.
Setting up apt-mirror
After you installed Debian and did the initial hardening/configuration according to your needs, you can start with installing the dependencies.
- Install
apt-mirror
:apt install apt-mirror apt-transport-https ca-certificates
- Configure
apt-mirror
:- Open the configuration file
/etc/apt/mirror.list
using your favorite editor and paste the following:############# config ################## ## This option sets the base path for apt-mirror to use. set base_path /var/apt-mirror ## The options below allow you to change the locations ## that are usually located in the base_path. # set mirror_path $base_path/mirror # set skel_path $base_path/skel # set var_path $base_path/var # set cleanscript $var_path/clean.sh ## You can change the default architecture using this option. # set defaultarch <running host architecture> ## You can use the options below to run a script ## after the mirroring finished. # set postmirror_script $var_path/postmirror.sh # set run_postmirror 0 ## The number of threads to use for downloading packages. set nthreads 8 ## Packages with a tilde (~) in their version are pre-release, ## we don't want them in the mirror. set _tilde 0 ############# end config ############## ## # Debian v12 Bookworm ## # Debian Bookworm deb https://deb.debian.org/debian bookworm main contrib non-free non-free-firmware deb-src https://deb.debian.org/debian bookworm main contrib non-free non-free-firmware deb-amd64 https://deb.debian.org/debian bookworm main contrib non-free non-free-firmware # deb-arm64 https://deb.debian.org/debian bookworm main contrib non-free non-free-firmware # Debian Bookworm Updates deb https://deb.debian.org/debian bookworm-updates main contrib non-free non-free-firmware deb-src https://deb.debian.org/debian bookworm-updates main contrib non-free non-free-firmware deb-amd64 https://deb.debian.org/debian bookworm-updates main contrib non-free non-free-firmware # deb-arm64 https://deb.debian.org/debian bookworm-updates main contrib non-free non-free-firmware # Debian Bookworm Backports deb https://deb.debian.org/debian bookworm-backports main contrib non-free non-free-firmware deb-src https://deb.debian.org/debian bookworm-backports main contrib non-free non-free-firmware deb-amd64 https://deb.debian.org/debian bookworm-backports main contrib non-free non-free-firmware # deb-arm64 https://deb.debian.org/debian bookworm-backports main contrib non-free non-free-firmware # Debian Bookworm Security deb https://deb.debian.org/debian-security bookworm-security main contrib non-free non-free-firmware deb-src https://deb.debian.org/debian-security bookworm-security main contrib non-free non-free-firmware deb-amd64 https://deb.debian.org/debian-security bookworm-security main contrib non-free non-free-firmware # deb-arm64 https://deb.debian.org/debian-security bookworm-security main contrib non-free non-free-firmware ## # Other Stuff ## # Clean Scripts clean https://deb.debian.org/debian-security
- Make sure to update the configuration according to your needs, especially the
base_path
andnthreads
options, in case you want/need to use a different storage path or more threads to sync the mirror. - In case you want to also mirror
arm64
packages, you can uncomment thedeb-arm64
statements in the repo list.
- Open the configuration file
- Add a CRON Job for the mirroring:
- Use
crontab -e
to open the crontab editor using your favorite editor - Add:
0 1 * * * /usr/bin/apt-mirror > /var/log/apt-mirror.log
- This will run every day at 1:00, you can of course change this as you want.
- Use
- Run the first mirroring (manually)
- I’d recommend using screen for this (or any other similar tool you prefer):
screen -S first-mirror
- Run
apt-mirror
and wait until the execution finishes
- I’d recommend using screen for this (or any other similar tool you prefer):
Regarding HTTPS
There are ongoing discussions on various websites about whether APT should use HTTPS/TLS by default (currently, it does not). I used HTTPS URLs for the mirror in this guide to provide a secure default, but the webserver of the mirror itself (which is assumed to run in the local network) is running with HTTP in order to keep the guide simple. You can find some examples of configuring NGINX for TLS on this blog (for example you could search for 443 to find config examples).
Setting up NGINX
Now that the mirror content is synced, you need a way to fetch the mirrored content from your server.
NGINX will be used in this guide together with the fancyindex
module in order to render nice looking indexes.
- Install NGINX:
apt install nginx libnginx-mod-http-fancyindex
- Configure NGINX
- Open the default config at
/etc/nginx/sites-enabled/default
using your favorite editor - Paste the following:
server { listen 80 default_server; server_name _; access_log /var/log/nginx/mirror.access.log; error_log /var/log/nginx/mirror.error.log; server_name_in_redirect off; autoindex off; server_tokens off; root /var/www/html; location /debian { alias /var/apt-mirror/mirror/deb.debian.org/debian; fancyindex on; fancyindex_exact_size off; fancyindex_header /head.html; fancyindex_footer /foot.html; } location /debian-security { alias /var/apt-mirror/mirror/deb.debian.org/debian-security; fancyindex on; fancyindex_exact_size off; fancyindex_header /head.html; fancyindex_footer /foot.html; } error_page 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 421 422 423 424 425 426 428 429 431 451 500 501 502 503 504 505 506 507 508 510 511 /error.html; location /error.html { root /var/www/html; internal; } }
- Don’t forget to update the paths of the
alias
params in case you changed the path in theapt-mirror
config
- Open the default config at
- Add the HTML files (I’ll provide unstyled examples):
- Add
/var/www/html/index.html
(replaceMIRROR_DOMAIN
with the actual DNS name (or IP(?)) of the mirror:<!DOCTYPE html> <html lang="en"> <head> <title>APT Mirror</title> </head> <body> <h1>APT Mirror</h1> <p>This is an APT mirror.</p> <h2>Currently hosting:</h2> <ul> <li> <a href="/debian">/debian</a> <ul> <li>bookworm</li> <li>bookworm-updates</li> <li>bookworm-backports</li> </ul> </li> <li> <a href="/debian-security">/debian-security</a> <ul> <li>bookworm-security</li> </ul> </li> </ul> <h2>Usage</h2> <p>Select the repos you need and add them to your <code>/etc/apt/sources.list</code>:</p> <details> <summary>Debian v12 (bookworm)</summary> <pre> # Debian Bookworm deb http://MIRROR_DOMAIN/debian bookworm main contrib non-free non-free-firmware deb-src http://MIRROR_DOMAIN/debian bookworm main contrib non-free non-free-firmware # Debian Bookworm Updates deb http://MIRROR_DOMAIN/debian bookworm-updates main contrib non-free non-free-firmware deb-src http://MIRROR_DOMAIN/debian bookworm-updates main contrib non-free non-free-firmware # Debian Bookworm Security deb http://MIRROR_DOMAIN/debian-security bookworm-security main contrib non-free non-free-firmware deb-src http://MIRROR_DOMAIN/debian-security bookworm-security main contrib non-free non-free-firmware # Debian Bookworm Backports deb http://MIRROR_DOMAIN/debian bookworm-backports main deb-src http://MIRROR_DOMAIN/debian bookworm-backports main </pre> </details> </body> </html>
- Add
/var/www/html/error.html
:<!DOCTYPE html> <html lang="en"> <head> <title>APT Mirror</title> </head> <body> <h1>Error!</h1> <p class="lead">An error occurred.</p> <p><a href="/">Main Page</a> </body> </html>
- Add
/var/www/html/head.html
:<html lang="en"> <head> <title>APT Mirror</title> </head> <body> <h1>APT Mirror</h1> <p>Welcome to the APT Mirror.</p> <h1>
- This gets cut off at the open
<h1>
because thefancyindex
module will render the title of the folder it’s showing after that and close it.
- This gets cut off at the open
- Add
/var/www/html/foot.html
:<hr /> <p>Thanks for using the APT Mirror.</p> </body> </html>
- Remove
/var/www/html/index.nginx-debian.html
in case it exists - Ensure the files are not world-writable and belong to either root or www-data
- Add
- Confirm that the NGINX config is valid by running:
nginx -t
- Restart NGINX:
systemctl restart nginx
You should now be able to open http://MIRROR_DOMAIN/
(changed to your actual DNS name) in a browser and also view the repo contents.
I added example usage instructions into the example index.html
, so you can copy the example sources.list
contents from there.
The next step would be adding styles to the mirror pages so it looks better, and of course add more/different repos/architectures in case you need them.
I hope this post was useful. If you have any suggestions or found errors please let me know!