How to set up for Ubuntu development¶
The following is a short guide to getting set up for Ubuntu development.
Prerequisites¶
You must have a Launchpad ID. To get an ID:
Go to Launchpad
Click Log in / Register
Install software¶
$ sudo apt update && \
sudo apt dist-upgrade -y && \
sudo apt install -y \
autopkgtest \
dh-make \
git-buildpackage \
pastebinit \
ubuntu-dev-tools && \
sudo snap install lxd && \
sudo snap install --classic snapcraft && \
sudo snap install --classic git-ubuntu
Configure your groups¶
Your user should be a member of the following groups:
admlibvirtlxdsbuildsudo
Ensure you have installed the packages listed above, which will be the trigger to create most of these groups. For group membership to be activated one usually needs to re-login. Then, one can double check group membership via:
$ groups my_user
my_user : my_user adm cdrom sudo dip plugdev lpadmin sambashare \
libvirt sbuild lxd
If any of the following groups is missing for your user you can fix it via
adduser, like this:
$ sudo adduser my_user lxd
$ sudo adduser my_user sbuild
$ sudo adduser my_user libvirt
Configure software¶
GnuPG¶
GnuPG is an encryption tool that helps manage your encryption keys. You’ll need it later to be able to add a signature to each upload.
Eventually the key will represent your identity. Therefore it needs to fulfil several recommendations and be kept safe as well as out of reach of other entities. The setup can be quite complex and is outlined step by step in Set up and manage PGP keys.
Git¶
Installing git-ubuntu will modify your .gitconfig. Make sure it got your
Launchpad username correct:
[gitubuntu]
lpuser = your-launchpad-username
You must also ensure that the [user] section has your name and email:
[user]
name = Your Full Name
email = your@email.com
You may also want to add the following to your .gitconfig:
[log]
decorate = short
[commit]
verbose = true
[merge]
summary = true
stat = true
[core]
whitespace = trailing-space,space-before-tab
[diff "ruby"]
funcname = "^ *\\(\\(def\\) .*\\)"
[diff "image"]
textconv = identify
[url "git+ssh://my_lp_username@git.launchpad.net/"]
insteadof = lp:
Quilt¶
Quilt is a CLI used to manage patch stacks. It can take any number of patches and condense them into a single patch.
A working .quiltrc:
d=. ; while [ ! -d $d/debian -a `readlink -e $d` != / ]; do d=$d/..; done
if [ -d $d/debian ] && [ -z $QUILT_PATCHES ]; then
# if in Debian packaging tree with unset $QUILT_PATCHES
QUILT_PATCHES="debian/patches"
QUILT_PATCH_OPTS="--reject-format=unified"
QUILT_DIFF_ARGS="-p ab --no-timestamps --no-index --color=auto"
QUILT_REFRESH_ARGS="-p ab --no-timestamps --no-index"
QUILT_COLORS="diff_hdr=1;32:diff_add=1;34:diff_rem=1;31:diff_hunk=1;33:diff_ctx=35:diff_cctx=33"
if ! [ -d $d/debian/patches ]; then mkdir $d/debian/patches; fi
fi
This configures Quilt for use with Debian packages, with default settings that conform to standard Debian practices.
dput-ng¶
dput-ng (the Debian Package Upload Tool,
next generation) is the modern replacement for dput. It’s used to upload a
software package to the Ubuntu repository, or to a personal package archive (PPA).
On recent Ubuntu releases, dput-ng is provided by the dput package, so
installing dput gives you dput-ng automatically:
$ sudo apt install dput
A working .dput.cf:
[DEFAULT]
default_host_main = unspecified
[unspecified]
fqdn = SPECIFY.A.TARGET
incoming = /
[ppa]
fqdn = ppa.launchpad.net
method = ftp
incoming = ~%(ppa)s/ubuntu
This configures dput for safety, such that if you accidentally forget to
specify a destination, it’ll default to doing nothing.
sbuild¶
sbuild is the recommended tool for building
packages on Ubuntu. It supports two backends: unshare (recommended) and
schroot (needed for cross-building without unshare).
The unshare backend uses user namespaces and mmdebstrap
to create isolated build environments without requiring root or schroot
setup. With recent versions of sbuild, chroot tarballs are created and
managed automatically on demand using mmdebstrap, making the unshare
backend the recommended approach for most users.
This automatic chroot management is available out of the box on Ubuntu 25.10
and later. It is also available on Ubuntu 24.04 LTS when sbuild is
installed from the noble-backports pocket. It is not available on Ubuntu
22.04 LTS and earlier – use the schroot backend setup instead.
Note
On Ubuntu 24.04 LTS, the noble-backports pocket is enabled by default in
/etc/apt/sources.list.d/ubuntu.sources. If you have disabled it, re-enable
it before installing sbuild from backports.
Install sbuild (from backports on 24.04 LTS) together with mmdebstrap and
uidmap:
Ubuntu 25.10 and later:
$ sudo apt install -y sbuild mmdebstrap uidmap
Ubuntu 24.04 LTS:
$ sudo apt install -y -t noble-backports sbuild mmdebstrap uidmap
sbuild reads the user specific configuration file
~/.config/sbuild/config.pl.
Create the file if it does not exist:
$ mkdir -p ~/.config/sbuild
$ touch ~/.config/sbuild/config.pl
Save the file with the following content:
$chroot_mode = 'unshare';
$unshare_mmdebstrap_keep_tarball = 1;
$unshare_tmpdir_template = '/var/tmp/tmp.sbuild.XXXXXXXXXX';
$clean_source = 0;
$run_lintian = 0;
The schroot backend is the traditional approach. Use this if you are on
Ubuntu 22.04 LTS or earlier, or if you need to cross-build packages without
unshare (see How to build packages locally).
Make the required mount points for builds, logs, and scratch:
$ mkdir -p ~/schroot/{build,logs,scratch}
Add a scratch directory to /etc/schroot/sbuild/fstab:
$ echo "$HOME/schroot/scratch /scratch none rw,bind 0 0" \
| sudo tee -a /etc/schroot/sbuild/fstab
Optionally, you can mount your home directory inside the container:
$ echo "$HOME $HOME none rw,bind 0 0" \
| sudo tee -a /etc/schroot/sbuild/fstab
sbuild reads the user specific configuration file
~/.config/sbuild/config.pl.
Create the file if it does not exist:
$ mkdir -p ~/.config/sbuild
$ touch ~/.config/sbuild/config.pl
Save the file with the following content, replacing the placeholders:
$maintainer_name = 'Your Full Name <your@email.com>';$build_dir = '/home/my_user/schroot/build';$log_dir = "/home/my_user/schroot/logs";
# Name to use as override in .changes files for the Maintainer: field
# (optional; only uncomment if needed).
# $maintainer_name = 'Your Full Name <your@email.com>';
$chroot_mode = 'schroot';
$unshare_mmdebstrap_keep_tarball = 1;
# Default distribution to build.
$distribution = "resolute";
# Build arch-all by default.
$build_arch_all = 1;
# Do not check for the presence of the build dependencies on the host
# system, as these exist only in the unshare chroot.
$clean_source = 0;
$run_lintian = 0;
# When to purge the build directory afterwards; possible values are 'never',
# 'successful', and 'always'. 'always' is the default. It can be helpful
# to preserve failing builds for debugging purposes. Switch these comments
# if you want to preserve even successful builds, and then use
# 'schroot -e --all-sessions' to clean them up manually.
$purge_build_directory = 'successful';
$purge_session = 'successful';
$purge_build_deps = 'successful';
# Directory for chroot symlinks and sbuild logs. Defaults to the
# current directory if unspecified.
$build_dir = '/home/my_user/schroot/build';
# Directory for writing build logs to
$log_dir = '/home/my_user/schroot/logs';
# Key used to sign the source package. Defaults to not using any key.
# $key_id = '';
# don't remove this, Perl needs it:
1;
Create ~/.mk-sbuild.rc:
$ touch ~/.mk-sbuild.rc
Save the file with the following content:
SCHROOT_CONF_SUFFIX="source-root-users=root,sbuild,admin
source-root-groups=root,sbuild,admin
preserve-environment=true"
# you will want to undo the below for stable releases, read `man mk-sbuild` for details
# during the development cycle, these pockets are not used, but will contain important
# updates after each release of Ubuntu
SKIP_UPDATES="1"
SKIP_PROPOSED="1"
# if you have a local proxy like apt-cacher-ng around enable the following
# DEBOOTSTRAP_PROXY=http://127.0.0.1:3142/
schroots
Having sbuild set up is only half of the solution - schroot (secure chroot)
environments for the respective builds are also needed.
Get a schroot for a specific release of Ubuntu using mk-sbuild:
$ mk-sbuild resolute --arch=amd64
List the available schroots:
$ sbuild -l
Update a schroot:
$ sbuild-update -udc resolute-amd64
Delete a schroot:
$ sudo rm /etc/schroot/chroot.d/sbuild-resolute-amd64
$ sudo rm -rf /var/lib/schroot/chroots/resolute-amd64
LXD¶
LXD is a powerful container system similar in concept to Docker and other container software.
Install and set up LXD using the standard installation directions.
Create some helper aliases for common LXD tasks:
$ lxc alias add ls 'list -c ns4,user.comment:comment'
$ lxc alias add login 'exec @ARGS@ \
--mode interactive -- bash -xac $@my_user - exec /bin/login -p -f '
Note that the trailing space after the -f is important. Replace ‘my_user’
with ‘ubuntu’ or whatever username you use in your containers.
Note
For more info, see the LXD documentation
Caching packages¶
When building packages with tools like sbuild or autopkgtest, the build
environment downloads packages from the Ubuntu mirrors on each run. This can
amount to hundreds of megabytes per build and significantly slow down the
iteration cycle.
Setting up a local package cache is strongly recommended.
apt-cacher-ng¶
The simplest approach is to install apt-cacher-ng on your development machine
with its default configuration:
$ sudo apt install apt-cacher-ng
Then configure apt to use it by creating /etc/apt/apt.conf.d/01acng with:
Acquire::http { Proxy "http://127.0.0.1:3142"; }
See also the DEBOOTSTRAP_PROXY setting in .mk-sbuild.rc as an example.
auto-apt-proxy¶
auto-apt-proxy detects a cache on your local network automatically. This is
useful if:
You have a shared cache on your LAN rather than your local machine.
You need the setup to work without reconfiguring when changing networks (e.g., at sprints or conferences).
$ sudo apt install auto-apt-proxy
Even with a local apt-cacher-ng, auto-apt-proxy can help resolve the
correct address to use from inside VMs or containers.
Configure your .profile¶
Your .profile should include entries for DEBFULLNAME and DEBEMAIL:
export DEBFULLNAME="Your Full Name"
export DEBEMAIL=your@email.com
You can also set the DEBSIGN variables:
export DEBSIGN_PROGRAM="/usr/bin/gpg2"
export DEBSIGN_KEYID="0xMYKEYHASH"
A fix for “clear-sign failed: Inappropriate ioctl for device”:
$ export GPG_TTY=$(tty)
If you’re operating from a GUI, this can be useful:
$ eval `dbus-launch --sh-syntax`
Keyring with plaintext storage¶
See git-ubuntu Keyring integration for details on how git-ubuntu uses keyring. If
you want to reconfigure keyring to use plaintext storage to avoid getting
keyring password prompts, create the file
~/.local/share/python_keyring/keyringrc.cfg with the following contents:
[backend]
default-keyring=keyrings.alt.file.PlaintextKeyring