Skip to content

Instantly share code, notes, and snippets.

@stueja
Last active May 5, 2021 15:53
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stueja/17ac61d542065549567ce6782bbdd525 to your computer and use it in GitHub Desktop.
Save stueja/17ac61d542065549567ce6782bbdd525 to your computer and use it in GitHub Desktop.
Arch Linux local pacman share via NFS

local Arch Linux pacman package cache

I was wondering whether it was possible to share downloaded Arch Linux packages in my home network, so that not every of my 5 hosts downloads from the mirrors. Advantages: saves bandwidth, no package duplicates, faster "download" of packages which are already the package cache to the client. (Note that pacman will actually not download packages which are already in the package cache).

Working principle

The CacheDir directive in /etc/pacman.conf holds the path to the (original) pacman package cache. Default /var/cache/pacman/pkg/. Sharing the package cache path over NFS, mounting it on the clients, and defining the NFS path in the client's /etc/pacman.conf should cater for a central pacman package cache.

The CacheDir directive can be used more than once, so should the central pacman package cache be down, or should the client not be connected to the Local Area Network during a pacman -Syu, the updated packages will be downloaded to the second CacheDir.

Since I have an always-on server in my LAN, I will use this server to share a central pacman package cache.

Steps

  1. on the server: create a directory for the pacman package cache

    I could use the original /var/cache/pacman/pkg/, but I decided to use a directory on an HDD drive rather than the system SSD.

  2. on the server: share the directory; in my case: via NFS; SMB/CIFS or sshfs should probably also work

  3. on the server: tell pacman to use the new directory as CacheDir.

  4. on the clients: mount the NFS share, in my case using /etc/fstab (but you could use

    systemd mount units or manual mounts or shell scripts or... or...)

  5. on the clients: tell pacman to use the NFS share as CacheDir, and the original path as secondary CacheDir

Detailed Steps:

On the server:

  1. create a directory for the pacman package cache

    mkdir -p /media/data/var/cache/pacman/pkg

  2. share the directory in /etc/exports, add the line

    /media/data/var/cache/pacman/pkg   192.168.1.0/24(fsid=1,crossmnt,rw,async,no_root_squash,no_subtree_check,insecure)
    

    use no_root_squash, because pacman, as root, has to be able to write to that directory

    run exportfs -rav

  3. tell pacman to use the new directory as CacheDir

    in /etc/pacman.conf, add the line

    CacheDir=/media/data/var/cache/pacman/pkg

    on top of

    CacheDir=/var/cache/pacman/pkg

On the client:

  1. mount the NFS share

    create the mountpoint: sudo mkdir -p /mnt/pkgcache

    in /etc/fstab, add a line

    192.168.1.1:/media/data/var/cache/pacman/pkg      /mnt/pkgcache   nfs noauto,nofail,x-systemd.automount,x-systemd.device-timeout=30,_netdev 0 0
    

    reboot, use sudo mount -a or sudo mount /mnt/pkgcache

  2. tell pacman to use the NFS share as CacheDir, and the original path as secondary

    in /etc/pacman.conf, add the line

    CacheDir=/mnt/pkgcache

    on top of

    CacheDir=/var/cache/pacman/pkg

    Note: this does not work as expected. If /mnt/pkgcache is unreachable, for example because of working abroad, pacman will stall. Current workaround to this problem: /usr/local/bin/update.sh which determines the IP address, and uses a different /etc/pacman*.conf if the local area network is not reachable.

Test

    [jan@md1qk4sc ~]$ checkupdates
    electrum 3.3.4-1 -> 3.3.4-2
    [jan@md1qk4sc ~]$ ll /mnt/pkgcache/electrum*
    -rw-r--r-- 1 root root 3,1M  1. Mär 22:38 /mnt/pkgcache/electrum-3.3.4-1-any.pkg.tar.xz
    [jan@md1qk4sc ~]$ sudo pacman -Syu
    [sudo] password for jan: 
    :: Synchronizing package databases...
     core is up to date
     extra is up to date
     community                                                       4,9 MiB  5,49M/s 00:01 [###################################################] 100%
     multilib is up to date
    :: Starting full system upgrade...
    warning: zeitgeist: local (1.0+1+g1bcc8585-2) is newer than extra (1.0.1-1)
    resolving dependencies...
    looking for conflicting packages...

    Packages (1) electrum-3.3.4-2

    Total Download Size:   3,04 MiB
    Total Installed Size:  9,08 MiB
    Net Upgrade Size:      0,00 MiB

    :: Proceed with installation? [Y/n] y
    :: Retrieving packages...
     electrum-3.3.4-2-any                                            3,0 MiB  5,15M/s 00:01 [###################################################] 100%
    (1/1) checking keys in keyring                                                          [###################################################] 100%
    (1/1) checking package integrity                                                        [###################################################] 100%
    (1/1) loading package files                                                             [###################################################] 100%
    (1/1) checking for file conflicts                                                       [###################################################] 100%
    (1/1) checking available disk space                                                     [###################################################] 100%
    :: Processing package changes...
    (1/1) upgrading electrum                                                                [###################################################] 100%
    New optional dependencies for electrum
        python-hidapi: Digital Bitbox hardware wallet support
        python-pycryptodomex: use PyCryptodome AES implementation instead of pyaes [installed]
        python-qdarkstyle: optional dark theme in graphical mode
        python-rpyc: send commands to Electrum Python console from an external script
    :: Running post-transaction hooks...
    (1/2) Arming ConditionNeedsUpdate...
    (2/2) Updating the desktop file MIME type cache...
    [jan@md1qk4sc ~]$ ll /mnt/pkgcache/electrum*
    -rw-r--r-- 1 root root 3,1M  1. Mär 22:38 /mnt/pkgcache/electrum-3.3.4-1-any.pkg.tar.xz
    -rw-r--r-- 1 root root 3,1M  7. Mär 18:03 /mnt/pkgcache/electrum-3.3.4-2-any.pkg.tar.xz
    [jan@md1qk4sc ~]$ 

Files to work around the cache-unreachable problem

/usr/local/bin/update.sh

#!/bin/bash
 
inetint=wlp2s0
ipaddress=$(ip -4 -o addr show dev $inetint | awk '{split($4,a,"/");print a[1]}')
configpath=/etc
 
echo "IP address is $ipaddress"
 
if [[ $ipaddress != 192.168.0.* ]]
then
	configfile=pacman-remote.conf
else
	configfile=pacman-local.conf
fi
 
echo "using config $configfile"
 
pacman --config=$configpath/$configfile -Syu

/etc/pacman-local.conf

# pacman-local.conf
[options]
# set CacheDir to NFS share
CacheDir = /mnt/pkgcache/
# include remaining configuration items
Include = /etc/pacman-include.conf

/etc/pacman-remote.conf

#pacman-remote.conf
[options]
# set CacheDir to local ssd
CacheDir = /var/cache/pacman/pkg/
# include remaining configuration items
Include = /etc/pacman-include.conf

/etc/pacman-include.conf

# pacman-include.conf
#
# /etc/pacman.conf
#
# See the pacman.conf(5) manpage for option and repository directives
 
#
# GENERAL OPTIONS
#
[options]
# The following paths are commented out with their default values listed.
# If you wish to use different paths, uncomment and update the paths.
#RootDir     = /
#DBPath      = /var/lib/pacman/
 
# commented out, CacheDir set in pacman-remote.conf / pacman-local.conf
#CacheDir    = /mnt/pkgcache/
#CacheDir    = /var/cache/pacman/pkg/
#LogFile     = /var/log/pacman.log
#GPGDir      = /etc/pacman.d/gnupg/
#HookDir     = /etc/pacman.d/hooks/
HoldPkg     = pacman glibc
#XferCommand = /usr/bin/curl -C - -f %u > %o
#XferCommand = /usr/bin/wget --passive-ftp -c -O %o %u
#CleanMethod = KeepInstalled
#UseDelta    = 0.7
Architecture = auto
 
# Pacman won't upgrade packages listed in IgnorePkg and members of IgnoreGroup
#IgnorePkg   =
#IgnoreGroup =
 
#NoUpgrade   =
#NoExtract   =
 
# Misc options
#UseSyslog
#Color
#TotalDownload
CheckSpace
#VerbosePkgLists
 
# By default, pacman accepts packages signed by keys that its local keyring
# trusts (see pacman-key and its man page), as well as unsigned packages.
SigLevel = Required DatabaseOptional
LocalFileSigLevel = Optional
#RemoteFileSigLevel = Required
 
# NOTE: You must run `pacman-key --init` before first using pacman; the local
# keyring can then be populated with the keys of all official Arch Linux
# packagers with `pacman-key --populate archlinux`.
 
#
# REPOSITORIES
#   - can be defined here or included from another file
#   - pacman will search repositories in the order defined here
#   - local/custom mirrors can be added here or in separate files
#   - repositories listed first will take precedence when packages
#     have identical names, regardless of version number
#   - URLs will have $repo replaced by the name of the current repo
#   - URLs will have $arch replaced by the name of the architecture
#
# Repository entries are of the format:
#       [repo-name]
#       Server = ServerName
#       Include = IncludePath
#
# The header [repo-name] is crucial - it must be present and
# uncommented to enable the repo.
#
 
# The testing repositories are disabled by default. To enable, uncomment the
# repo name header and Include lines. You can add preferred servers immediately
# after the header, and they will be used before the default mirrors.
 
#[testing]
#Include = /etc/pacman.d/mirrorlist
 
[core]
Include = /etc/pacman.d/mirrorlist
 
[extra]
Include = /etc/pacman.d/mirrorlist
 
#[community-testing]
#Include = /etc/pacman.d/mirrorlist
 
[community]
Include = /etc/pacman.d/mirrorlist
 
# If you want to run 32 bit applications on your x86_64 system,
# enable the multilib repositories as required here.
 
#[multilib-testing]
#Include = /etc/pacman.d/mirrorlist
 
[multilib]
Include = /etc/pacman.d/mirrorlist
 
# An example of a custom package repository.  See the pacman manpage for
# tips on creating your own repositories.
#[custom]
#SigLevel = Optional TrustAll
#Server = file:///home/custompkgs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment