My arch repositories

I keep several Arch Linux repositories on svasey.org. This page documents their organization and how to use them.

Organization

I publish only two repositories: the public one and the private one. The private repository is accessible only to neo2, neo and tank, whereas the public one is accessible without restrictions via HTTP.

The name of the public repository is svasey-public, the private one is svasey-private.

Generally, my repository names are always prefixed by "svasey-".

All my repositories are hosted on repo.svasey.org . To access the public repository, one must go through the public-repo.svasey.org record .

Each repository is a directory organized as follows:

repository/
    os/
        i686/
            package1.pkg.tar.gz
            package2.pkg.tar.gz
            repodb.db.tar.gz
        x86_64/
            package3.pkg.tar.gz
            package4.pkg.tar.gz
            repodb.tar.gz
src/
    basename1.tar.gz
    basename2.tar.gz

The os directory contains the binary packages, whereas src contains the source tarballs that are named using the package name without any version number. For example, if a binary package file is named urpkg-1.9-1-i686.pkg.tar.gz, the source file will be named urpkg.tar.gz.

If a package is intended to be the same in several repositories, it is linked using hard links (not symlinks, as this causes problems when accessing via sftp).

Directory hierarchy of repo.svasey.org

Everything is stored in /home/archrepo .

Each repository has its own home directory in there. The hierarchy is as follows:

/home/archrepo/$reponame/
    .ssh/
        authorized_keys
    repo/
        os/
            ...
    src/
        ...

Special users and groups, permissions

Important groups are all-repo and archrepo. Any user that wants read access to /home/archrepo should be a member of archrepo, whereas only repository users should be members of all-repo (this group is only used in the sshd_config file to match repository users, see below).

There is a manager user repo-manager, which should be used for any package adding or removal. It is the only user to have write rights over the hierarchy. It is a member of archrepo and all the repository groups (svasey-public, svasey-private etc.).

There is one user for each repository. They only have read access to their respective repository. Their name is the same as the name of the repository, e.g at the moment there is svasey-private and svasey-public . The hierarchy permissions should be set as follows

  • /home/archrepo should be root:archrepo 750 (root must be used, since it must own all the components of the path where sshd chroots us).
  • /home/archrepo/$reponame should be root:$reponame 755
  • /home/archrepo/$reponame/.ssh should be $reponame:$reponame 700
  • /home/archrepo/$reponame/.ssh/authorized_keys should be $reponame:$reponame 600
  • /home/archrepo/$reponame/repo should be root:$reponame 750
  • /home/archrepo/$reponame/repo/os should be repo-manager:$reponame 750
  • /home/archrepo/$reponame/repo/src should be repo-manager:$reponame 750
  • /home/archrepo/$reponame/repo/src/*.tar.gz should be repo-manager:archrepo 640
  • /home/archrepo/$reponame/repo/os/$arch should all be repo-manager:$reponame 750`
  • /home/archrepo/$reponame/repo/os/$arch/package1.pkg.tar.gz should be repo-manager:archrepo 640
  • /home/archrepo/$reponame/repo/os/$arch/repodb.db.tar.gz should be repo-manager:$reponame 640

The manager user has a home in /home/repo-manager. This home could contain a .ssh/authorized_keys file for automated package publishing.

Any repositories should be accessible by sftp for those having the rights to. Here is the essential part of sshd_config allowing this:

Subsystem sftp internal-sftp

Match Group all-repo
    ChrootDirectory /home/archrepo/%u/repo
    ForceCommand internal-sftp

If you want to give access to some remote user, add its ssh key to /home/archrepo/$reponame/.ssh/authorized_keys (in the archrepo-config package).

Read access to a given repository $reponame for a local user is allowed by adding it to the $reponame group. For example, since I wanted the public repository to be accessible via HTTP, I added http to the svasey-public group.

Packaging guidelines for svasey packages

Pretty much any kind of files are allowed, for any path. It is advised to keep configuration packages and software packages separated, i.e one package should contain softwares for a given task, and another the necessary configuration files. That is to easily enable one to be public, while the other stays private...

If some configuration package is specific to a given machine, there should not be any $pkgname-config package; instead, one should name the packages $pkgname-config-$machinename . See the darwrap-config package to see an example of how this is done in practice.

Confidential data like passwords should never be in a package; instead, configuration files containing passwords should be marked as so in the PKGBUILD using the backup array, and the user should be reminded to put his password in the files after the package installation. See the mailsystem-config package for an example.

Accessing the public svasey arch repository

The public repository access is setup with a little trick:

/home/www/sites/svasey.org/sub/public-repo/pages is set to point to /home/archrepo/svasey-public/repo

This way the public repository is part of the HTTP hierarchy. Of course, the http user has to be in the svasey-public and archrepo groups otherwise, it would not work.

To add this repo to pacman, add:

[svasey-public]
Server = http://public-repo.svasey.org/os/i686

to /etc/pacman.conf

Creating and removing a repository

To create a repository named $reponame, run:

$ repocreate $reponame

This will create an empty repository, with nobody allowed to access it. To update its list of SSH keys (authorized_keys), run:

$ repokey-update $reponame $keyfile

This will add the keys in $keyfile to those having read-access to the repository. To remove access to keys, just use the --remove flag.

To remove a repository $reponame, run:

$ reporemove $reponame

This will remove all the files that were in the repository !

Publishing a package: the direct way

The simple way is to use addpkg, from repoutils. It takes at least three arguments: the binary package file, the tarball source, and the name of the repository, e.g:

$ addpkg your_package.pkg.tar.gz your_package.tar.gz svasey-public

You can always associate several binary package file to a single source. For example, the following command is okay:

$ addpkg package-i686.pkg.tar.gz package-x86_64.pkg.tar.gz package.tar.gz \
     svasey-public

Note that by default, addpkg expects to also find detached signatures of your package and tarballs. This means that for each file named $name that you give on the command line, a file ${name}.sig should exist and contain a GPG detached signature of the file. If you do not want to provide signatures, use the --no-sign option.

Also note that if the repository name is of the form ${base}-public, then the package is first published to ${base}-private, and then a link is made to the public repository.

On tank, repo-manager can execute addpkg via sudo without entering a password. This is useful if you want to automate the publication of your packages.

Publishing a package: the automated way

The building and publishing process can quickly become time-consumming and boring. To automate it, I use publishpkg, from repoutils. At the root of all my software's source directory, there is a dist/arch directory. The directory contains:

  • The PKGBUILD files
  • Optionaly, the .install script
  • Optionaly, a configuration file publish.conf

There can be multiple PKGUILD. For example, you might want to have a different one depending on the host for which you are building the package. In that case, just name them PKGBUILD.$host1 and PKGBUILD.$host2, where $host1 and $host2 are the hostnames of your two hosts.

Building directly

If you only want to build a package, cd to where you want to build it, and run makeprivpkg /path/to/your/srcdir. Different files will be created:

  • A package file, with extension .pkg.tar.gz
  • A source tarball file, with extension .tar.gz
  • Your PKGBUILD and .install files that were in dist/arch.

You can then go on an publish or install your package. However, this is not a very automated method of doing things.

Building and installing/publishing

The publishpkg script can be used to really automate the whole process.

Remote configuration

Of course, it cannot work magically, you will have to do some configuration first. What you have to do is allow your machine to access the remote repository server, and also allow it to access the remote hosts on which you want to build the package.

Configuration for publishing

For the remaining part of those instructions, I assume the address of your repository server is repo.example.com. The idea you want to implement is to access via SSH using the repo-manager user of the repository server. To do this, first generate a ssh keypair:

$ ssh-keygen -t rsa -b 4096

Copy the resulting id_rsa and id_rsa.pub in the /etc/repoutils-config/repo-manager@repo.example.com/ directory (which you should create if it doesn't exist).

Then create a /etc/repoutils-config/repo-manager@repo.example.com/ssh_config file with a content similar to:

HostName repo.example.com
User repo-manager
Port 22
UserKnownHostsFile /etc/repoutils-config/repo-manager@repo.example.com/known_hosts
StrictHostKeyChecking yes
Compression yes
ConnectionAttempts 3
IdentityFile /etc/repoutils-config/repo-manager@repo.example.com/id_rsa
PasswordAuthentication no
PubKeyAuthentication yes

You should also create a known_hosts file containing the fingerprints of repo.example.com.

On your repository server, configure repo-manager to have sudo rights to launch addpkg, and add the id_rsa.pub file you generated previously to /home/repo-manager/.ssh/authorized_keys.

Configuration for building

The building configuration is very similar to the publishing configuration. The only difference is that a repo-builder user is used. It should be created on the host on which you want to build. The rest of the configuration is exactly as above (with the usernames changed of course).

Invocation

Now that everything is configured. You are ready to launch publishpkg. It takes one or more arguments:

  • The first argument should be the source directory of your software. It defaults to the current directory.
  • The following arguments should be name of repositories to which you want to publish, as they should be given to addpkg. If you use --no-publish, this is not necessary. Otherwise, at least one repository is required.

By default, it will build a package for the local host and publish it on the given repositories. You can give it several options:

  • --no-local: use this if you do not want to build a packge for the local host.
  • --no-remote: use this if you want to build a package only for the local host.
  • --repo-server: give the address of the server on which your repositories are. For me, that would be repo.svasey.org. This option should either be specified on the command line, or in an environment variable: PUBLISHPKG_SERVER.
  • --sign-key: give the GPG key id to use to sign the published package and its source tarball. If this is not given, this is assumed to be the environment variable PUBLISHPKG_SIGNKEY.
  • --no-sign: Use this if you do not want to sign the package or the tarball.
  • --host: add a host to the list of hosts for which to build a package. This can of course be given multiple times
  • --install: Specify this if you also want to install the package on the hosts for which it is built
  • --no-publish: Specify this if you do not want to publish your package, just build and install it. This implies --install.

Note that if you want to publish (i.e you did not use --no-publish), you must give the program your repository server, either via --repo-server, or via the PUBLISHPKG_SERVER environment variable.

You should also give it a GPG key to sign your packages and tarball with. If you do not want to mess with digital signatures, use --no-sign.

publishpkg can also be configured via the publish.conf file introduced earlier. An example configuration is:

[DEFAULT]
hosts = localhost tank.svasey.org
repos = svasey-public
server = repo.svasey.org

The accepted variables are:

  • hosts contains the list of hosts to build for, with localhost being the local host.
  • repos contains the list of repository where to publish
  • server is your repository server.

The variables in the configuration file are used if their corresponding option is not used. For example, if --host does not appear in the command line invocation, then the host list will be read from the configuration file.

An example invocation would be:

$ publishpkg --install --host tank.svasey.org ~/rep/darwrap svasey-public

Which would build, publish on svasey-public and install darwrap on tank.svasey.org and the local host.

Linking to an existing package

If you have already added a package to e.g the private repository and want to make it available in the public one, you can avoid wasting space by making your package in the public repository be the same as the one in the private repository by running the following command:

$ linkpkg $pkgname svasey-private svasey-public

where $pkgname is the name of (or path to) your package

Removing a package

To remove a package, use removepkg. Its first argument is the name of the package to remove, and its second optionnal argument is the name of the repository (all repositories are assumed if nothing is given), e.g:

$ removepkg your_package [public]

Accessing the private svasey arch repository

It is a little more tricky to access it, since pacman does not support ssh directly. The idea is to mount the folder containg the repository remotely using sshfs, and then to access the repository from pacman using a file:// url.

First you need to download sshfs:

yaourt sshfs

And load up fuse:

modprobe fuse

Do not forget to change your /etc/rc.conf so that MODULES include fuse

I use a little trick to ease up mounting of the remote filesystems at each boot. I have a directory /etc/fuse.mount , containing a shell script mountscript, defining two functions: fuse_mount and fuse_umount , mounting and umounting all my fuse filesystems. For example, here is the mountscript file to mount svasey-private:

function fuse_mount ()
{
    sshfs svasey-private@repo.svasey.org: /home/archrepo.mount/svasey-private \
    -F /etc/fuse.mount/svasey-private/ssh_config -o ro
}

function fuse_umount ()
{
    fusermount -u /home/archrepo.mount/svasey-private
}

I have put the ssh keys and configuration information in /etc/fuse.mount/svasey-private

The ssh file system will then be mounted to /home/archrepo.mount/svasey-private. I restrict /home/archrepo.mount to root (root:root 750) because sshfs has some trouble figuring out user permissions inside the mount point. To execute mountscript at each boot, just add something like this in /etc/rc.local

stat_busy "Mounting fuse filesystems"
source /etc/fuse.mount/mountscript
fuse_mount
stat_done

Do not forget to umount at shutdown, i.e in /etc/rc.local.shutdown:

stat_busy "Unmounting fuse filesystems"
source /etc/fuse.mount/mountscript
fuse_umount
stat_done

Finally, add the repository to pacman, in your pacman.conf, add:

[svasey-private]
Server = file:///home/archrepo.mount/svasey-private/os/$arch

Where $arch is either i686 or x86_64. One more thing: you should exclude everything mounted in /home/archrepo.mount from backups: it might take a lot of time to download everything.

Packaging

The server-side hierarchy is implemented by the archrepo-config package. Tools like addpkg and publishpkg are implemented in the repoutils package. My repoutils configuration is in repoutils-config. The fuse remote mounting scripts are in fusemount-config.