Install Debian sans les mains (presque)

Donc, une installation de Debian (presque) sans les mains, ça vous paraît impossible? C’est pourtant ce que permet l’installeur Debian (d-i) grâce à sa fonction de preseeding.

Personnellement, je m’en sers pour aller vite sur la partie pas drôle de l’installation d’un nouveau serveur: installation et configuration de base (jusqu’à la conf du shell et des outils de base).

Prérequi: mon article “Install Debian 100% réseau

Attention: Avec ce qui est décrit là, vous ruinez le disque de la machine que vous réinstallez (on flingue la table de partition – et tout ou partie des données – et on recommence au propre).

Pour les impatients, voir l’exemple d’utilisation 😉

Le preseed, c’est quoi? Ça permet quoi?

Pour faire simple, c’est un fichier texte qui contient une bonne partieª des questions que pose d-i et des réponses qui vont avec. En disant à d-i d’utiliser un tel fichier, il ne pose (normalement) plus de questions. La mise en place du fichier peut s’avérer assez fastidieuse: on peut include des scripts et d’autres fichiers de preseed, on peut définir des classes d’installations (pour aller plus loin que juste un système de base), on peut définir des partitionnement avec RAID soft, LVM et partitions cryptées…

Dans ce post, je présente un cas relativement simple pour se faire une idée (et qui répond à mon besoin).

[a] en fait, toutes les questions où l’on sait que l’on répond toujours pareil 🙂

Mise en place dans le bazare netboot/PXE:

Il suffit de modifier le fichier pxelinux.cfg/default comme suit:

prompt 1
timeout 180
display boot.msg

default rescue64

[...]

label auto64
    kernel debian-installer/amd64/linux
    append auto=true vga=788 priority=critical preseed/url=http://install.dummy.net/preseed.cfg netcfg/disable_dhcp=true netcfg/use_autoconfig=true initrd=debian-installer/amd64/initrd.gz -- quiet

On notera que par défaut on boot sur un système de secours (rescue64), histoire qu’une machine mal configurée ne se réinstalle pas en boucle, et qu’on se laisse tout de même 3 minutes pour taper nos 5 paramètres pour l’installation (et encore, si on veut que le système final se configure via le DHCP, on a même pas besoin de ces paramètres).

On peut aussi décider d’embarquer le fichier preseed.cfg dans d-i en buildant une image personnalisée de l’installeur Debian. Il est aussi possible d’utiliser le preseed pour une installation depuis un CD ou une clé USB.

Le fichier de preseed:

Voilà, brut de décoffrage, mon fichier de preseed quasi-standard.

Attention: Quand on démarre d-i avec ça, on détruit tout ou partie des données présentes sur la machine (et les données pas détruites seront pas faciles à récupérer!).

#### Contents of the preconfiguration file (for wheezy)

### Set language, country and keyboard type
d-i debian-installer/language string en
d-i debian-installer/country string FR
d-i debian-installer/locale string en_US.UTF-8
d-i console-tools/archs select at
d-i console-keymaps-at/keymap select us
d-i keyboard-configuration/xkb-keymap select us

### Network configuration
# enable network configuration
d-i netcfg/enable boolean true
# let d-i choose the first available interface (ie. interface with link)
d-i netcfg/choose_interface select auto
# d-i has 10sec to detect the link
d-i netcfg/link_detection_timeout string 10
# don't ask for confimration
d-i netcfg/confirm_static boolean true

# detect if extra firmware is needed
d-i hw-detect/load_firmware boolean true

### Network console
# Use the following settings if you wish to make use of the network-console
# component for remote installation over SSH. This only makes sense if you
# intend to perform the remainder of the installation manually.
#d-i anna/choose_modules string network-console
#d-i network-console/authorized_keys_url string http://10.0.0.1/openssh-key
#d-i network-console/password password r00tme
#d-i network-console/password-again password r00tme

### Debian mirror settings
d-i mirror/country string manual
d-i mirror/http/hostname string ftp.fr.debian.org
d-i mirror/http/directory string /debian
# don't use a proxy. you may add one here:
d-i mirror/http/proxy string
# suite to install (stable/testing/unstable)
d-i mirror/suite string stable
d-i mirror/udeb/suite string stable

### Account setup
# We don't allow root login, we prefer admin user to use 'sudo'
d-i passwd/root-login boolean false
d-i passwd/make-user boolean true
d-i passwd/user-fullname string Default admin user
d-i passwd/username string admin
# admin's password is change-me
d-i passwd/user-password password change-me
d-i passwd/user-password-again password change-me
# we force admin's uid to be 1000
d-i passwd/user-uid string 1000
d-i passwd/user-default-groups string adm

### Clock and time zone setup
d-i clock-setup/utc boolean true
d-i time/zone string Europe/Paris
d-i clock-setup/ntp boolean true
d-i clock-setup/ntp-server string X.Y.Z.N

### Partitioning
# WARNING: this will delete all existing partitionning (and part of the data) of the selected disk
# Nota: you may override the disk name at boot time with d-i parameter partman-auto/diks=/dev/...
d-i partman-auto/disk string /dev/sda
# we choose a home made partition scheme (regular), check the official doc for RAID/LVM/CRYPTO
d-i partman-auto/method string regular
d-i partman-lvm/device_remove_lvm boolean true
d-i partman-md/device_remove_md boolean true
d-i partman-lvm/confirm boolean true
d-i partman-lvm/confirm_nooverwrite boolean true
# /dev/sda will be partitionned like this:
# #: mount    size      fs    prim? bootable?   fs options
# 1: /boot    150MB    ext2    p     b         noexec,nodev,nosuid
# 5: swap     1GB      swap    l
# 6: /        5GB      ext3    l               relatime,user_xattr
# 7: /tmp     1GB      ext4    l               nodev,nosuid,noatime
# 6: /var/log 1GB      ext3    l               nodev,nosuid,noexec,noatime
d-i partman-auto/expert_recipe string                         \
      boot-root ::                                            \
              150 150 150 ext2                                \
                      $primary{ }                             \
                      $bootable{ }                            \
                      method{ format } format{ }              \
                      use_filesystem{ } filesystem{ ext2 }    \
                      mountpoint{ /boot }                     \
                      label { /boot }                         \
                      option/nodev{ nodev }                   \
                      option/noexec{ noexec }                 \
                      option/nosuid{ nosuid }                 \
              .                                               \
              1024 1024 1024 linux-swap                       \
                      method{ swap } format{ }                \
                      label{ swap }                           \
              .                                               \
              5120 5120 5120  ext3                            \
                      method{ format } format{ }              \
                      use_filesystem{ } filesystem{ ext3 }    \
                      mountpoint{ / }                         \
                      label{ / }                              \
                      option/relatime{ relatime }             \
                      option/user_xattr{ user_xattr }         \
              .                                               \
              1024 1024 1024 ext4                             \
                      method{ format } format{ }              \
                      use_filesystem{ } filesystem{ ext4 }    \
                      mountpoint{ /tmp }                      \
                      label{ /tmp }                           \
                      option/nodev{ nodev }                   \
                      option/noexec{ noexec }                 \
                      option/nosuid{ nosuid }                 \
                      option/noatime{ noatime }               \
              .                                               \
              1024 1024 1024 ext3                             \
                      method{ format } format{ }              \
                      use_filesystem{ } filesystem{ ext3 }    \
                      mountpoint{ /var/log }                  \
                      label{ /var/log }                       \
                      option/nodev{ nodev }                   \
                      option/noexec{ noexec }                 \
                      option/nosuid{ nosuid }                 \
                      option/noatime{ noatime }               \
             .
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
# fstab will use UUIDs (alternatives: traditional, lalbel)
d-i partman/mount_style select uuid

### Base system installation
d-i base-installer/install-recommends boolean false
## kernel
# meta package:
d-i base-installer/kernel/image string linux-image-amd64
# or specific kernel
#d-i base-installer/kernel/image string linux-image-3.2.0-4-amd64
## Apt setup
d-i apt-setup/non-free boolean true
d-i apt-setup/contrib boolean true
d-i apt-setup/use_mirror boolean true
d-i apt-setup/services-select multiselect security, updates
d-i apt-setup/security_host string security.debian.org
# Additional repositories, local[0-9] available
#d-i apt-setup/local0/repository string \
#       http://local.server/debian stable main
#d-i apt-setup/local0/comment string local server
# Enable deb-src lines
#d-i apt-setup/local0/source boolean true
#d-i apt-setup/local0/key string http://local.server/key
#d-i debian-installer/allow_unauthenticated boolean true
## Package selection
# some choices standard, web-server, openssh-server, ...
# install nothing (almost)
tasksel tasksel/first multiselect none
# Individual additional packages to install - none, done in postinst after config of apt/dpkg
#d-i pkgsel/include string openssh-server ...
# Whether to upgrade packages after debootstrap. - nope, done in postinst...
# Allowed values: none, safe-upgrade, full-upgrade
d-i pkgsel/upgrade select none
# disable popularity contest
popularity-contest popularity-contest/participate boolean false

### Finishing up the installation
# 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
d-i cdrom-detect/eject boolean false
# system will reboot when install is over, you may prefer to halt it:
#d-i debian-installer/exit/halt boolean true
# or power off:
#d-i debian-installer/exit/poweroff boolean true

### Running custom commands after the installation
d-i preseed/late_command string \
    cd /target/root; \
    wget -q -O postinst.sh http://install.dummy.net/postinst.sh; \
    chmod 0700 postinst.sh; \
    in-target bash /root/postinst.sh

Un peu de hors-sujet: on peut faire un fichier de preseed en s’arrêtant après la section “Network console” (et en la décommentant), ça permet de démarrer automatiquement sur la machine sur la console d’installation via SSH (ce qui peut-être aussi assez pratique).

Le script de post-installation (appelé à la fin de l’installation de base par le d-i):

À la fin du fichier de preseed, on voit que d-i télécharge un script postinst.sh dans le /root du système fraichement installé et l’exécute. En voici une version courte:

#!/bin/bash

echo "### Post-install"

cd /

N=`date +%F`
H=`hostname -s`
I=`hostname -i`
F=`hostname -f`

echo "## APT"
echo "# Configure..."
cat > /etc/apt/sources.list <<EOF
deb http://ftp.fr.debian.org/debian/ wheezy main non-free contrib
#deb-src http://ftp.fr.debian.org/debian/ wheezy main non-free contrib
EOF
cat > /etc/apt/sources.list.d/deb_updates.list <<EOF
# wheezy-updates, previously known as 'volatile'
deb http://ftp.fr.debian.org/debian/ wheezy-updates main contrib non-free
#deb-src http://ftp.fr.debian.org/debian/ wheezy-updates main contrib non-free
EOF
cat > /etc/apt/sources.list.d/deb_secu.list <<EOF
deb http://security.debian.org/ wheezy/updates main contrib non-free
#deb-src http://security.debian.org/ wheezy/updates main contrib non-free
EOF
cat > /etc/apt/apt.conf.d/10norecommends <<EOF
APT::Install-Recommends "0";
EOF
cat > /etc/apt/apt.conf.d/10nosuggests <<EOF
APT::Install-Suggests "0";
EOF
echo "# Update package list..."
aptitude update
echo "# Upgrade installed packages..."
aptitude -y safe-upgrade
echo "# Install a few useful packages..."
aptitude -y install vim-nox sudo screen inetutils-telnet ntpdate bsd-mailx logrotate multitail tcpdump nmap lsof ssmtp bind9-host atop htop iptraf psmisc less mlocate mtr python rsync unzip dnsutils whois cron-apt geoip-database snmp snmpd openssh-server file lockfile-progs openssh-blacklist openssh-blacklist-extra logwatch

echo "## Sample bash config"
echo "# for 'root'"
cat > /root/.bashrc <<EOF
# ~/.bashrc: executed by bash(1) for non-login shells.
export LS_OPTIONS='--color=auto'
eval "\`dircolors\`"
alias ls='ls \$LS_OPTIONS'
alias ll='ls \$LS_OPTIONS -l'
alias l='ls \$LS_OPTIONS -lA'
alias grep="grep --color"
# Some more alias to avoid making mistakes:
alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'
# Prompt
case "\$TERM" in
xterm*|rxvt*)
    PS1="[\u@\h: \w]\\\$ "
    export PROMPT_COMMAND='echo -ne "\033]0;\${USER}@\${HOSTNAME}: \${PWD}\007"'
    ;;
screen)
    PS="[\u@\h: \w]\\\\$ "
    export PROMPT_COMMAND='echo -ne "\ek$(echo ${USER}@${HOSTNAME}: ${PWD/$HOME/\~})\e\\"'
    ;;
*)
    PS1="[\u@\h: \w]\\\$ "
    ;;
esac

# pour ne pas que dpkg soit gene par le noexec de /tmp
export TMPDIR="/var/tmp"
export PS1
EOF

echo "## for 'admin'..."
cat > /home/admin/.bashrc <<EOF
[ -z "\$PS1" ] && return
export HISTCONTROL=\$HISTCONTROL\${HISTCONTROL+,}ignoredups
export HISTCONTROL=ignoreboth
shopt -s histappend
shopt -s checkwinsize

case "\$TERM" in
xterm*|rxvt*)
    PS1="[\u@\h: \w]\\\$ "
    export PROMPT_COMMAND='echo -ne "\033]0;\${USER}@\${HOSTNAME}: \${PWD}\007"'
    ;;
screen)
    PS="[\u@\h: \w]\\\\$ "
    export PROMPT_COMMAND='echo -ne "\ek$(echo ${USER}@${HOSTNAME}: ${PWD/$HOME/\~})\e\\"'
    ;;
*)
    PS1="[\u@\h: \w]\\\$ "
    ;;
esac
export PS1

if [ -x /usr/bin/dircolors ]; then
    eval "\`dircolors -b\`"
    alias ls='ls --color=auto --time-style=long-iso'
    alias grep='grep --color=auto'
    alias fgrep='fgrep --color=auto'
    alias egrep='egrep --color=auto'
fi
if [ -f /etc/bash_completion ]; then
    . /etc/bash_completion
fi
EOF
chown 1000:1000 /home/admin/.bashrc
chmod 0644 /home/admin/.bashrc

echo "## Vim"
cat > /etc/vim/vimrc.local <<EOF
syntax on
set hls
set showmatch
set laststatus=2
set modeline
set modelines=1
set title
EOF

echo "# SSMTP"
cat > /etc/ssmtp/ssmtp.conf <<EOF
root=user@gmail.com
mailhub=smtp.gmail.com:587
rewriteDomain=
FromLineOverride=YES
hostname=user@gmail.com
UseSTARTTLS=YES
AuthUser=user@gmail.com
AuthPass=Pa55w0rd
EOF
cat > /etc/ssmtp/revaliases <<EOF
root:user@gmail.com:smtp.gmail.com:587
admin:user@gmail.com:smtp.gmail.com:587
EOF

echo "# Cron-APT"
cat > /etc/cron-apt/config <<EOF
APTCOMMAND=/usr/bin/aptitude
MAILON="upgrade"
SYSLOGON="error"
DIFFONCHANGES=prepend
EOF
cat > /etc/cron-apt/action.d/3-download <<EOF
autoclean -y
safe-upgrade -d -y -o APT::Get::Show-Upgraded=true -o quiet=2
EOF
cat > /etc/cron-apt/action.d/0-update <<EOF
update -o quiet=2
EOF

echo "# Cron"
cat > /etc/cron.d/perso <<EOF
0 0    * * *    root    /usr/sbin/logrotate /etc/logrotate.conf > /dev/null 2> /dev/null || /bin/true
59 23  * * *    root    /usr/sbin/logwatch --mailto user@gmail.com --output mail > /dev/null 2> /dev/null || /bin/true
EOF
chmod 0755 /etc/cron.d/tfb

echo -e '#!/bin/sh\nexit 0' > /etc/cron.daily/logrotate
chmod 0444 /etc/cron.daily/logrotate
echo -e '#!/bin/sh\nexit 0'> /etc/cron.daily/00logwatch
chmod 0444 /etc/cron.daily/00logwatch

echo "# Default editor/pager"
update-alternatives --set editor /usr/bin/vim.nox
update-alternatives --set pager /bin/less
echo "# Disable some needless services"
for s in atop  mpt-statusd  rsync
do
    echo -n "## disable $s... "
    update-rc.d $s disable &> /dev/null
    if [ $? -eq 0 ]
    then
        echo OK
    else
        echo KO
    fi
done

echo "*** DONE ***"

Exemple d’utilisation:

À l’invite de boot on précise tout ça:

boot: auto64 netcfg/get_ipaddress=x.y.z.t/m netcfg/get_gateway=x.y.z.g netcfg/get_nameservers=x.y.z.d netcfg/get_hostname=my-host netcfg/get_domain=dummy.net

Normalement, c’est la seule fois de l’installation où on touche au clavier.

boot prompt

boot prompt

Maintenant, on part tranquillement se préparer un bon goûter (ou juste un café). Quand on revient, la machine a rebooté et son invite de login nous attend:

system/login prompt

system/login prompt

Pour aller plus loin:

 

One thought on “Install Debian sans les mains (presque)

Comments are closed.