MMDEBSTRAP(1) | User Contributed Perl Documentation | MMDEBSTRAP(1) |
mmdebstrap - multi-mirror Debian chroot creation
mmdebstrap [OPTION...] [SUITE [TARGET [MIRROR...]]]
mmdebstrap creates a Debian chroot of SUITE into TARGET from one or more MIRRORs. It is meant as an alternative to the debootstrap tool (see section DEBOOTSTRAP). In contrast to debootstrap it uses apt to resolve dependencies and is thus able to use more than one mirror and resolve more complex dependency relationships. See section OPERATION for an overview of how mmdebstrap works internally.
The SUITE option may either be a valid release code name (eg, sid, bookworm, trixie) or a symbolic name (eg, unstable, testing, stable, oldstable). Any suite name that works with apt on the given mirror will work. The SUITE option is optional if no TARGET and no MIRROR option is provided. If SUITE is missing, then the information of the desired suite has to come from standard input as part of a valid apt sources.list file or be set up via hooks. The value of the SUITE argument will be used to determine which apt index to use for finding out the set of "Essential:yes" packages and/or the set of packages with the right priority for the selected variant. This functionality can be disabled by choosing the empty string for SUITE. See the section VARIANTS for more information.
The TARGET option may either be the path to a directory, the path to a tarball filename, the path to a squashfs image, the path to an ext2 image, a FIFO, a character special device, or "-". The TARGET option is optional if no MIRROR option is provided. If TARGET is missing or if TARGET is "-", an uncompressed tarball will be sent to standard output. Without the --format option, TARGET will be used to choose the format. See the section FORMATS for more information.
The MIRROR option may either be provided as a URI, in apt one-line format, as a path to a file in apt's one-line or deb822-format, or "-". If no MIRROR option is provided, then <http://deb.debian.org/debian> is used as the default. If SUITE does not refer to "unstable" or "testing", then SUITE-updates and SUITE-security mirrors are automatically added. If a MIRROR option starts with "deb " or "deb-src " then it is used as a one-line format entry for apt's sources.list inside the chroot. If a MIRROR option contains a "://" then it is interpreted as a mirror URI and the apt line inside the chroot is assembled as "deb [arch=A] B C D" where A is the host's native architecture, B is the MIRROR, C is the given SUITE and D is the components given via --components (defaults to "main"). If a MIRROR option happens to be an existing file, then its contents are written into the chroot's sources.list (if the first MIRROR is a file in one-line format) or into the chroot's sources.list.d directory, named with the extension .list or .sources, depending on whether the file is in one-line or deb822 format, respectively. If MIRROR is "-" then standard input is pasted into the chroot's sources.list. More than one mirror can be specified and are appended to the chroot's sources.list in the given order. If you specify a https or tor MIRROR and you want the chroot to be able to update itself, don't forget to also install the ca-certificates package, the apt-transport-https package for apt versions less than 1.5 and/or the apt-transport-tor package using the --include option, as necessary.
All status output is printed to standard error unless --logfile is used to redirect it to a file or --quiet or --silent is used to suppress any output on standard error. Help and version information will be printed to standard error with the --help and --version options, respectively. Otherwise, an uncompressed tarball might be sent to standard output if TARGET is "-" or if no TARGET was specified.
Options are case insensitive. Short options may be bundled. Long options require a double dash and may be abbreviated to uniqueness. Options can be placed anywhere on the command line, even before or mixed with the SUITE, TARGET, and MIRROR arguments. A double dash "--" can be used to stop interpreting command line arguments as options to allow SUITE, TARGET and MIRROR arguments that start with a single or double dash. Option order only matters for options that can be passed multiple times as documented below.
pod2man /usr/bin/mmdebstrap | man -l -
Example: This is necessary for allowing old timestamps from snapshot.debian.org
--aptopt='Acquire::Check-Valid-Until "false"' --aptopt='Apt::Key::gpgvcommand "/usr/libexec/mmdebstrap/gpgvnoexpkeysig"'
Example: Settings controlling download of package description translations
--aptopt='Acquire::Languages { "environment"; "en"; }' --aptopt='Acquire::Languages "none"'
Example: Enable installing Recommends (by default mmdebstrap doesn't)
--aptopt='Apt::Install-Recommends "true"'
Example: Configure apt-cacher or apt-cacher-ng as an apt proxy
--aptopt='Acquire::http { Proxy "http://127.0.0.1:3142"; }'
Example: For situations in which the apt sandbox user cannot access the chroot
--aptopt='APT::Sandbox::User "root"'
Example: Minimizing the number of packages installed from experimental
--aptopt='APT::Solver "aspcud"' --aptopt='APT::Solver::aspcud::Preferences "-count(solution,APT-Release:=/a=experimental/),-removed,-changed,-new"'
By default, the local setting of Dir::Etc::Trusted and Dir::Etc::TrustedParts are used to choose the keyring used by apt as run by mmdebstrap. These two locations are set to /etc/apt/trusted.gpg and /etc/apt/trusted.gpg.d by default. Depending on whether a file or directory is passed to this option, the former and latter default can be changed, respectively. Since apt only supports a single keyring file and directory, respectively, you can not use this option to pass multiple files and/or directories. Using the "--keyring" argument in the following way is equal to keeping the default:
--keyring=/etc/apt/trusted.gpg --keyring=/etc/apt/trusted.gpg.d
If you need to pass multiple keyrings, use the "signed-by" option when specifying the mirror like this:
mmdebstrap mysuite out.tar "deb [signed-by=/path/to/key.gpg] http://..."
Another reason to use "signed-by" instead of --keyring is if apt inside the chroot needs to know by what key the repository is signed even after the initial chroot creation.
The "signed-by" option will automatically be added to the final "sources.list" if the keyring required for the selected SUITE is not yet trusted by apt. Automatically adding the "signed-by" option in these cases requires "gpg" to be installed. If "gpg" and "ubuntu-archive-keyring" are installed, then you can create a Ubuntu Bionic chroot on Debian like this:
mmdebstrap bionic ubuntu-bionic.tar
The resulting chroot will have a "source.list" with a "signed-by" option pointing to /usr/share/keyrings/ubuntu-archive-keyring.gpg.
You do not need to use --keyring or "signed-by" if you placed the keys that apt needs to know about into /etc/apt/trusted.gpg.d in the --setup-hook (which is before "apt update" runs), for example by using the copy-in special hook. You also need to copy your keys into the chroot explicitly if the key you passed via "signed-by" points to a location that is not otherwise populated during chroot creation (for example by installing a keyring package).
Example: Exclude paths to reduce chroot size
--dpkgopt='path-exclude=/usr/share/man/*' --dpkgopt='path-include=/usr/share/man/man[1-9]/*' --dpkgopt='path-exclude=/usr/share/locale/*' --dpkgopt='path-include=/usr/share/locale/locale.alias' --dpkgopt='path-exclude=/usr/share/doc/*' --dpkgopt='path-include=/usr/share/doc/*/copyright' --dpkgopt='path-include=/usr/share/doc/*/changelog.Debian.*'
The option can be specified multiple times and the packages are concatenated in the order in which they are given on the command line. If later list items are repeated, then they get dropped so that the resulting package list is free of duplicates. So the following are equivalent:
--include="pkg1/stable pkg2=1.0 pkg3-" --include=pkg1/stable,pkg2=1.0,pkg3-,,, --incl=pkg1/stable --incl="pkg2=1.0 pkg3-" --incl=pkg2=1.0,pkg3-
Since the list of packages is separated by comma or whitespace, it is not possible to mix apt patterns or .deb package file paths containing either commas or whitespace with normal package names. If you do, your patterns and paths will be split by comma and whitespace as well and become useless. To pass such a pattern or package file path, put them into their own --include option. If the argument to --include starts with an apt pattern or with a file path, then it will not be split:
--include="?or(?priority(required), ?priority(important))" --include="./path/to/deb with spaces/and,commas/foo.deb"
Specifically, all arguments to --include that start with a "?", "!", "~", "(", "/", "./" or "../" are not split and treated as single arguments to apt. To add more packages, use multiple --include options. To disable this detection of patterns and paths, start the argument to --include with a comma or whitespace.
If you pass the path to a .deb package file using --include, mmdebstrap will ensure that the path exists. If the path is a relative path, it will internally by converted to an absolute path. Since apt (outside the chroot) passes paths to dpkg (on the inside) verbatim, you have to make the .deb package available under the same path inside the chroot as well or otherwise dpkg inside the chroot will be unable to access it. This can be achieved using a setup-hook. A hook that automatically makes the contents of "file://" mirrors as well as .deb packages given with --include available inside the chroot is provided by mmdebstrap as --hook-dir=/usr/share/mmdebstrap/hooks/file-mirror-automount. This hook takes care of copying all relevant file to their correct locations and cleans up those files at the end. In unshare mode, the .deb package paths have to be accessible by the unshared user as well. This means that the package itself likely must be made world-readable and all directory components on the path to it world-executable.
--components="main contrib non-free non-free-firmware" --components=main,contrib,non-free,non-free-firmware --comp=main --comp="contrib non-free" --comp="main,non-free-firmware"
--architectures="amd64 armhf mipsel" --architectures=amd64,armhf,mipsel --arch=amd64 --arch="armhf mipsel" --arch=armhf,mipsel
Example: add additional apt sources entries on top of the default ones:
--setup-hook='echo "deb http..." > "$1"/etc/apt/sources.list.d/custom.list'
Example: Setup chroot for installing a sub-essential busybox-based chroot with --variant=custom --include=dpkg,busybox,libc-bin,base-files,base-passwd,debianutils
--setup-hook='mkdir -p "$1/bin"' --setup-hook='for p in awk cat chmod chown cp diff echo env grep less ln mkdir mount rm rmdir sed sh sleep sort touch uname mktemp; do ln -s busybox "$1/bin/$p"; done' --setup-hook='echo root:x:0:0:root:/root:/bin/sh > "$1/etc/passwd"' --setup-hook='printf "root:x:0:\nmail:x:8:\nutmp:x:43:\n" > "$1/etc/group"'
For a more elegant way for setting up a sub-essential busybox-based chroot, see the --hook-dir option below.
Example: Install busybox symlinks
--extract-hook='chroot "$1" /bin/busybox --install -s'
Example: Enable unattended upgrades
--essential-hook='echo unattended-upgrades unattended-upgrades/enable_auto_updates boolean true | chroot "$1" debconf-set-selections'
Example: Select Europe/Berlin as the timezone
--essential-hook='echo tzdata tzdata/Areas select Europe | chroot "$1" debconf-set-selections' --essential-hook='echo tzdata tzdata/Zones/Europe select Berlin | chroot "$1" debconf-set-selections'
Example: Add a user without a password
--customize-hook='chroot "$1" useradd --home-dir /home/user --create-home user' --customize-hook='chroot "$1" passwd --delete user'
Example: set up /etc/hostname and /etc/hosts
--customize-hook='echo host > "$1/etc/hostname"' --customize-hook='echo "127.0.0.1 localhost host" > "$1/etc/hosts"'
Example: to mimic debootstrap behaviour, mmdebstrap copies from the host. Remove them in a --customize-hook to make the chroot reproducible across multiple hosts:
--customize-hook='rm "$1"/etc/resolv.conf' --customize-hook='rm "$1"/etc/hostname'
mmdebstrap --customize=./scriptA --hook-dir=./hooks --setup=./scriptB
is equivalent to this call:
mmdebstrap --customize=./scriptA --setup=./hooks/setup01-foo.sh \ --setup=./hooks/setup02-bar.sh --setup=./scriptB
The option can be specified multiple times and scripts are added to the respective hooks in the order the options are given on the command line. Thus, if the scripts in two directories depend upon each other, the scripts must be placed into a common directory and be named such that they get added in the correct order.
Example 1: Run mmdebstrap with eatmydata
--hook-dir=/usr/share/mmdebstrap/hooks/eatmydata
Example 2: Setup chroot for installing a sub-essential busybox-based chroot
--hook-dir=/usr/share/mmdebstrap/hooks/busybox
Example 3: Automatically mount all directories referenced by "file://" mirrors into the chroot
--hook-dir=/usr/share/mmdebstrap/hooks/file-mirror-automount
Creating a Debian chroot requires not only permissions for running chroot but also the ability to create files owned by the superuser. The selected mode decides which way this is achieved.
The unshared user will not automatically have access to the same files as you do. This is intentional and an additional security against unintended changes to your files that could theoretically result from running mmdebstrap and package maintainer scripts. To copy files in and out of the chroot, either use globally readable or writable directories or use special hooks like copy-in and copy-out.
Besides the user namespace, the mount, pid (process ids), uts (hostname) and ipc namespaces will be unshared as well. See the man pages of namespaces(7) and unshare(2) as well as the manual pages they are linking to.
A directory chroot created with this mode will end up with wrong ownership information (seen from outside the unshared user namespace). For correct ownership information, the directory must be accessed from a user namespace with the right subuid/subgid offset, like so:
$ lxc-usernsexec -- lxc-unshare -s 'MOUNT|PID|UTSNAME|IPC' -- \ > /usr/sbin/chroot ./debian-rootfs /bin/bash
Or without LXC:
$ mmdebstrap --unshare-helper /usr/sbin/chroot ./debian-rootfs /bin/bash
Or, if you don't mind using superuser privileges and have systemd-nspawn available and you know your subuid/subgid offset (100000 in this example):
$ sudo systemd-nspawn --private-users=100000 \ > --directory=./debian-rootfs /bin/bash
A directory created in unshare mode cannot be removed the normal way. Instead, use something like this:
$ unshare --map-root-user --map-auto rm -rf ./debian-rootfs
If this mode is used as the root user, the user namespace is not unshared (but the mount namespace and other still are) and created directories will have correct ownership information. This is also useful in cases where the root user wants the benefits of an unshared mount namespace to prevent accidentally messing up the system.
mmdebstrap --variant=apt --include=mmdebstrap \ --customize-hook='chroot "$1" mmdebstrap --mode=chrootless --variant=apt unstable chrootless.tar' \ --customize-hook='copy-out chrootless.tar .' unstable /dev/null
All package sets also include the direct and indirect hard dependencies (but not recommends) of the selected package sets. The variants minbase, buildd and -, resemble the package sets that debootstrap would install with the same --variant argument. The release with a name matching the SUITE argument as well as the native architecture will be used to determine the "Essential:yes" and priority values. To select packages with matching priority from any suite, specify the empty string for SUITE. The default variant is debootstrap.
--variant=essential --include="apt,build-essential"
--variant=essential --include="?priority(required)"
--variant=essential --include="~prequired|~pimportant"
--variant=essential --include="~prequired|~pimportant|~pstandard"
The output format of mmdebstrap is specified using the --format option. Without that option the default format is auto. The following formats exist:
This section describes properties of the hook options --setup-hook, --extract-hook, --essential-hook and --customize-hook which are common to all four of them. Any information specific to each hook is documented under the specific hook options in the section OPTIONS.
The options can be specified multiple times and the commands are executed in the order in which they are given on the command line. There are four different types of hook option arguments. If the argument passed to the hook option starts with "copy-in", "copy-out", "tar-in", "tar-out", "upload" or "download" followed by a space, then the hook is interpreted as a special hook. Otherwise, if command is an existing executable file from $PATH or if command does not contain any shell metacharacters, then command is directly exec-ed with the path to the chroot directory passed as the first argument. Otherwise, command is executed under sh and the chroot directory can be accessed via $1. Most environment variables set by mmdebstrap (like "DEBIAN_FRONTEND", "LC_ALL" and "PATH") are preserved. Most notably, "APT_CONFIG" is being unset. If you need the path to "APT_CONFIG" as written by mmdebstrap it can be found in the "MMDEBSTRAP_APT_CONFIG" environment variable. All environment variables set by the user are preserved, except for "TMPDIR" which is cleared. See section TMPDIR. Furthermore, "MMDEBSTRAP_MODE" will store the mode set by --mode, "MMDEBSTRAP_FORMAT" stores the format chosen by --format, "MMDEBSTRAP_HOOK" stores which hook is currently run (setup, extract, essential, customize), "MMDEBSTRAP_ARGV0" stores the name of the binary with which mmdebstrap was executed and "MMDEBSTRAP_VERBOSITY" stores the numerical verbosity level (0 for no output, 1 for normal, 2 for verbose and 3 for debug output). The "MMDEBSTRAP_INCLUDE" variable stores the list of packages, apt patterns or file paths given by the --include option, separated by a comma and with commas and percent signs in the option values urlencoded. If SUITE name was supplied, it's stored in "MMDEBSTRAP_SUITE".
In special hooks, the paths inside the chroot are relative to the root directory of the chroot. The path on the outside is relative to current directory of the original mmdebstrap invocation. The path inside the chroot must already exist. Paths outside the chroot are created as necessary.
In fakechroot mode, "tar", or "sh" and "cat" have to be run inside the chroot or otherwise, symlinks will be wrongly resolved and/or permissions will be off. This means that the special hooks might fail in fakechroot mode for the setup hook or for the extract and custom variants if no "tar" or "sh" and "cat" is available inside the chroot.
This section gives an overview of the different steps to create a chroot. At its core, what mmdebstrap does can be put into a 14 line shell script:
mkdir -p "$2/etc/apt" "$2/var/cache" "$2/var/lib" cat << END > "$2/apt.conf" Apt::Architecture "$(dpkg --print-architecture)"; Apt::Architectures "$(dpkg --print-architecture)"; Dir "$(cd "$2" && pwd)"; Dir::Etc::Trusted "$(eval "$(apt-config shell v Dir::Etc::Trusted/f)"; printf "$v")"; Dir::Etc::TrustedParts "$(eval "$(apt-config shell v Dir::Etc::TrustedParts/d)"; printf "$v")"; END echo "deb http://deb.debian.org/debian/ $1 main" > "$2/etc/apt/sources.list" APT_CONFIG="$2/apt.conf" apt-get update APT_CONFIG="$2/apt.conf" apt-get --yes --download-only install '?essential' for f in "$2"/var/cache/apt/archives/*.deb; do dpkg-deb --extract "$f" "$2"; done chroot "$2" sh -c "dpkg --install --force-depends /var/cache/apt/archives/*.deb"
The additional complexity of mmdebstrap is to support operation without superuser privileges, bit-by-bit reproducible output, hooks and foreign architecture support.
The remainder of this section explains what mmdebstrap does step-by-step.
If --skip=output/dev is added, the resulting chroot will not contain the device nodes, directories and symlinks that debootstrap creates but just an empty /dev as created by base-files.
If --skip=output/mknod is added, the resulting chroot will not contain device nodes (neither block nor character special devices). This is useful if the chroot tarball is to be exatracted in environments where mknod does not function like in unshared user namespaces.
Use like debootstrap:
$ sudo mmdebstrap unstable ./unstable-chroot
Without superuser privileges:
$ mmdebstrap unstable unstable-chroot.tar
With no command line arguments at all. The chroot content is entirely defined by a sources.list file on standard input.
$ mmdebstrap < /etc/apt/sources.list > unstable-chroot.tar
Since the tarball is output on stdout, members of it can be excluded using tar on-the-fly. For example the /dev directory can be removed from the final tarbal in cases where it is to be extracted by a non-root user who cannot create device nodes:
$ mmdebstrap unstable | tar --delete ./dev > unstable-chroot.tar
Create a tarball for use with "sbuild --chroot-mode=unshare":
$ mmdebstrap --variant=buildd unstable ~/.cache/sbuild/unstable-amd64.tar
Instead of a tarball, a squashfs image can be created:
$ mmdebstrap unstable unstable-chroot.squashfs
By default, mmdebstrap runs tar2sqfs with "--no-skip --exportable --compressor xz --block-size 1048576". To choose a different set of options, and to filter out all extended attributes not supported by tar2sqfs, pipe the output of mmdebstrap into tar2sqfs manually like so:
$ mmdebstrap unstable \ | mmtarfilter --pax-exclude='*' \ --pax-include='SCHILY.xattr.user.*' \ --pax-include='SCHILY.xattr.trusted.*' \ --pax-include='SCHILY.xattr.security.*' \ | tar2sqfs --quiet --no-skip --force --exportable --compressor xz \ --block-size 1048576 unstable-chroot.squashfs
By default, debootstrapping a stable distribution will add mirrors for security and updates to the sources.list.
$ mmdebstrap stable stable-chroot.tar
If you don't want this behaviour, you can override it by manually specifying a mirror in various different ways:
$ mmdebstrap stable stable-chroot.tar http://deb.debian.org/debian $ mmdebstrap stable stable-chroot.tar "deb http://deb.debian.org/debian stable main" $ mmdebstrap stable stable-chroot.tar /path/to/sources.list $ mmdebstrap stable stable-chroot.tar - < /path/to/sources.list
Drop locales (but not the symlink to the locale name alias database), translated manual packages (but not the untranslated ones), and documentation (but not copyright and Debian changelog).
$ mmdebstrap --variant=essential \ --dpkgopt='path-exclude=/usr/share/man/*' \ --dpkgopt='path-include=/usr/share/man/man[1-9]/*' \ --dpkgopt='path-exclude=/usr/share/locale/*' \ --dpkgopt='path-include=/usr/share/locale/locale.alias' \ --dpkgopt='path-exclude=/usr/share/doc/*' \ --dpkgopt='path-include=/usr/share/doc/*/copyright' \ --dpkgopt='path-include=/usr/share/doc/*/changelog.Debian.*' \ unstable debian-unstable.tar
Create a bootable USB Stick that boots into a full Debian desktop:
$ mmdebstrap --aptopt='Apt::Install-Recommends "true"' --customize-hook \ 'chroot "$1" adduser --gecos user --disabled-password user' \ --customize-hook='echo 'user:live' | chroot "$1" chpasswd' \ --customize-hook='echo host > "$1/etc/hostname"' \ --customize-hook='echo "127.0.0.1 localhost host" > "$1/etc/hosts"' \ --include=linux-image-amd64,task-desktop unstable debian-unstable.tar $ cat << END > extlinux.conf > default linux > timeout 0 > > label linux > kernel /vmlinuz > append initrd=/initrd.img root=LABEL=rootfs END # You can use $(sudo blockdev --getsize64 /dev/sdXXX) to get the right # image size for the target medium in bytes $ guestfish -N debian-unstable.img=disk:8G -- \ part-disk /dev/sda mbr : \ part-set-bootable /dev/sda 1 true : \ mkfs ext4 /dev/sda1 : \ set-label /dev/sda1 rootfs : \ mount /dev/sda1 / : \ tar-in debian-unstable.tar / xattrs:true : \ upload /usr/lib/EXTLINUX/mbr.bin /boot/mbr.bin : \ copy-file-to-device /boot/mbr.bin /dev/sda size:440 : \ extlinux / : copy-in extlinux.conf / : sync : umount / : shutdown $ qemu-system-x86_64 -m 1G -enable-kvm debian-unstable.img $ sudo dd if=debian-unstable.img of=/dev/sdXXX status=progress
On architectures without extlinux you can also boot using grub2:
$ mmdebstrap --include=linux-image-amd64,grub2,systemd-sysv unstable fs.tar $ guestfish -N debian-unstable.img=disk:2G -- \ part-disk /dev/sda mbr : \ part-set-bootable /dev/sda 1 true : \ mkfs ext4 /dev/sda1 : \ set-label /dev/sda1 rootfs : \ mount /dev/sda1 / : \ tar-in fs.tar / xattrs:true : \ command "grub-install /dev/sda" : \ command update-grub : \ sync : umount / : shutdown $ qemu-system-x86_64 -m 1G -enable-kvm debian-unstable.img
Build libdvdcss2.deb without installing installing anything or changing apt sources on the current system:
$ mmdebstrap --variant=apt --components=main,contrib --include=libdvd-pkg \ --customize-hook='chroot $1 /usr/lib/libdvd-pkg/b-i_libdvdcss.sh' \ | tar --extract --verbose --strip-components=4 \ --wildcards './usr/src/libdvd-pkg/libdvdcss2_*_*.deb' $ ls libdvdcss2_*_*.deb
Use as replacement for autopkgtest-build-qemu and vmdb2 for all architectures supporting EFI booting (amd64, arm64, armhf, i386, riscv64), use a convenience wrapper around mmdebstrap:
$ mmdebstrap-autopkgtest-build-qemu unstable ./autopkgtest.img
Use as replacement for autopkgtest-build-qemu and vmdb2 on architectures supporting extlinux (amd64 and i386):
$ mmdebstrap --variant=important --include=linux-image-amd64 \ --customize-hook='chroot "$1" passwd --delete root' \ --customize-hook='chroot "$1" useradd --home-dir /home/user --create-home user' \ --customize-hook='chroot "$1" passwd --delete user' \ --customize-hook='echo host > "$1/etc/hostname"' \ --customize-hook='echo "127.0.0.1 localhost host" > "$1/etc/hosts"' \ --customize-hook=/usr/share/autopkgtest/setup-commands/setup-testbed \ unstable debian-unstable.tar $ cat << END > extlinux.conf > default linux > timeout 0 > > label linux > kernel /vmlinuz > append initrd=/initrd.img root=/dev/vda1 rw console=ttyS0 END $ guestfish -N debian-unstable.img=disk:8G -- \ part-disk /dev/sda mbr : \ part-set-bootable /dev/sda 1 true : \ mkfs ext4 /dev/sda1 : mount /dev/sda1 / : \ tar-in debian-unstable.tar / xattrs:true : \ upload /usr/lib/EXTLINUX/mbr.bin /boot/mbr.bin : \ copy-file-to-device /boot/mbr.bin /dev/sda size:440 : \ extlinux / : copy-in extlinux.conf / : sync : umount / : shutdown $ qemu-img convert -O qcow2 debian-unstable.img debian-unstable.qcow2
As a debootstrap wrapper to run it without superuser privileges but using Linux user namespaces instead. This fixes Debian bug #829134.
$ mmdebstrap --variant=custom --mode=unshare \ --setup-hook='debootstrap unstable "$1"' \ - debian-debootstrap.tar
Build a non-Debian chroot like Ubuntu bionic:
$ mmdebstrap --aptopt='Dir::Etc::Trusted "/usr/share/keyrings/ubuntu-keyring-2012-archive.gpg"' bionic bionic.tar
If, for some reason, you cannot use a caching proxy like apt-cacher or apt-cacher-ng, you can use the sync-in and sync-out special hooks to synchronize a directory outside the chroot with /var/cache/apt/archives inside the chroot.
$ mmdebstrap --variant=apt --skip=essential/unlink \ --setup-hook='mkdir -p ./cache "$1"/var/cache/apt/archives/' \ --setup-hook='sync-in ./cache /var/cache/apt/archives/' \ --customize-hook='sync-out /var/cache/apt/archives ./cache' \ unstable /dev/null
Instead of copying potentially large amounts of data with sync-in you can also use a bind-mount in combination with a "file://" mirror to make packages from the outside available inside the chroot:
$ mmdebstrap --variant=apt --skip=essential/unlink \ --setup-hook='mkdir "$1/tmp/mirror"' \ --setup-hook='mount -o ro,bind /tmp/mirror "$1/tmp/mirror"' \ --customize-hook='sync-out /var/cache/apt/archives ./cache' \ --customize-hook='umount "$1/tmp/mirror"; rmdir "$1/tmp/mirror";' \ unstable /dev/null file:///tmp/mirror http://deb.debian.org/debian
To automatically mount all directories referenced by "file://" mirrors into the chroot you can use a hook:
$ mmdebstrap --variant=apt \ --hook-dir=/usr/share/mmdebstrap/hooks/file-mirror-automount \ unstable /dev/null file:///tmp/mirror1 file:///tmp/mirror2
Create a system that can be used with docker:
$ mmdebstrap unstable | sudo docker import - debian [...] $ sudo docker run -it --rm debian whoami root $ sudo docker rmi debian
Create and boot a qemu virtual machine for an arbitrary architecture using the debvm-create wrapper script around mmdebstrap:
$ debvm-create -r stable -- --architecture=riscv64 $ debvm-run
Create a system that can be used with podman:
$ mmdebstrap unstable | podman import - debian [...] $ podman run --network=none -it --rm debian whoami root $ podman rmi debian
As a docker/podman replacement:
$ mmdebstrap unstable chroot.tar [...] $ mmdebstrap --variant=custom --skip=update,tar-in/mknod \ --setup-hook='tar-in chroot.tar /' \ --customize-hook='chroot "$1" whoami' unstable /dev/null [...] root $ rm chroot.tar
You can re-use a chroot tarball created with mmdebstrap for further refinement. Say you want to create a minimal chroot and a chroot with more packages installed, then instead of downloading and installing the essential packages twice you can instead build on top of the already present minimal chroot:
$ mmdebstrap --variant=apt unstable chroot.tar $ mmdebstrap --variant=custom --skip=update,setup,cleanup,tar-in/mknod \ --setup-hook='tar-in chroot.tar /' \ --customize-hook='chroot "$1" apt-get install --yes pkg1 pkg2' \ '' chroot-full.tar
$ mmdebstrap --customize-hook='rm "$1"/etc/resolv.conf' \ --customize-hook='rm "$1"/etc/hostname' ...
or fill them with reproducible content:
$ mmdebstrap --customize-hook='echo nameserver X > "$1"/etc/resolv.conf' \ --customize-hook='echo host > "$1"/etc/hostname' ...
If you set "TMPDIR" in unshare mode, then the unshared user must be able to access the directory. This means that the directory itself must be world-writable and all its ancestors must be at least world-executable.
Since "TMPDIR" is only valid outside the chroot, the variable is being unset when running hook scripts. If you need a valid temporary directory in a hook, consider using /tmp inside your target directory.
This section lists some differences to debootstrap.
Limitations in comparison to debootstrap:
--second-stage, --exclude, --resolve-deps, --force-check-gpg, --merged-usr and --no-merged-usr
mmdebstrap will create a merged-/usr chroot or not depending on whether packages setting up merged-/usr (i.e. the usrmerge package) are installed or not. In Debian, the essential package init-system-helpers depends on the usrmerge package, starting with Debian 12 (Bookworm).
Before Debian 12 (Bookworm), to force mmdebstrap to create a chroot with merged-/usr using symlinks, either explicitly install the usrmerge package:
--include=usrmerge
or setup merged-/usr using the debootstrap-method which takes care of the architecture specific symlinks and installs the usr-is-merged package.
--hook-dir=/usr/share/mmdebstrap/hooks/merged-usr
To force mmdebstrap to create a chroot without merged-/usr even after the Debian 12 (Bookworm) release, you can use the following hook:
--hook-dir=/usr/share/mmdebstrap/hooks/no-merged-usr
This will write "this system will not be supported in the future" into /etc/unsupported-skip-usrmerge-conversion inside the chroot and install the usr-is-merged package to avoid the installation of the usrmerge package and its dependencies.
If you are using mmdebstrap in a setup where you do not know upfront whether the chroot you are creating should be merged-/usr or not and you want to avoid installation of the usrmerge package and it's dependencies, you can use:
--hook-dir=/usr/share/mmdebstrap/hooks/maybe-merged-usr
That hook will use the availability of the usr-is-merged package to decide whether to call the merged-usr hook or not.
mmdebstrap will choose a suitable compressor for the output tarball depending on the filename extension. The following mapping from filename extension to compressor applies:
extension compressor -------------------- .tar none .gz gzip .tgz gzip .taz gzip .Z compress .taZ compress .bz2 bzip2 .tbz bzip2 .tbz2 bzip2 .tz2 bzip2 .lz lzip .lzma lzma .tlz lzma .lzo lzop .lz4 lz4 .xz xz .txz xz .zst zstd
To change compression specific options, either use the respecitve environment variables like XZ_OPT or send mmdebstrap output to your compressor of choice with a pipe.
debvm helps create and run virtual machines for various Debian releases and architectures. The tool debvm-create can be used to create a virtual machine image and the tool debvm-run can be used to run such a machine image. Their purpose primarily is testing software using qemu as a containment technology. These are relatively thin wrappers around mmdebstrap and qemu.
bdebstrap is a YAML config based multi-mirror Debian chroot creation tool. bdebstrap is an alternative to debootstrap and a wrapper around mmdebstrap to support YAML based configuration files. It inherits all benefits from mmdebstrap. The support for configuration allows storing all customization in a YAML file instead of having to use a very long one-liner call to mmdebstrap. It also layering multiple customizations on top of each other, e.g. to support flavors of an image.
https://gitlab.mister-muffin.de/josch/mmdebstrap/issues
https://bugs.debian.org/src:mmdebstrap
As of version 1.20.9, dpkg does not provide facilities preventing it from reading the dpkg configuration of the machine running mmdebstrap. Therefore, until this dpkg limitation is fixed, a default dpkg configuration is recommended on machines running mmdebstrap. If you are using mmdebstrap as the non-root user, then as a workaround you could run "chmod 600 /etc/dpkg/dpkg.cfg.d/*" so that the config files are only accessible by the root user. See Debian bug #808203.
With apt versions before 2.1.16, setting "[trusted=yes]" or "Acquire::AllowInsecureRepositories "1"" to allow signed archives without a known public key or unsigned archives will fail because of a gpg warning in the apt output. Since apt does not communicate its status via any other means than human readable strings, and because mmdebstrap wants to treat transient network errors as errors, mmdebstrap treats any warning from "apt-get update" as an error.
debootstrap(8), debvm(1), bdebstrap(1)
2024-02-26 | perl v5.38.2 |