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.
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 any mirror contains a https URI, then the packages
apt-transport-https and ca-certificates will be installed inside the chroot.
If any mirror contains a tor+xxx URI, then the apt-transport-tor package
will be installed inside the chroot.
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. If mmdebstrap is instructed to retrieve packages from
multiple releases, then 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.
- -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, proot 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, and ext2. 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"'
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. By default,
/etc/apt/trusted.gpg and /etc/apt/trusted.gpg.d are used.
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://..."
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.
- --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.*'
--dpkgopt='path-exclude=/usr/share/{doc,info,man,omf,help,gnome/help}/*'
- --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. The
essential variant does not include apt and thus, the include option
will only work when the chrootless mode is selected and thus apt
from the outside can be used. Package names are directly passed to apt and
thus, you can use apt features like
"pkg/suite",
"pkg=version",
"pkg-" or use a glob or regex for
"pkg". 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-
- --components=comp1[,comp2,...]
- Comma or whitespace separated list of components like main, contrib and
non-free 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"
--components=main,contrib,non-free
--comp=main --comp="contrib non-free" --comp="main,non-free"
- --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 merged-/usr via symlinks
--setup-hook='for d in bin sbin lib; do ln -s usr/$d "$1/$d";
mkdir -p "$1/usr/$d"; done'
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; 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"'
- 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" 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
"setup01-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: Run mmdebstrap with eatmydata
--hook-dir=/usr/share/mmdebstrap/hooks/eatmydata
- --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.
- -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 the system has the sysctl
"kernel.unprivileged_userns_clone" set
to 1. Should that not be the case and if the
fakechroot binary exists, the fakechroot mode is chosen. Lastly,
the proot mode is used if the proot binary exists.
- 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
- 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 should be bit-by-bit
identical to a tarball created with the root mode. In Debian, this
mode requires the sysctl
"kernel.unprivileged_userns_clone" being
set to 1. The default used to be
0 but was changed to 1
with linux 5.10.1 or Debian 11 (Bullseye). SETTING THIS OPTION TO 1 HAS
SECURITY IMPLICATIONS. Refer to
<https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=898446>
A directory chroot created with this mode will end up with
wrong ownership information. 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. Since ldconfig cannot run under fakechroot, the final system will
not contain /etc/ld.so.cache. See the section LIMITATIONS in
fakechroot(1).
- proot
- This mode will carry out all calls to chroot with proot instead. Since
ownership information is only retained while proot is still running, this
will lead to wrong ownership information in the final directory
(everything will be owned by the user that executed mmdebstrap) and
tarball (everything will be owned by the root user). Extended attributes
are not retained. This mode is useful if you plan to use the chroot with
proot.
- 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.
Unless mmdebstrap was run inside fakeroot, the TARGET
directory will be owned by the user running mmdebstrap.
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. If
multiple releases are passed as apt sources to mmdebstrap, then the
release with a name matching the SUITE argument will be used to
determine the "Essential:yes" and priority
values.
- 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.
- required,
minbase
- The essential set plus all packages with Priority:required and
apt.
- buildd
- The minbase set plus build-essential.
- important,
debootstrap, -
- The required set plus all packages with Priority:important. This is
the default of debootstrap.
- standard
- The important set plus all packages with Priority:standard.
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
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 like
/dev/null, 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 ./-. Since
"tar2sqfs" does not support extended
attributes, the resulting image will not contain them.
- 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.
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. All environment variables
set by mmdebstrap (like
"APT_CONFIG",
"DEBIAN_FRONTEND",
"LC_ALL" and
"PATH") are preserved. All environment
variables set by the user are preserved, except for
"TMPDIR" which is cleared.
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 and proot 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 and
proot 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.
- 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.
This section gives an overview of the different steps to create a
chroot.
- 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
- if you are root, check whether you have the ability to mount. This check
requires the "unshare" program from the
"util-linux" package and can be disabled
by using --skip=check/canmount.
- 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
- setup
- The following tasks are carried out:
- 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.
- download
- Checks whether /var/cache/apt/archives/ is empty. This can be
disabled with --skip=download/empty. In the extract and
custom variants, "apt-get
--download-only 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 --download-only
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.
- Extract the downloaded packages into the rootfs. This step is not carried
out in chrootless mode if the variant is not extract.
- Run --extract-hook options and all extract* scripts in
--hook-dir.
- 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.
- 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.
- cleanup
- Performs cleanup tasks like:
- Removes the package lists and apt cache. This can be disabled 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 all files that make the result unreproducible, like apt and dpkg
logs and caches or /etc/machine-id. This can be disabled using
--skip=cleanup/reproducible
- 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
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, pipe the output of mmdebstrap into
tar2sqfs manually.
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 ext2 /dev/sda1 : \
set-label /dev/sda1 rootfs : mount /dev/sda1 / : \
tar-in debian-unstable.tar / xattrs:true : \
upload /usr/lib/SYSLINUX/mbr.bin /mbr.bin : \
copy-file-to-device /mbr.bin /dev/sda size:440 : rm /mbr.bin : \
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
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 console=ttyS0
END
$ guestfish -N debian-unstable.img=disk:8G -- \
part-disk /dev/sda mbr : \
part-set-bootable /dev/sda 1 true : \
mkfs ext2 /dev/sda1 : mount /dev/sda1 / : \
tar-in debian-unstable.tar / xattrs:true : \
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=download/empty --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
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
- "SOURCE_DATE_EPOCH"
- By setting "SOURCE_DATE_EPOCH" the
result will be reproducible over multiple runs with the same options and
mirror content.
- "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.
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, proot, unshare
- 3-6 times faster
- 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
- Some debootstrap options don't exist, namely:
--second-stage, --exclude,
--resolve-deps, --force-check-gpg, --merged-usr and
--no-merged-usr
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 --threads=0
.txz xz --threads=0
.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.19.5, 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.
Setting [trusted=yes] to allow signed archives without a known
public key 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, mmdebstrap treats any warning from "apt-get
update" as an error. Fixing this will require apt to provide a machine
readable status interface. See Debian bugs #778357, #776152, #696335, and
#745735.