Some time ago, I started to set up the “Network UPS Tools” (NUT) for my uninterruptible power supply (UPS) “Eaton 3S”. It’s a UPS which can be connected to a computer via USB cable.

I found a NUT-package in the “testing”-repository of “Alpine Linux”. Unfortunately, I was unable to create a working setup using this package. After some research, I found the reason for my problems: A missing dependency to the hidapi-package. I wanted to submit a merge request to get around the problem permanently.

Most of my servers run on “Alpine Linux” due to its “diskless mode”, but I prefer “Arch Linux” installed on my laptop. So, I needed an easy and reliable way to build and test the fixed package on my laptop to prepare the merge request.

I decided to give “containers” a try. In this tutorial, I show you, how I get things up and running. I chose the bash-package as an example. Please don’t hesitate to choose another one to follow the tutorial.

Requisites for readers

This article is written for people with a basic understanding in “Linux” operating system and containers. Writing this article, I assume the reader does not have “Alpine Linux” running on her/his workstation. The instructions given here should work for most Linux distributions.

I added tags to clarify which commands have to be executed on which of your systems:

  • Workstation: Your local desktop computer or laptop which you use to run the container.
  • Container: Your build container.

To make this article easier to read, I do not prefix commands run as root with sudo. Instead, I use the following syntax for the commands in this article. But for your daily business, I definitively recommend using the sudo-command.

  • $ command : Running the command as a normal or admin user
  • # command : Running the command as root

Build the container image

Workstation Build container image

First create a working directory and paste the content into a Dockerfile-file. It doesn’t matter how you name the working directory.

$ mkdir -p <working_directory_container_image>
$ vi Dockerfile
FROM alpine:latest

# install required packages to build "alpine linux" packages
RUN apk add --update --no-cache --no-progress alpine-sdk coreutils bash
RUN apk add --update --no-cache --no-progress sudo

# setup directory for built packages
RUN mkdir -p /var/cache/distfiles
RUN chmod a+w /var/cache/distfiles
RUN chgrp abuild /var/cache/distfiles
RUN chmod g+w /var/cache/distfiles

# setup the abuild configuration
RUN echo 'PACKAGER="Your Name <your@email.address>"' >> /etc/abuild.conf
RUN echo 'MAINTAINER="$PACKAGER"' >> /etc/abuild.conf
RUN echo "%abuild ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers.d/abuild

# setup the build user in container
RUN adduser -D user1
RUN addgroup user1 abuild

# setup directory to pass in build instructions files for abuild
VOLUME /home/user1/aports
WORKDIR /home/user1/aports
RUN chown user1:user1 /home/user1/aports

# make user1 the current user in the image
USER user1

# create keys for signing packages after the build has been finished
RUN abuild-keygen -a -i -n

# setup git for the build user
RUN git config --global "Build User"
RUN git config --global ""

Next, please download the current version of the “Alpine Linux” container base image. This step is only required to update an already existing alpine:latest-container image.

$ sudo docker pull alpine:latest

latest: Pulling from library/alpine
5843afab3874: Already exists
Digest: sha256:234cb88d3020898631af0ccbbcca9a66ae7306ecd30c9720690858c1b007d2a0
Status: Downloaded newer image for alpine:latest

When you have created the Dockerfile-file, build the container image with the following command. The given output should match yours.

$ sudo docker build -t feduxorg/alpine-dev .

Sending build context to Docker daemon  3.584kB
Step 1/19 : FROM alpine:latest
 ---> d4ff818577bc
Step 2/19 : RUN apk add --update --no-cache --no-progress alpine-sdk coreutils bash
 ---> Using cache
 ---> f7744c1c2842
Step 3/19 : RUN apk add --update --no-cache --no-progress sudo
 ---> Using cache
 ---> 3ea4a0e3bc06
Step 4/19 : RUN mkdir -p /var/cache/distfiles
 ---> Using cache
 ---> 1e97184b0aca
Step 5/19 : RUN chmod a+w /var/cache/distfiles
 ---> Using cache
 ---> f85a246cf9c4
Step 6/19 : RUN chgrp abuild /var/cache/distfiles
 ---> Using cache
 ---> 0167de99bca8
Step 7/19 : RUN chmod g+w /var/cache/distfiles
 ---> Using cache
 ---> bf41921c42ba
Step 8/19 : RUN echo 'PACKAGER="Your Name <your@email.address>"' >> /etc/abuild.conf
 ---> Using cache
 ---> a6b0746093eb
Step 9/19 : RUN echo 'MAINTAINER="$PACKAGER"' >> /etc/abuild.conf
 ---> Using cache
 ---> c8147e4ff956
Step 10/19 : RUN echo "%abuild ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers.d/abuild
 ---> Using cache
 ---> 8e128a7d77d9
Step 11/19 : RUN adduser -D user1
 ---> Using cache
 ---> 072258140dc3
Step 12/19 : RUN addgroup user1 abuild
 ---> Using cache
 ---> 815f63fcb234
Step 13/19 : VOLUME /home/user1/aports
 ---> Using cache
 ---> 5337450d764a
Step 14/19 : WORKDIR /home/user1/aports
 ---> Using cache
 ---> 859c352752c3
Step 15/19 : RUN chown user1:user1 /home/user1/aports
 ---> Using cache
 ---> df99576f1802
Step 16/19 : USER user1
 ---> Using cache
 ---> 09edaf22bc0b
Step 17/19 : RUN abuild-keygen -a -i -n
 ---> Using cache
 ---> abe47dd97da3
Step 18/19 : RUN git config --global "Build User"
 ---> Running in c50ce65f6cc7
Removing intermediate container c50ce65f6cc7
 ---> 147325c8eb08
Step 19/19 : RUN git config --global ""
 ---> Running in 5b9fcd3c6501
Removing intermediate container 5b9fcd3c6501
 ---> f859ac69a8d6
Successfully built f859ac69a8d6
Successfully tagged feduxorg/alpine-dev:latest

Setup “Alpine Linux” “aports”

Workstation Clone “aports” repository

Please clone the “Alpine Linux” aports-repository. For this tutorial, we use a so-called “shallow clone” to speed up the git clone-command. Remove the --depth 1-parameter if you clone the repository for a “real” merge request.

$ git clone --depth 1

Cloning into 'aports'...
warning: redirecting to
remote: Enumerating objects: 22163, done.
remote: Counting objects: 100% (22163/22163), done.
remote: Compressing objects: 100% (15417/15417), done.
remote: Total 22163 (delta 1008), reused 16749 (delta 831), pack-reused 0
Receiving objects: 100% (22163/22163), 10.91 MiB | 6.48 MiB/s, done.
Resolving deltas: 100% (1008/1008), done.
Updating files: 100% (14383/14383), done.

When the git clone-command has finished, make the aports-directory to your current working directory.

$ cd aports

Prepare the build container

  • Workstation Start the build container

    Please start the container. You need to pass the directory with the aports-repository to the container.

    $ sudo docker run --rm --name alpine-dev-1 -v $PWD:/home/user1/aports -it  feduxorg/alpine-dev
  • Container Check the content of the /home/user1/aports-directory.

    Given you cloned the aports-repository and passed it to the container, you should see a similar content in your directory.

    $ ls -1
  • Container Update package repository

    apk requires the package database to be available to install packages. So, please, update the package database first.

    $ sudo apk update
    v3.14.0-114-g8a8c96a0ea []
    v3.14.0-112-gde20fa9d3b []
    OK: 14932 distinct packages available

Build “Alpine Linux” package

  • Container Build package

    As mentioned at the beginning, we build the bash-package in this tutorial. Please navigate to the /home/user1/aports/main/bash-directory and run the abuild-command.

    This directory contains all required files to build the package. The most important one is the APKBUILD-file. It contains all instructions about how to create the apk-package.

    $ cd /home/user1/aports/main/bash
    $ abuild -r
    >>> bash: Building main/bash 5.1.8-r0 (using abuild 3.8.0_rc4-r0) started Sun, 11 Jul 2021 13:06:38 +0000
    >>> bash: Checking sanity of /home/user1/aports/main/bash/APKBUILD...
    >>> bash: Analyzing dependencies...
    >>> bash: Installing for build: build-base bison flex readline-dev>8 ncurses-dev
    WARNING: Ignoring /home/user1/packages//main: No such file or directory
    (1/7) Installing m4 (1.4.18-r2)
    (2/7) Installing bison (3.7.6-r0)
    (3/7) Installing flex (2.6.4-r2)
    (4/7) Installing libhistory (8.1.0-r0)
    (5/7) Installing ncurses-dev (6.2_p20210612-r0)
    (6/7) Installing readline-dev (8.1.0-r0)
    (7/7) Installing .makedepends-bash (20210711.130638)
    Executing busybox-1.33.1-r2.trigger
    OK: 238 MiB in 72 packages
    >>> bash: Cleaning up srcdir
    >>> bash: Cleaning up pkgdir
    >>> bash: Fetching
      % Total    % Received % Xferd  Average Speed   Time    Time     Tim
    >>> bash: Build complete at Sun, 11 Jul 2021 13:09:29 +0000 elapsed time 0h 2m 51s
    >>> bash: Cleaning up srcdir
    >>> bash: Cleaning up pkgdir
    >>> bash: Uninstalling dependencies...
    (1/7) Purging .makedepends-bash (20210711.130638)
    (2/7) Purging bison (3.7.6-r0)
    (3/7) Purging flex (2.6.4-r2)
    (4/7) Purging m4 (1.4.18-r2)
    (5/7) Purging readline-dev (8.1.0-r0)
    (6/7) Purging libhistory (8.1.0-r0)
    (7/7) Purging ncurses-dev (6.2_p20210612-r0)
    Executing busybox-1.33.1-r2.trigger
    OK: 236 MiB in 65 packages
    >>> bash: Updating the main/x86_64 repository index...
    >>> bash: Signing the index...
  • Container Check for built packages

    By default, abuild places built packages under /home/user1/packages/. Let’s check, if we can find our packages in that directory as well.

    $ find /home/user1/packages/main/x86_64/ | sort
  • Container Install package

    Given your build was successful, you can find the package and install it. Any error about missing other packages requires a modification of the APKBUILD-file.

    $ sudo apk add --allow-untrusted /home/user1/packages/main/x86_64/bash*apk
    (1/4) Upgrading bash (5.1.4-r0 -> 5.1.8-r0)
    (2/4) Installing bash-dbg (5.1.8-r0)
    (3/4) Installing bash-dev (5.1.8-r0)
    (4/4) Installing bash-doc (5.1.8-r0)
    Executing busybox-1.33.1-r2.trigger
    OK: 241 MiB in 68 packages


Now you have got a working build environment for an “Alpine Linux”-package. I hope you can make some use of it and support the “Alpine Linux”-project.


If you found a mistake in this article or would like to contribute some content to it, please file an issue in this Git Repository


The contents of this article are put together to the best of the authors' knowledge, but it cannot be guaranteed that it's always accurate in any environment. It is up to the reader to make sure that all information found in this article, does not do any damage to the reader's working environment or wherever this information is applied to. In no event shall the authors or copyright holders be liable for any claim, damages or other liability, arising from, out of or in connection with this article. Please also note the information given on the Licences' page.