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 dependencies. See section
OPERATION for
an overview of how
mmdebstrap works internally.
If no
MIRROR option is provided, <
http://deb.debian.org/debian> is
used. If
SUITE is a stable release name and no
MIRROR is
specified, then mirrors for updates and security are automatically added. If a
MIRROR option starts with "deb " or "deb-src " then
it is used as a one-line-style 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 pasted into the
chroot's sources.list. This can be used to supply a deb822 style sources.list.
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.
The optional
TARGET argument can 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 "-". Without the
--format option,
TARGET will be used to choose the format. See
the section
FORMATS for more information. If no
TARGET was
specified or if
TARGET is "-", an uncompressed tarball will
be sent to standard output.
The
SUITE may be a valid release code name (eg, sid, stretch, jessie) or
a symbolic name (eg, unstable, testing, stable, oldstable). Any suite name
that works with apt on the given mirror will work. If no
SUITE was
specified, then a single
MIRROR "-" is added and thus the
information of the desired suite has to come from standard input as part of a
valid apt sources.list file. 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. See the section
VARIANTS for more
information.
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.
- -h,--help
- Print synopsis and options of this man page and exit.
- --man
- Show the full man page as generated from Perl POD in a
pager. This requires the perldoc program from the perl-doc package. This
is the same as running:
pod2man /usr/bin/mmdebstrap | man -l -
- --version
- Print the mmdebstrap version and exit.
-
--variant=name
- Choose which package set to install. Valid variant
names are extract, custom, essential,
apt, required, minbase, buildd,
important, debootstrap, -, and standard. The
default variant is debootstrap. See the section VARIANTS for
more information.
-
--mode=name
- Choose how to perform the chroot operation and create a
filesystem with ownership information different from the current user.
Valid mode names are auto, sudo, root,
unshare, fakeroot, fakechroot and chrootless.
The default mode is auto. See the section MODES for more
information.
-
--format=name
- Choose the output format. Valid format names are
auto, directory, tar, squashfs, ext2
and null. The default format is auto. See the section
FORMATS for more information.
-
--aptopt=option|file
- Pass arbitrary options to apt. Will be permamently
added to /etc/apt/apt.conf.d/99mmdebstrap inside the chroot. Use
hooks for temporary configuration options. Can be specified multiple
times. Each option will be appended to 99mmdebstrap. A semicolon
will be added at the end of the option if necessary. If the command line
argument is an existing file, the content of the file will be
appended to 99mmdebstrap verbatim.
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"'
-
--keyring=file|directory
- Change the default keyring to use by apt during the initial
setup. This is similar to setting Dir::Etc::Trusted and
Dir::Etc::TrustedParts using --aptopt except that the latter
setting will be permanently stored in the chroot while the keyrings passed
via <--keyring> will only be visible to apt as run by
mmdebstrap. Do not use --keyring if apt inside the chroot
needs to know about your keys after the initial chroot creation by
mmdebstrap. This option is mainly intended for users who use
mmdebstrap as a deboostrap drop-in replacement. As such, it
is probably not what you want to use if you use mmdebstrap with
more than a single mirror unless you pass it a directory containing all
the keyrings you need.
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).
-
--dpkgopt=option|file
- Pass arbitrary options to dpkg. Will be permanently
added to /etc/dpkg/dpkg.cfg.d/99mmdebstrap inside the chroot. Use
hooks for temporary configuration options. Can be specified multiple
times. Each option will be appended to 99mmdebstrap. If the command
line argument is an existing file, the content of the file will be
appended to 99mmdebstrap verbatim.
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.*'
-
--include=pkg1[,pkg2,...]
- Comma or whitespace separated list of packages which will
be installed in addition to the packages installed by the specified
variant. The direct and indirect hard dependencies will also be installed.
The behaviour of this option depends on the selected variant. The
extract and custom variants install no packages by default,
so for these variants, the packages specified by this option will be the
only ones that get either extracted or installed by dpkg, respectively.
For all other variants, apt is used to install the additional packages.
Package names are directly passed to apt and thus, you can use apt
features like "pkg/suite", "pkg=version",
"pkg-", use a glob or regex for "pkg", use apt
patterns or pass a path to a .deb package file (see below for notes
concerning passing the path to a .deb package file in unshare
mode). See apt(8) for the supported syntax.
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=comp1[,comp2,...]
- Comma or whitespace separated list of components like main,
contrib, non-free and non-free-firmware which will be used for all
URI-only MIRROR arguments. The option can be specified multiple
times and the components 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 component list is free of duplicates. So the
following are equivalent:
--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=native[,foreign1,...]
- Comma or whitespace separated list of architectures. The
first architecture is the native architecture inside the chroot.
The remaining architectures will be added to the foreign dpkg
architectures. Without this option, the native architecture of the
chroot defaults to the native architecture of the system running
mmdebstrap. The option can be specified multiple times and values
are concatenated. If later list items are repeated, then they get dropped
so that the resulting list is free of duplicates. So the following are
equivalent:
--architectures="amd64 armhf mipsel"
--architectures=amd64,armhf,mipsel
--arch=amd64 --arch="armhf mipsel" --arch=armhf,mipsel
-
--simulate, --dry-run
- Run apt-get with --simulate. Only the package cache
is initialized but no binary packages are downloaded or installed. Use
this option to quickly check whether a package selection within a certain
suite and variant can in principle be installed as far as their
dependencies go. If the output is a tarball, then no output is produced.
If the output is a directory, then the directory will be left populated
with the skeleton files and directories necessary for apt to run in it. No
hooks are executed in with --simulate or --dry-run.
-
--setup-hook=command
- Execute arbitrary commands right after initial setup
(directory creation, configuration of apt and dpkg, ...) but before any
packages are downloaded or installed. At that point, the chroot directory
does not contain any executables and thus cannot be chroot-ed into. See
section HOOKS for more information.
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.
-
--extract-hook=command
- Execute arbitrary commands after the Essential:yes
packages have been extracted but before installing them. See section
HOOKS for more information.
Example: Install busybox symlinks
--extract-hook='chroot "$1" /bin/busybox --install -s'
-
--essential-hook=command
- Execute arbitrary commands after the Essential:yes
packages have been installed but before installing the remaining packages.
The hook is not executed for the extract and custom
variants. See section HOOKS for more information.
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'
-
--customize-hook=command
- Execute arbitrary commands after the chroot is set
up and all packages got installed but before final cleanup actions are
carried out. See section HOOKS for more information.
Example: Preparing a chroot for use with autopkgtest
--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
-
--hook-directory=directory
- Execute scripts in directory with filenames starting
with "setup", "extract", "essential" or
"customize", at the respective stages during an mmdebstrap run.
The files must be marked executable. Their extension is ignored.
Subdirectories are not traversed. This option is a short-hand for
specifying the remaining four hook options individually for each file in
the directory. If there are more than one script for a stage, then they
are added alphabetically. This is useful in cases, where a user wants to
run the same hooks frequently. For example, given a directory
"./hooks" with two scripts "setup01-foo.sh" and
"setup02-bar.sh", this call:
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
-
--skip=stage[,stage,...]
-
mmdebstrap tries hard to implement sensible defaults
and will try to stop you before shooting yourself in the foot. This option
is for when you are sure you know what you are doing and allows one to
skip certain actions and safety checks. See section OPERATION for a
list of possible arguments and their context. The option can be specified
multiple times or you can separate multiple values by comma or
whitespace.
-
-q,--quiet, -s,--silent
- Do not write anything to standard error. If used together
with --verbose or --debug, only the last option will take
effect.
- -v,--verbose
- Instead of progress bars, write the dpkg and apt output
directly to standard error. If used together with --quiet or
--debug, only the last option will take effect.
- -d,--debug
- In addition to the output produced by --verbose,
write detailed debugging information to standard error. Errors will print
a backtrace. If used together with --quiet or --verbose,
only the last option will take effect.
-
--logfile=filename
- Instead of writing status information to standard error,
write it into the file given by filename.
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.
- auto
- This mode automatically selects a fitting mode. If the
effective user id is the one of the superuser, then the sudo mode
is chosen. Otherwise, the unshare mode is picked if
/etc/subuid and /etc/subgid are set up correctly. Should
that not be the case and if the fakechroot binary exists, the
fakechroot mode is chosen.
-
sudo, root
- This mode directly executes chroot and is the same mode of
operation as is used by debootstrap. It is the only mode that can directly
create a directory chroot with the right permissions. If the chroot
directory is not accessible by the _apt user, then apt sandboxing will be
automatically disabled. This mode needs to be able to mount and thus
requires "SYS_CAP_ADMIN".
- unshare
- When used as a normal (not root) user, this mode uses Linux
user namespaces to allow unprivileged use of chroot and creation of files
that appear to be owned by the superuser inside the unshared namespace. A
tarball created in this mode will be bit-by-bit identical to a tarball
created with the root mode. With this mode, the only binaries that
will run as the root user will be newuidmap(1) and
newgidmap(1) via their setuid bit. Running those
successfully requires /etc/subuid and /etc/subgid to have an
entry for your username. This entry was usually created by
adduser (8) already.
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
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.
-
fakeroot, fakechroot
- This mode will exec mmdebstrap again under
"fakechroot fakeroot". A directory chroot created with this mode
will end up with wrong permissions. If you need a directory then run
mmdebstrap under "fakechroot fakeroot -s fakeroot.env"
and use "fakeroot.env" later when entering the chroot with
"fakechroot fakeroot -i fakeroot.env chroot ...". This mode will
not work if maintainer scripts are unable to handle "LD_PRELOAD"
correctly like the package initramfs-tools until version 0.132.
This mode will also not work with a different libc inside the chroot than
on the outside. See the section LIMITATIONS in
fakechroot (1).
- chrootless
- Uses the dpkg option "--force-script-chrootless"
to install packages into TARGET without dpkg and apt inside
TARGET but using apt and dpkg from the machine running
mmdebstrap. Maintainer scripts are run without chrooting into
TARGET and rely on their dependencies being installed on the
machine running mmdebstrap. Only very few packages support this
mode. Namely, as of 2022, not all essential packages support it. See
https://wiki.debian.org/Teams/Dpkg/Spec/InstallBootstrap or the
dpkg-root-support usertag of [email protected] in the Debian
bug tracking system. WARNING: if this option is used carelessly
with packages that do not support "DPKG_ROOT", this mode can
result in undesired changes to the system running mmdebstrap
because maintainer-scripts will be run without
chroot(1).
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.
- extract
- Installs nothing by default (not even
"Essential:yes" packages). Packages given by the
"--include" option are extracted but will not be installed.
- custom
- Installs nothing by default (not even
"Essential:yes" packages). Packages given by the
"--include" option will be installed. If another mode than
chrootless was selected and dpkg was not part of the included
package set, then this variant will fail because it cannot configure the
packages.
- essential
- "Essential:yes" packages.
- apt
- The essential set plus apt. This variant uses the
fact that apt treats itself as essential and thus running
"apt-get dist-upgrade" without any packages installed will
install the essential set plus apt. If you just want
essential and apt, then this variant is faster than using
the essential variant and adding apt via
"--include" because all packages get installed at once. The
downside of this variant is, that if it should happen that an
essential package is not installable, then it will just get ignored
without throwing an error.
-
required, minbase
- The essential set plus all packages with
Priority:required and apt. It is roughly equivalent to running mmdebstrap
with
--variant=essential --include="?priority(required)"
- buildd
- The minbase set plus build-essential. It is roughly
equivalent to running mmdebstrap with
--variant=essential --include="?priority(required),build-essential"
-
important, debootstrap, -
- The required set plus all packages with
Priority:important. This is the default of debootstrap. It is roughly
equivalent to running mmdebstrap with
--variant=essential --include="~prequired|~pimportant"
- standard
- The important set plus all packages with
Priority:standard. It is roughly equivalent to running mmdebstrap with
--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:
- auto
- When selecting this format (the default), the actual format
will be inferred from the TARGET positional argument. If
TARGET was not specified, then the tar format will be
chosen. If TARGET happens to be /dev/null or if standard
output is /dev/null, then the null format will be chosen. If
TARGET is an existing directory, and does not equal to
"-", then the directory format will be chosen. If
TARGET ends with ".tar" or with one of the filename
extensions listed in the section COMPRESSION, or if TARGET
equals "-", or if TARGET is a named pipe (fifo) or if
TARGET is a character special file, then the tar format will
be chosen. If TARGET ends with ".squashfs" or
".sqfs", then the squashfs format will be chosen. If
<TARGET> ends with ".ext2" then the ext2 format
will be chosen. If none of these conditions apply, the directory
format will be chosen.
-
directory, dir
- A chroot directory will be created in TARGET. If the
directory already exists, it must either be empty or only contain an empty
"lost+found" directory. The special TARGET "-"
does not work with this format because a directory cannot be written to
standard output. If you need your directory be named "-", then
just explicitly pass the relative path to it like ./-. If a
directory is chosen as output in any other mode than sudo, then its
contents will have wrong ownership information and special device files
will be missing. Refer to the section MODES for more
information.
- tar
- A temporary chroot directory will be created in $TMPDIR or
/tmp if $TMPDIR is not set. A tarball of that directory will be
stored in TARGET or sent to standard output if TARGET was
omitted or if TARGET equals "-". If TARGET ends
with one of the filename extensions listed in the section
COMPRESSION, then a compressed tarball will be created. The tarball
will be in POSIX 1003.1-2001 (pax) format and will contain extended
attributes. To preserve the extended attributes, you have to pass
--xattrs --xattrs-include='*' to tar when extracting the
tarball.
-
squashfs, sqfs
- A temporary chroot directory will be created in $TMPDIR or
/tmp if $TMPDIR is not set. A tarball of that directory will be
piped to the "tar2sqfs" utility, which will create an xz
compressed squashfs image with a blocksize of 1048576 bytes in
TARGET. The special TARGET "-" does not work with
this format because "tar2sqfs" can only write to a regular file.
If you need your squashfs image be named "-", then just
explicitly pass the relative path to it like ./-. The
"tar2sqfs" tool only supports a limited set of extended
attribute prefixes. Therefore, extended attributes are disabled in the
resulting image. If you need them, create a tarball first and remove the
extended attributes from its pax headers. Refer to the EXAMPLES
section for how to achieve this.
- ext2
- A temporary chroot directory will be created in $TMPDIR or
/tmp if $TMPDIR is not set. A tarball of that directory will be
piped to the "genext2fs" utility, which will create an ext2
image that will be approximately 90% full in TARGET. The special
TARGET "-" does not work with this format because
"genext2fs" can only write to a regular file. If you need your
ext2 image be named "-", then just explicitly pass the relative
path to it like ./-. To convert the result to an ext3 image, use
"tune2fs -O has_journal TARGET" and to convert it to ext4, use
"tune2fs -O extents,uninit_bg,dir_index,has_journal TARGET".
Since "genext2fs" does not support extended attributes, the
resulting image will not contain them.
- null
- A temporary chroot directory will be created in $TMPDIR or
/tmp if $TMPDIR is not set. After the bootstrap is complete, the
temporary chroot will be deleted without being part of the output. This is
most useful when the desired artifact is generated inside the chroot and
it is transferred using special hooks such as sync-out. It is also
useful in situations where only the exit code or stdout or stderr of a
process run in a hook is of interest.
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_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.
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.
-
copy-out pathinside [pathinside ...]
pathoutside
- Recursively copies one or more files and directories
recursively from pathinside inside the chroot to pathoutside
outside of the chroot.
-
copy-in pathoutside [pathoutside ...]
pathinside
- Recursively copies one or more files and directories into
the chroot into, placing them into pathinside inside of the
chroot.
-
sync-out pathinside pathoutside
- Recursively copy everything inside pathinside inside
the chroot into pathoutside. In contrast to copy-out, this
command synchronizes the content of pathinside with the content of
pathoutside without deleting anything from pathoutside but
overwriting content as necessary. Use this command over copy-out if
you don't want to create a new directory outside the chroot but only
update the content of an existing directory.
-
sync-in pathoutside pathinside
- Recursively copy everything inside pathoutside into
pathinside inside the chroot. In contrast to copy-in, this
command synchronizes the content of pathoutside with the content of
pathinside without deleting anything from pathinside but
overwriting content as necessary. Use this command over copy-in if
you don't want to create a new directory inside the chroot but only update
the content of an existing directory.
-
tar-in outside.tar pathinside
- Unpacks a tarball outside.tar from outside the
chroot into a certain location pathinside inside the chroot.
-
tar-out pathinside outside.tar
- Packs the path pathinside from inside the chroot
into a tarball, placing it into a certain location outside.tar
outside the chroot.
-
download fileinside fileoutside
- Copy the file given by fileinside from inside the
chroot to outside the chroot as fileoutside. In contrast to
copy-out, this command only handles files and not directories. To
copy a directory recursively out of the chroot, use copy-out or
tar-out. Its advantage is, that by being able to specify the full
path on the outside, including the filename, the file on the outside can
have a different name from the file on the inside. In contrast to
copy-out and tar-out, this command follows symlinks.
-
upload fileoutside fileinside
- Copy the file given by fileoutside from outside the
chroot to inside the chroot as fileinside. In contrast to
copy-in, this command only handles files and not directories. To
copy a directory recursively into the chroot, use copy-in or
tar-in. Its advantage is, that by being able to specify the full
path on the inside, including the filename, the file on the inside can
have a different name from the file on the outside. In contrast to
copy-in and tar-in, permission and ownership information
will not be retained.
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.
- check
- Upon startup, several checks are carried out, like:
- •
- whether required utilities (apt, dpkg, tar) are
installed
- •
- which mode to use and whether prerequisites are met
- •
- whether the requested architecture can be executed
(requires arch-test) using qemu binfmt_misc support. This requires
arch-test and can be disabled using --skip=check/qemu
- •
- how the apt sources can be assembled from SUITE,
MIRROR and --components and/or from standard input as deb822
or one-line format and whether the required GPG keys exist.
- •
- which output format to pick depending on the
--format argument or name of TARGET or its type.
- •
- whether the output directory is empty. This check can be
disabled using --skip=check/empty
- •
- whether adding a "signed-by" to
"apt/sources.list" is necessary. This requires gpg and can be
disabled using --skip=check/signed-by
- setup
- The following tasks are carried out unless
--skip=setup is used:
- •
- create required directories
- •
- write out the temporary apt config file
- •
- populates /etc/apt/apt.conf.d/99mmdebstrap and
/etc/dpkg/dpkg.cfg.d/99mmdebstrap with config options from
--aptopt and --dpkgopt, respectively
- •
- write out /etc/apt/sources.list
- •
- copy over /etc/resolv.conf and
/etc/hostname
- •
- populate /dev if mknod is possible
- setup-hook
- Run --setup-hook options and all setup*
scripts in --hook-dir.
- update
- Runs "apt-get update" using the temporary apt
configuration file created in the setup step. This can be disabled
using --skip=update.
- download
- In the extract and custom variants,
"apt-get install" is used to download all the packages requested
via the --include option. The apt variant uses the fact that
libapt treats the "apt" packages as implicitly essential to
download only all "Essential:yes" packages plus apt using
"apt-get dist-upgrade". In the remaining variants, all Packages
files downloaded by the update step are inspected to find the
"Essential:yes" package set as well as all packages of the
required priority. If SUITE is a non-empty string, then only
packages from the archive with suite or codename matching SUITE
will be considered for selection of "Essential:yes"
packages.
- mount
- Mount relevant device nodes, /proc and /sys
into the chroot and unmount them afterwards. This can be disabled using
--skip=chroot/mount or specifically by
--skip=chroot/mount/dev, --skip=chroot/mount/proc and
--skip=chroot/mount/sys, respectively. mmdebstrap will
disable running services by temporarily moving
/usr/sbin/policy-rc.d and /sbin/start-stop-daemon if they
exist. This can be disabled with --skip=chroot/policy-rc.d and
--skip=chroot/start-stop-daemon, respectively.
- extract
- Extract the downloaded packages into the rootfs.
- prepare
- In fakechroot mode, environment variables
"LD_LIBRARY_PATH" will be set up correctly. If the chroot
requires the qemu-user-static binary it will be copied in. For foreign
fakechroot environments, "LD_LIBRARY_PATH" and
"QEMU_LD_PREFIX" are set up accordingly. This step is not
carried out in extract mode and neither for the chrootless
variant.
- extract-hook
- Run --extract-hook options and all extract*
scripts in --hook-dir.
- essential
- Uses "dpkg --install" to properly install all
packages that have been extracted before. Removes all packages downloaded
in the download step, except those which were present in
/var/cache/apt/archives/ before (if any). This can be disabled
using --skip=essential/unlink. This step is not carried out in
extract mode.
- essential-hook
- Run --essential-hook options and all
essential* scripts in --hook-dir. This step is not carried
out in extract mode.
- install
- Install the apt package into the chroot, if necessary and
then run apt from inside the chroot to install all remaining packages.
This step is not carried out in extract mode.
- customize-hook
- Run --customize-hook options and all
customize* scripts in --hook-dir. This step is not carried
out in extract mode.
- unmount
- Unmount everything that was mounted during the mount
stage and restores /usr/sbin/policy-rc.d and
/sbin/start-stop-daemon if necessary.
- cleanup
- Performs cleanup tasks, unless --skip=cleanup is
used:
- •
- Removes the package lists (unless
--skip=cleanup/apt/lists) and apt cache (unless
--skip=cleanup/apt/cache). Both removals can be disabled by using
--skip=cleanup/apt.
- •
- Remove all files that were put into the chroot for setup
purposes, like /etc/apt/apt.conf.d/00mmdebstrap, the temporary apt
config and the qemu-user-static binary. This can be disabled using
--skip=cleanup/mmdebstrap.
- •
- Remove files that make the result unreproducible and write
the empty string to /etc/machine-id if it exists. This can be disabled
using --skip=cleanup/reproducible. Note that this will not remove
files that make the result unreproducible on machines with differing
/etc/resolv.conf or /etc/hostname. Use a
--customize-hook to make those two files reproducible across
multiple hosts. See section "SOURCE_DATE_EPOCH" for more
information. The following files will be removed:
- •
- /var/log/dpkg.log
- •
- /var/log/apt/history.log
- •
- /var/log/apt/term.log
- •
- /var/log/alternatives.log
- •
- /var/cache/ldconfig/aux-cache
- •
- /var/log/apt/eipp.log.xz
- •
- /var/lib/dbus/machine-id
- •
- Remove everything in /run inside the chroot. This
can be disabled using --skip=cleanup/run.
- •
- Remove everything in /tmp inside the chroot. This
can be disabled using --skip=cleanup/tmp.
For formats other than
directory, pack up the temporary chroot directory
into a tarball, ext2 image or squashfs image and delete the temporary chroot
directory.
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:
$ 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='env container=lxc 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 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 | mmtarfilter --path-exclude='/dev/*' > chroot.tar
[...]
$ mmdebstrap --variant=custom --skip=update \
--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 --setup-hook \
'mmtarfilter "--path-exclude=/dev/*" < chroot.tar | tar -C "$1" -x' \
--customize-hook='chroot "$1" apt-get install --yes pkg1 pkg2' \
'' chroot-full.tar
- "SOURCE_DATE_EPOCH"
- By setting "SOURCE_DATE_EPOCH" the result will be
reproducible across multiple runs with the same options and mirror
content. Note that for debootstrap compatibility, mmdebstrap will
copy the host's /etc/resolv.conf and /etc/hostname into the
chroot. This means that the mmdebstrap output will differ if it is
run on machines with differing /etc/resolv.conf and
/etc/hostname contents. To make the result reproducible across
different hosts, you need to manually either delete both files from the
output:
$ 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' ...
- "TMPDIR"
- When creating a tarball, a temporary directory is populated
with the rootfs before the tarball is packed. The location of that
temporary directory will be in /tmp or the location pointed to by
"TMPDIR" if that environment variable is set. Setting
"TMPDIR" to a different directory than /tmp is useful if
you have /tmp on a tmpfs that is too small for your rootfs.
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.
- •
- More than one mirror possible
- •
- Default mirrors for stable releases include updates and
security mirror
- •
- Multiple ways to operate as non-root: fakechroot and
unshare
- •
- twice as fast
- •
- Can create a chroot with only "Essential:yes"
packages and their deps
- •
- Reproducible output by default if $SOURCE_DATE_EPOCH is
set
- •
- Can create output on filesystems with nodev set
- •
- apt cache and lists are cleaned at the end
- •
- foreign architecture chroots using qemu-user
Limitations in comparison to debootstrap:
- •
- Only runs on systems with apt installed (Debian and
derivatives)
- •
- No SCRIPT argument (use hooks instead)
- •
- Some debootstrap options don't exist, namely:
--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.
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)