... and OpenWrt, in a way that requires no specific modification of clients.
Squid: squid-cache.org
How to
-
On clients in
/etc/zypp/repos.d/*.repo
change allhttps
tohttp
. (It's safe to do, because all packages are signed by repo key.) -
On OpenWrt install
bash
,curl
,squid
andluci-app-squid
and attach some external disk for extra space. Alternatively you can install Squid on any other machine in your network. -
Add to
squid.conf
:maximum_object_size 1024 MB cache_dir aufs /mnt/data/squid <CACHE_SIZE> 16 256 refresh_pattern \.rpm$ 10080 90% 43200 http_port 3129 intercept url_rewrite_program /path/to/redirect.sh
For
<CACHE_SIZE>
seecache_dir
documentation. -
redirect.sh
:#!/bin/bash doo_regex='^http://download.opensuse.org/' while read -r url extras; do if [[ "$url" =~ $doo_regex ]]; then location="$(curl -s --head "$url" \ | grep -E "^Location: " \ | sed -e 's/^Location: \(.*\)\r$/\1/' \ -e 's/^https:/http:/')" if [[ -n "$location" ]]; then echo "OK url=\"${location}\"" else echo "ERR" fi else echo "ERR" fi done
-
Configure OpenWrt port forwarding:
This will redirect all outgoing http connections to Squid intercepting socket.
/etc/config/firewall
:config redirect list proto 'tcp' option name 'squid' option target 'DNAT' option src 'lan' option src_dport '80' option dest 'lan' option dest_ip '192.168.1.1' option dest_port '3129'
Change
dest_ip
if you have installed Squid on different host.
Backstory
My internet connection over LTE and with monthly transfer limits forced me to optimize my downloads. I have two computers running openSUSE Tumbleweed, which as a rolling release distro has a lot of updates. Downloading them twice is an obvious waste of resources.
But one of those computers is my laptop, which is not always in my home network. So I wanted to have something, that requires no specific configuration on client side. Bonus points for running 100% on my router with OpenWrt.
First I found this guide:
https://wiki.jessen.ch/index/How_to_cache_openSUSE_repositories_with_Squid
It's quite complicated due to parsing the list of mirrors and generating config for url rewriter. But it was a good starting point.
openSUSE's primary download server download.opensuse.org is an instance of MirrorBrain. It's not hosting any data, but it redirects client to a nearest mirror. In practice it looks like this:
$ curl -s --head http://download.opensuse.org/[...]/some.rpm
HTTP/1.1 302 Found
Date: Wed, 17 Mar 2021 21:24:05 GMT
Server: Apache/2.4.43 (Linux/SUSE)
X-MirrorBrain-Mirror: ftp.gwdg.de
X-MirrorBrain-Realm: other_country
Link: <http://download.opensuse.org/[...]/some.rpm.meta4>; rel=describedby; type="application/metalink4+xml"
Link: <https://ftp.gwdg.de/pub/opensuse/[...]/some.rpm>; rel=duplicate; pri=1; geo=de
Link: <http://widehat.opensuse.org/[...]/some.rpm>; rel=duplicate; pri=2; geo=de
Link: <http://mirror.karneval.cz/pub/linux/opensuse/[...]/some.rpm>; rel=duplicate; pri=3; geo=cz
Link: <http://ftp.lysator.liu.se/pub/opensuse/[...]/some.rpm>; rel=duplicate; pri=4; geo=se
Link: <http://mirror.tspu.ru/opensuse/[...]/some.rpm>; rel=duplicate; pri=5; geo=ru
Location: https://ftp.gwdg.de/pub/opensuse/[...]/some.rpm
Content-Type: text/html; charset=iso-8859-1
The HTTP redirect points to url in Location
line, but there are also
additional Link
urls. They are used by zypper to connect and download parts of
a package from multiple mirrors at the same time.
Unfortunately Squid cannot cache such partial downloads. To remove those
additional urls, the redirect.sh
script gets the Location
from upstream
server and tells Squid to send its own redirect response.
And that's it! The only thing that could "break" caching is download server
returning different Location
for every request. But so far I haven't seen it
do this.