What is simple-cdd

As you can read here, simple-cdd simply is a limited, though relatively easy to use tool to create a customized DebianInstaller CD.

It is a wrapper around debian-cd and mirroring tools used to create a customized DebianInstaller CD image. It takes a list of packages to install, and debconf pre-seeding files to pre-configure the installation. It has some support for multiple profiles and custom post-install scripts for things that can't be configured by debconf preseeding.

Mind your goal before start

Before provisioning an entire server farm, you should be well prepared on what your machines are going to do.

It is easy to underestimate the work needed to empower a consistent infrastructure and the more work you do before, the less pain you will encounter while deploying all together.

When you shouldn't use simple-cdd

If you have to handle web services and some simple server, this could be something too much for you. You can easily handle what you want with Docker or creating templates with your VM manager, like Proxmox does.

So you need simple-cdd, huh?

Good to know you are still interested. Let's see in detail what this tool, can do and how to achieve some simple goals.


  • a customized Debian ISO with no questions during the install process
  • a template which installs MongoDB automatically
  • a second template which installs Docker automatically

These goals are very easy but let me to introduce you the pros and cons.


You are going to need a fresh installed Debian, version 8 at the time of writing. After you have net-installed with nothing but an ssh server, you are almost ready.

# install simple-cdd
sudo apt-get update && sudo apt-get install -y simple-cdd

# cd ~
mkdir -p cdd/profiles && cd cdd

# create a fresh iso, is easy as typing

How it works

In the folder we just created (~/cdd) we are going to save everything we need to create our ISO. The folder ~/cdd/profiles will contain our profiles, divided into two file kind: *.preseed*.postinst and *.packages.

Keep in mind if profile named default exists, it will be installed with no questions, without any other profile, so this is what we are not going to do, since we want to choose what to install.


a simple text file with a package we want to be installed in every line


a file, formatted with the standard rules defined here.


an executable file, executed at the end of the installation process, as root in the installed system.

First profile

Let's create a very simple profile. This profile will install nano if chosen.

echo "nano" > profiles/test.packages  
build-simple-cdd --profiles test  

This will take a lot of time, depending on your internet connection. At the end, in the folder ./images a iso will be ready to burn.

Mount the iso into a VM manager like VirtualBox or Proxmox.
The installer will ask you to select, if you want, a profile to install. Obviously we try our test profile. After the VM is installed, simply try typing nano --version.

No questions during the install process

You know how much boring is to install so many VM, each with the very same configuration. The same keyboard layout, the same timezone. The preseed files are going to help us.

Here I am downloading the example preseed file from debian official website.

curl https://www.debian.org/releases/jessie/example-preseed.txt > profiles/test.preseed

nano profiles/test.preseed  

Many params are in this file. Many can be ignored but we need to uncomment at least these (values for an italian Keyboard and timezone). With this file, nothing will be requested during the installation.

### Localization
# Preseeding only locale sets language, country and locale.
d-i debian-installer/locale string en_US

# The values can also be preseeded individually for greater flexibility.
d-i debian-installer/language string en  
d-i debian-installer/country string IT  
d-i debian-installer/locale string en_US.UTF-8

# Keyboard selection.
d-i keyboard-configuration/xkb-keymap select it

# netcfg will choose an interface that has link if possible. This makes it
# skip displaying a list if there is more than one interface.
d-i netcfg/choose_interface select auto

# Any hostname and domain names assigned from dhcp take precedence over
# values set here. However, setting the values still prevents the questions
# from being shown, even if values come from dhcp.
d-i netcfg/get_hostname string unknown  
d-i netcfg/get_domain string brugnara.me

# Disable that annoying WEP key dialog.
d-i netcfg/wireless_wep string

# This may be unwanted if using VM standard netcard
# If non-free firmware is needed for the network or other hardware, you can
# configure the installer to always try to load it, without prompting. Or
# change to false to disable asking.
d-i hw-detect/load_firmware boolean true

### Mirror settings (selecting httpredir as hostname, the Country doesn't matter)
# If you select ftp, the mirror/country string does not need to be set.
#d-i mirror/protocol string ftp
d-i mirror/country string Austria  
d-i mirror/http/hostname string httpredir.debian.org  
d-i mirror/http/directory string /debian  
d-i mirror/http/proxy string

### Account setup
# Skip creation of a root account (normal user account will be able to
# use sudo).
d-i passwd/root-login boolean false

# Root password, either in clear text
d-i passwd/root-password password Pa$$w0rd!RT!  
d-i passwd/root-password-again password Pa$$w0rd!RT!

# To create a normal user account.
d-i passwd/user-fullname string Devops  
d-i passwd/username string devops  
# Normal user's password, either in clear text
d-i passwd/user-password password Dev0ps  
d-i passwd/user-password-again password Dev0ps

### Clock and time zone setup
# Controls whether or not the hardware clock is set to UTC.
d-i clock-setup/utc boolean true

# You may set this to any valid setting for $TZ; see the contents of
# /usr/share/zoneinfo/ for valid values.
d-i time/zone string Europe/Rome

# Controls whether to use NTP to set the clock during the install
d-i clock-setup/ntp boolean true

### Partitioning
## Partitioning example
# If the system has free space you can choose to only partition that space.
# This is only honoured if partman-auto/method (below) is not set.
d-i partman-auto/init_automatically_partition select biggest_free  
d-i partman-auto/method string lvm

# If one of the disks that are going to be automatically partitioned
# contains an old LVM configuration, the user will normally receive a
# warning. This can be preseeded away...
d-i partman-lvm/device_remove_lvm boolean true  
# The same applies to pre-existing software RAID array:
d-i partman-md/device_remove_md boolean true  
# And the same goes for the confirmation to write the lvm partitions.
d-i partman-lvm/confirm boolean true  
d-i partman-lvm/confirm_nooverwrite boolean true

# You can choose one of the three predefined partitioning recipes:
# - atomic: all files in one partition
# - home:   separate /home partition
# - multi:  separate /home, /var, and /tmp partitions
d-i partman-auto/choose_recipe select multi

# This makes partman automatically partition without confirmation.
d-i partman-md/confirm boolean true  
d-i partman-partitioning/confirm_write_new_label boolean true  
d-i partman/choose_partition select finish  
d-i partman/confirm boolean true  
d-i partman/confirm_nooverwrite boolean true

### Apt setup
# Select which update services to use; define the mirrors to be used.
# Values shown below are the normal defaults.
d-i apt-setup/services-select multiselect security, updates  
d-i apt-setup/security_host string security.debian.org

# Individual additional packages to install
d-i pkgsel/include string openssh-server build-essential python git ntp curl  
# Whether to upgrade packages after debootstrap.
# Allowed values: none, safe-upgrade, full-upgrade
d-i pkgsel/upgrade select none

# Some versions of the installer can report back on what software you have
# installed, and what software you use. The default is not to report back,
# but sending reports helps the project determine what software is most
# popular and include it on CDs.
popularity-contest popularity-contest/participate boolean true

# This is fairly safe to set, it makes grub install automatically to the MBR
# if no other operating system is detected on the machine.
d-i grub-installer/only_debian boolean true

# This one makes grub-installer install to the MBR if it also finds some other
# OS, which is less safe as it might not be able to boot that other OS.
d-i grub-installer/with_other_os boolean true

# Due notably to potential USB sticks, the location of the MBR can not be
# To install to the first device (assuming it is not a USB stick):
d-i grub-installer/bootdev  string default

# Optional password for grub, either in clear text
d-i grub-installer/password password !r00tme  
d-i grub-installer/password-again password !r00tme

# Avoid that last message about the install being complete.
d-i finish-install/reboot_in_progress note

# This will prevent the installer from ejecting the CD during the reboot,
# which is useful in some situations.
d-i cdrom-detect/eject boolean true  

Rebuild the iso:

# since we didn't added any packages, we can skip recreating the mirror
build-simple-cdd --profiles test --no-do-mirror  

Mount the iso and check everything is working as expected. You can change any param in that file, as requested by you.

Let's customize more

So you want to do something more, uh? What about installing MongoDB?

echo '  
apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 0C49F3730359A14518585931BC711F9BA15703C6

echo "deb http://repo.mongodb.org/apt/debian jessie/mongodb-org/3.4 main" | tee /etc/apt/sources.list.d/mongodb-org-3.4.list

apt-get update

apt-get install -y mongodb-org-server  
service mongod start

# start on boot
systemctl enable mongod.service  
' > profiles/mongodb.postinst && chmod +x $_

build-simple-cdd --profiles "test,mongodb" --no-do-mirror  


I prefer put the cdd build conf into a separate file, as you can see the --profiles flag becomes something to remember when you build your iso.

echo '  
' > cdd.conf

# we keep the flag --no-do-mirror out of the conf because we are likely going to not use it while creating new profiles with new packages which needs to be downloaded.
echo "build-simple-cdd --conf ./cdd.conf --no-do-mirror" > build.sh  
echo "build-simple-cdd --conf ./cdd.conf" > full-build.sh

chmod +x build.sh full-build.sh



In this part we are going to see, how powerful profiles are.

echo "  
" > profiles/docker.packages

echo '  
curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add -  
echo  "deb https://download.docker.com/linux/debian jessie stable" > /etc/apt/sources.list.d/docker.list

apt-get update  
apt-get -y install docker-ce

service docker start

# enable docker to non root user
groupadd docker  
usermod -aG docker devops

# start on boot
systemctl enable docker  
' > profiles/docker.postinst

# build and test
# add docker to profiles list in cdd.conf and then

Combine profiles

You can create as many profiles you want and use in a combination while installing your machines. In my case, I have a base profile with all the things we need and profiles like mongodb or docker, to finish the customization of a ready machine.


As you can easily backup the profiles folder, you can easily recreate your machines.


Preparing a good machine is the key. The goal is to don't have the need to enter as root into the machines, so in our base profile, the last executed command is apt-get remove --purge sudo so the machine is not editable. This prevent to lose some configuration done on the machine and not documented, as always happens...


You may want to rename your host or simply set an IP. For us, the best solution, is a DHCP server, also able to set the hostname, as argued here.

Enjoy this wonderful and now well documented, tool!