While developing my Arch VM script, I had to go through the installation over and over to test every change.

I am tethered to my phone for Internet connectivity, and the quality and speeds are… How should I put it? Underwhelming to say the least (I live in a mountainous rural area).

So while doing so, I grew increasingly wary of the long wait for packages to download and the 287 MB worth (gah!) of data it would chip off my 40 GB plan each and every time. What I needed was a way to provide a local package cache to pacman.

Amazingly, but certainly not surprisingly, there is a great article on the Arch wiki for that.

However, due to my target file system being exFAT (cough ventoy shenanigans, cough) and some file names containing the forbidden : character, this solution didn’t work for me.

Also because I am using GNOME Boxes, sharing a folder with the host was out of the equation as that entails installing some SPICE-related packages which pull in an entire graphical stack as dependencies, hence defeating the purpose.

Setting up SSH access to the guest requires quite some fiddling, and anyway it wasn’t immediately clear to me how I would instruct pacstrap to tap into the network cache, or it would have likely required some modifications to the live pacman.conf and I wanted to avoid all that complexity1.

Remastering the ISO was another option that I left out because I wanted the script to work with a vanilla install. No, what I was really looking for was something of the utmost simplicity2.

What I finally came up with, and not to toot my own horn but I think it is pretty darn brillant (considering I haven’t seen it mentioned anywhere online when I researched the topic3), is a bind mounted squashfs4 package cache placed on an external medium like a USB flash drive. This in turn can easily be shared in GNOME Boxes even without the SPICE packages installed in the guest!

Here is a rundown of the process:

  • create a SquashFS archive of /var/cache/pacman/pkg on a system containing the desired package set (I reused a just-installed VM to match its exact minimal set but you can go wild and copy everything from your main rig, that’ll give you a larger cache):

    mksquashfs /var/cache/pacman/pkg/ pkg.sqsh \
        -comp zstd \
        -no-exports \
        -progress \
        -mem 1G \
        -not-reproducible
    
  • copy the SquashFS file on the external medium you will mount during the install

  • boot into the Arch Live environment and create two directories, one for your external medium and one for the archive:

    mkdir /tmp/{usb,squash}
    

Note

Do not use /mnt if you plan to use it as the installation mount point.
  • mount the external medium containing the squash file and then the squash file itself:

    mount /dev/XXXY /tmp/usb
    mount /tmp/usb/pkg.sqsh /tmp/squash
    
  • finally, and that’s what’s doing the trick for pacstrap, bind-mount /tmp/squash on archiso’s /var/cache/pacman/pkg:

    mount --bind /tmp/squash /var/cache/pacman/pkg
    

That’s it, now you just have to add -c to your pacstrap invocation:

pacstrap -c /mnt base linux [...]

Downloads will be skipped (as long as package versions in the squashfs archive are not older than the synced databases’ ones), and now you can carry on with your installation, contented by the blissful release of not having to suffer through the hell of this perpetual cycle of reincar… Err I mean wasteful downloading of already acquired packages 😊️

Happy hacking!


  1. Just as I was bringing the finishing touches to this article, I realized my blunder: what I needed was an access from the guest to the host, not the contrary. This would allow me to do something like an SSHFS mount or even serving the cache via a simple web server. Follow-up article to come on how easy it actually is to connect from a guest to the host in GNOME Boxes 😁️ ↩︎

  2. Yeah, no seriously, in my use case that was the web server/SSHFS mount. But let’s just say this article was actually meant to be for a fully offline install… 😂️ ↩︎

  3. I’ll admit this may only be due to my constraints being ridiculously specific, but maybe for once I can dream of having come up with a truly original solution, wouldn’t you agree ? 😀️ ↩︎

  4. The idea of using SquashFS instead of a more common loop-mounted filesystem-in-a-file is what I felt was the real feat of ingeniosity here. And yes, I need to pat myself on the back from time to time, is it something wrong? 😉️ ↩︎