Installer Debian en CLI comme Archlinux

28 févr. 2023

RĂ©cemment j'ai voulu changer de serveur Kimsufi et passer sur une gamme plus importante. J'avais une machine avec 4 disques, j'ai donc initialement voulu faire un gros RAID 5. Sauf que le manager OVH m'envoyait valser sur l'installation de l'OS car la partition / devait ĂȘtre en RAID 0 ou 1 mais pas en RAID 5...
Quel dommage (sic), cette limitation m'a donnée envie de bidouiller un peu et d'installer une Debian sans l'installeur d'OVH... Et pourquoi pas installer sa Debian comme une ArchLinux ? Pas en rolling release mais en faisant tout manuellement ?


Petite anecdote, les nouveaux serveurs "kimsufi" sont en rĂ©alitĂ© devenus des gammes Éco chez OVHcloud, donc maintenant on peut commander son KS avec son compte OVH et avoir accĂšs Ă  un mĂȘme manager pour tout gĂ©rer (DNS, Domaine, serveur)...


Envie de s'amuser un peu ? Eh bien c'est parti !

Petite chose cependant, je souhaitais partir sur un RAID 5, mais aprÚs diverse réflexions un RAID 0 me suffit amplement. Alors oui je sais, c'est dangereux, je peux perdre tout un FS complet en cas de panne, corruption de disque ou whatever... Si je suis parti sur ça, j'ai mes raisons.

Alors pourquoi continuer d'installer ma Debian comme ça alors que le manager OVH permet d'installer son OS sur un RAID 0 ? Eh bien pour le FUN

â„č
Apparament il n'est plus possible d'avoir son /boot et / en RAID 0, mais uniquement en RAID 1

Du coup, c'est parti pour de la ligne de commande !

DĂ©jĂ  on boot le serveur en rescue sur le rescue64-pro... C'est une Debian 8 et ça va nous embĂȘter pour la suite, mais que serai l'informatique sans problĂšme ? :D
Une fois booté sur le rescue, on va éditer comme des sauvages le sources.list de la machine pour ajouter les repository de Debian 11, on va en utiliser le paquet arch-install-scripts. On peut largement s'en passer, mais ils facilitent un peu tout ça (un peu) :

sed -i '1 i\deb http://deb.debian.org/debian bullseye main contrib non-free' /etc/apt/sources.list
apt-get update
apt-get install arch-install-scripts

Une fois cela fait, on va créer les partitions nécessaires pour installer notre machine. vérifier l'état des disques avec la commande smartctl. Ensuite on crée les partitions nécessaires pour installer notre machine.

Il y a plusieurs écoles, celle qui met une seule et unique partition et celle qui sépare le / du /var du /var/log du /home.
Je vous avouerai que sur cette machine j'ai fait un énorme / et basta. Sur mes machines ayant besoin d'un peu plus de qualité (pour la MCO par exemple) j'ai un /, un /var et un /data séparé et avec du LVM. D'ailleurs si vous souhaitez faire des partitions, je conseil de les faire avec LVM et de gérer votre RAID avec mdadm (qui semble avoir de meilleure performance) et donc de n'avoir qu'une partition physique sur le disque, que vous brancher avec mdadm pour ensuite mettre vos partitions LVM comme ça par exemple :

dryusdan@mul:~$ lsblk 
NAME                            MAJ:MIN RM   SIZE RO TYPE  MOUNTPOINT
sda                               8:0    0   2,7T  0 disk  
└─sda1                            8:1    0   2,7T  0 part  
  └─md0                           9:0    0   5,5T  0 raid5 
    └─vg--data-lv--data         254:2    0   5,5T  0 lvm   
sdb                               8:16   0   2,7T  0 disk  
└─sdb1                            8:17   0   2,7T  0 part  
  └─md0                           9:0    0   5,5T  0 raid5 
    └─vg--data-lv--data         254:2    0   5,5T  0 lvm   
sdc                               8:32   0   2,7T  0 disk  
└─sdc1                            8:33   0   2,7T  0 part  
  └─md0                           9:0    0   5,5T  0 raid5 
    └─vg--data-lv--data         254:2    0   5,5T  0 lvm   
nvme0n1                         259:0    0 894,3G  0 disk  
├─nvme0n1p1                     259:1    0   487M  0 part  
└─nvme0n1p2                     259:3    0 886,3G  0 part  
  ├─vg--srv-lv--root            254:0    0    80G  0 lvm   
  └─vg--srv-lv--var             254:1    0   568G  0 lvm   

Du coup, on ne crée qu'une seule partition avec fdisk :

fdisk /dev/sda

Pour résumer, j'ai appuyé sur m pour avoir le helper puis sur n pour "new", puis sur entré, puis sur entré (deux fois donc), puis sur w pour écrire la table de partition.
Et parce que j'ai une FLEMME MONSTRUEUSE de faire cette Ă©reintante commande 4 fois, j'utilise sfdisk pour cloner ma table de partition :

sfdisk -d /dev/sda | sfdisk /dev/sdb
sfdisk -d /dev/sda | sfdisk /dev/sdc
sfdisk -d /dev/sda | sfdisk /dev/sdd

La partition est créé sur tout les disques ? Vous pouvez utiliser lsblk pour voir cela :

root@fancy ~ # lsblk 
NAME    MAJ:MIN RM  SIZE RO TYPE
sda       8:0    0  1.8T  0 disk  
└─sda1    8:1    0  1.8T  0 part  
sdb       8:16   0  1.8T  0 disk  
└─sdb1    8:17   0  1.8T  0 part  
sdc       8:32   0  1.8T  0 disk  
└─sdc1    8:33   0  1.8T  0 part  
sdd       8:48   0  1.8T  0 disk  
└─sdd1    8:49   0  1.8T  0 part  

Du coup c'est bon ?

TrĂšs bien, donc maintenant le RAID ! Tout simple, c'est avec mdadm !

mdadm --create /dev/md0 --level=0 --raid-devices=4 /dev/sd[a-d]1
💡
Petit point d'attention, faire un RAID sur un disque complet sans partition c'est possible, mais si votre systĂšme est hĂ©bergĂ© sur ce RAID, cela va empĂȘcher l'installation de grub

On format le nouveau périphérique (nommé md0) en ext4 (ou xfs ou ce que vous voulez) et on le monte sur /mnt

mkfs.ext4 /dev/md0
mount /dev/md0 /mnt

Du coup, comme le rescue est un OS vieux comme le monde, il faut récupérer la clé GPG de Debian 11

wget https://ftp-master.debian.org/keys/release-11.asc -qO- | gpg --import --no-default-keyring --keyring ./debian-release-11.gpg

On installe debootstrap et on lance l'installation de la base de Debian dans le /mnt

apt-get install debootstrap

debootstrap --keyring=./debian-release-11.gpg bullseye /mnt http://deb.debian.org/debian

Puis on attend un :

I: Base system installed successfully.

À partir de là les scripts de archlinux nous seront utile (mais il est possible de le faire sans)

genfstab /mnt > /mnt/etc/fstab
arch-chroot /mnt

Alternativement, pour le /mnt/etc/fstab :

/dev/md0            	/         	ext4      	rw,relatime,stripe=512	0 1

Si vous n'avez qu'une seule partition

Et pour vous chrootez :

cd /mnt
mount -t proc /proc proc/
mount -t sysfs /sys sys/
mount --rbind /dev dev/
chroot /mnt

Maintenant on va installer et configurer la machine (comme sur une archlinux, on commence par le nom de la machine, l'heure et la langue de la machine

echo <HOSTNAME> > /etc/hostname
apt update
apt install locales
dpkg-reconfigure tzdata
dpkg-reconfigure locales

tzdata permet de paramétrer l'heure de la machine.
locales permet de paramĂ©trer et gĂ©nĂ©rer la langue de la machine et les langues supportĂ©. J'ai une petite prĂ©fĂ©rence pour le support de fr_FR.UTF-8 et en_US.UTF-8 avec en par dĂ©faut, mais vous ĂȘtes grand ;).

Ensuite, on va installer linux ( 🎉 ).
Je vais partir du principe que vous ĂȘtes sur un Kimsufi, alors vous ĂȘtes sur un BIOS et vous avez une architecture en 64bits, donc vous allez installer les paquets qui suit :

apt-get install linux-image-amd64 grub-pc

Vous pouvez chercher des images Linux plus approprié avec la commande apt-cache search linux-image qui permet de lister les images standard, cloud ou rt.

Pour grub, si vous n'ĂȘtes pas sur si votre machine supporte EFI ou pas, une commande peut gĂ©rer ça :

[ -d /sys/firmware/efi ] && echo UEFI || echo BIOS

C'est pas forcĂ©ment fiable, la carte mĂšre d'un autre serveur supporte l'UEFI mais je l'ai configurĂ© en BIOS il y a longtemps (pourquoi ? Alors lĂ ...) mais ça donne une idĂ©e. Si vous ĂȘtes sĂ»r de supporter l'EFI, utilisez le paquet grub-efi.

Une fois ces paquets-là installés, on a quasiment fini (quasiment ! ), on doit installer mdadm pour permettre l'installation du grub, sinon cela échoue (je me suis cassé un peu le crùne sur l'erreur car l'OS ne trouvait pas md0 alors qu'il était dessus...

apt-get install mdadm

Ensuite on install grub :

grub-install /dev/sda
update-grub

Voilà, Linux est installé.

Ce n'est pas fini. Si vous redémarrez votre machine maintenant elle n'aura pas de réseau !
Pour ça, on va installer deux trois paquets, notamment SSH (sinon mĂȘme avec une connexion rĂ©seau vous n'avez pas accĂšs Ă  l'administration de votre machine, c'est un peu dommage et ça m'est un peu arrivĂ©).

Du coup :

apt-get install vim ssh

vim ou nano on s'en fout (non), vous allez l'utiliser pour :

  • Configurer votre serveur SSH
  • Ajouter une clĂ© SSH dans votre ${HOME}/.ssh/authorized_keys
  • Configurer votre rĂ©seau (la partie la moins simple)
⚠
Vous n'avez pas de mot de passe défini pour root

La section authentification c'est un peu la foire à l'empoigne, chacun à sa petite méthode pour se connecter à sa machine qui est mieux que celle de l'autre (et je sais que je risque d'avoir des commentaires sur la mienne).

Alors je vais faire la méthode la plus complexe pour l'authentification, mais en retenant qu'un seul point : interdire la connexion root avec mot de passe en SSH (vraiment).

Tout d'abord, ajoutez un mot de passe Ă  root

passwd

Ensuite, on va créer un nouvel utilisateur et lui créer son dossier .ssh :

useradd -c "My SSH user" -d /home/dryusdan -m -s /bin/bash dryusdan
mkdir /home/dryusdan/.ssh
echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINGaZ4mz7y0/5/kKFYm75H0zadl0XI2n8/Fm/RvlkUt3 dryusdan@Nemo" > /home/dryusdan/.ssh/authorized_keys
chown -R dryusdan: /home/dryusdan/.ssh

Ensuite modifiez votre configuration SSH pour glisser ces directives :

PermitRootLogin no #Interdit la connexion SSH avec root
PubkeyAuthentication yes #Permet la connexion SSH via un échange de clé
AuthorizedKeysFile	.ssh/authorized_keys 
PasswordAuthentication no #Interdit l'authentification par mot de passe
PermitEmptyPasswords no #Interdit l'authentification par mot de passe vide

PermitRootLogin peut avoir différente valeur :

  • yes qui permet de se connecter comme un utilisateur normal
  • without-password qui permet de se connecter mais sans utiliser de mot de passe
  • forced-commands-only qui permet de se connecter en root (pareil sans utiliser de mot de passse pour lancer certaines commandes.
  • no interdit la connexion Ă  root

(le man).

On modifie le sudoers pour pouvoir utiliser root :

visudo -f /etc/sudoers.d/dryusdan
dryusdan	ALL = (ALL)

(Le man)

Maintenant le réseau !

C'est ici la partie la plus "compliquée", la configuration de l'interface réseau.
Le rescue force l'utilisation du nom eth0, mais l'interface a probablement un autre nom.

Bon, je suis prĂȘt Ă  parier que le nom sera eno1 😉 mais sait on jamais.

On va donc Ă©diter les interfaces. Tout d'abord l'interface local, assez facile :

vim /etc/network/interfaces.d/lo 
auto lo
iface lo inet loopback

Maintenant l'interface public de la machine, on va se rendre sur le manager OVH

Vous vous doutez, les IPs sont modifiées mais l'essentiel est là

Donc dans le fichier de configuration réseau /etc/network/interfaces.d/eno1 vous allez remplir les informations suivantes :

auto eno1
allow-hotplug eno1
iface eno1 inet static
    address 94.0.0.0
    netmask 255.255.255.0
    gateway 94.0.0.254

iface eno1 inet6 static
    address 2001::1
    netmask 128
    post-up /sbin/ip -f inet6 route add 2001::00ff:00ff:00ff:00ff dev eno1 && /sbin/ip -f inet6 route add default via 2001::00ff:00ff:00ff:00ff
    pre-down /sbin/ip -f inet6 route del 2001::00ff:00ff:00ff:00ff dev eno1 && /sbin/ip -f inet6 route del default via 2001::00ff:00ff:00ff:00ff

Pour la gestion de l'IPv6 sur un Kimsufi, je vous invite Ă  lire l'article Ă  ce sujet

Mettre en place l’IPv6 sur un Kimsufi

Maintenant, l'heure de verité, vous allez quitter votre chroot, redémarrer la machine (en ayant pris soin de retirer le mode rescue sur le manager OVH) et attendre. Vous pouvez dans un terminal à cÎté lancer un ping.

Normalement il y a de grandes chances que votre serveur démarre.

Si jamais cela ne fonctionne pas, revenez sur le rescue, et effectuez la commande suivante :

root@fancy ~ # grep eth /var/log/kern.log 
Feb 18 18:06:59 fancy kernel: [    0.900019] igb 0000:03:00.0: added PHC on eth0
Feb 18 18:06:59 fancy kernel: [    0.900021] igb 0000:03:00.0: eth0: (PCIe:2.5Gb/s:Width x1) 00:1e:67:f8:e8:df
Feb 18 18:06:59 fancy kernel: [    0.900063] igb 0000:03:00.0: eth0: PBA No: 103000-000
Feb 18 18:06:59 fancy kernel: [    0.926630] igb 0000:04:00.0: added PHC on eth1
Feb 18 18:06:59 fancy kernel: [    0.926632] igb 0000:04:00.0: eth1: (PCIe:2.5Gb/s:Width x1) 00:1e:67:f8:e8:e0
Feb 18 18:06:59 fancy kernel: [    0.926674] igb 0000:04:00.0: eth1: PBA No: 103000-000
Feb 18 18:06:59 fancy kernel: [    0.927373] igb 0000:03:00.0 eno1: renamed from eth0
Feb 18 18:06:59 fancy kernel: [    0.952969] igb 0000:04:00.0 eno2: renamed from eth1

(On voit d'ailleur que j'ai 2 interfaces sur cette machine).
eth0 a été renommé en eno1.

Un exemple sur autre exemple sur mon archlinux :

root@Nemo ~ # journalctl -b | grep eth0
févr. 22 18:50:25 Nemo kernel: igc 0000:05:00.0 eth0: MAC: 04:42:1a:09:e9:14
févr. 22 18:50:25 Nemo kernel: igc 0000:05:00.0 enp5s0: renamed from eth0

Donc ça marche plutÎt bien.

Si le nom ressorti n'est pas eno1 mais enp5s0, refaites l'étape précédente (modification d'un fichier de configuration réseau) en remplaçant eno1 par enp5s0.

Petit découverte par la suite. Ma machine est montée avec des interfaces 1000mbps mais un débit limité à 100mbps. Assez rapidement j'ai découvert que j'avais énormément de "TCP retransmit"

Ce que me confirmait iperf3 (et là j'étais sur le rescue pour valider que ce n'était une application qui a pété une durite) :

root@rescue:~# iperf3 -c rbx.proof.ovh.net test
Connecting to host rbx.proof.ovh.net, port 5201
[  4] local 2001:41d0:2:2d5b::1 port 48362 connected to 2001:41d0:203:9fe4::1 port 5201
[ ID] Interval           Transfer     Bandwidth       Retr  Cwnd
[  4]   0.00-1.00   sec  6.03 MBytes  50.6 Mbits/sec  869   4.18 KBytes       
[  4]   1.00-2.00   sec  3.92 MBytes  32.9 Mbits/sec  417   4.18 KBytes       
[  4]   2.00-3.00   sec  3.92 MBytes  32.9 Mbits/sec  446   1.39 KBytes       
[  4]   3.00-4.00   sec  4.17 MBytes  35.0 Mbits/sec  442   2.79 KBytes       
[  4]   4.00-5.00   sec  3.92 MBytes  32.9 Mbits/sec  375   4.18 KBytes       
[  4]   5.00-6.00   sec  4.41 MBytes  37.0 Mbits/sec  457   1.39 KBytes       
[  4]   6.00-7.00   sec  4.90 MBytes  41.1 Mbits/sec  350   1.39 KBytes       
[  4]   7.00-8.00   sec  5.88 MBytes  49.4 Mbits/sec  490   5.58 KBytes       
[  4]   8.00-9.00   sec  3.55 MBytes  29.8 Mbits/sec  594   1.39 KBytes       
[  4]   9.00-10.00  sec  4.29 MBytes  36.0 Mbits/sec  808   1.39 KBytes       
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bandwidth       Retr
[  4]   0.00-10.00  sec  45.0 MBytes  37.8 Mbits/sec  5248             sender
[  4]   0.00-10.00  sec  44.8 MBytes  37.6 Mbits/sec                  receiver

iperf Done.
root@rescue:~# iperf3 -4 -c rbx.proof.ovh.net test
Connecting to host rbx.proof.ovh.net, port 5201
[  4] local 94.23.44.91 port 48992 connected to 152.228.221.228 port 5201
[ ID] Interval           Transfer     Bandwidth       Retr  Cwnd
[  4]   0.00-1.00   sec  5.58 MBytes  46.8 Mbits/sec  950   7.07 KBytes       
[  4]   1.00-2.00   sec  3.50 MBytes  29.4 Mbits/sec  731   1.41 KBytes       
[  4]   2.00-3.00   sec  4.25 MBytes  35.7 Mbits/sec  772   1.41 KBytes       
[  4]   3.00-4.00   sec  4.67 MBytes  39.2 Mbits/sec  896   1.41 KBytes       
[  4]   4.00-5.00   sec  3.92 MBytes  32.9 Mbits/sec  733   14.1 KBytes       
[  4]   5.00-6.00   sec  4.33 MBytes  36.3 Mbits/sec  748   2.83 KBytes       
[  4]   6.00-7.00   sec  4.46 MBytes  37.4 Mbits/sec  792   2.83 KBytes       
[  4]   7.00-8.00   sec  4.91 MBytes  41.2 Mbits/sec  849   22.6 KBytes       
[  4]   8.00-9.00   sec  4.86 MBytes  40.8 Mbits/sec  697   14.1 KBytes       
[  4]   9.00-10.00  sec  4.86 MBytes  40.8 Mbits/sec  748   24.0 KBytes       
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bandwidth       Retr
[  4]   0.00-10.00  sec  45.4 MBytes  38.0 Mbits/sec  7916             sender
[  4]   0.00-10.00  sec  45.2 MBytes  37.9 Mbits/sec                  receiver

iperf Done.
root@rescue:~#

La petite colonne Retr indique le nombre de paquet retransmis.
Du coup, il va falloir contrĂŽler le trafic (Traffic shapping) et lĂ  c'est pas simple.
Assez rapidement j'ai découvert que la méthode la plus efficace serait d'utiliser tc déjà intégré au systÚme. Le wrapper tcconfig que j'ai testé n'avait pas fonctionné. Mais tc c'est un peu comme la commande ip ou nft (pour nftables et pas "non-fungible token") c'est trÚs efficace, mais trÚs complexes à appréhender.

Du coup, aprÚs avoir parcouru plusieurs sites pour trouver non pas un article qui fonctionne, mais un article qui explique plus simplement que la documentation, je suis tombé sur cet article (en anglais) qui donne pas mal d'exemple et explique avec des cas "concrets" : Limiting WireGuard Bandwidth.
Mais nous n'allons pas limiter le trafic pour wireguard mais carrément en sortie du serveur.

tc qdisc add dev eno1 parent root handle 1: hfsc default 1 
tc class add dev eno1 parent 1: classid 1:1 hfsc sc rate 100mbit ul rate 100mbit

# Et sa version oneliner a taper d'un coup pour Ă©viter de se faire couper la main
tc qdisc add dev eno1 parent root handle 1: hfsc default 1 && tc class add dev eno1 parent 1: classid 1:1 hfsc sc rate 100mbit ul rate 100mbit
💡
Il faut l’exĂ©cuter dans un tmux ou un screen

Normalement, en relançant un iperf3, vous devriez avoir de bien meilleur résultat :

root@fancy ~ # iperf3 -c rbx.proof.ovh.net test
Connecting to host rbx.proof.ovh.net, port 5201
[  5] local 2001:41d0:2:2d5b::1 port 44816 connected to 2001:41d0:203:9fe4::1 port 5201
[ ID] Interval           Transfer     Bitrate         Retr  Cwnd
[  5]   0.00-1.00   sec  12.0 MBytes   100 Mbits/sec    0    166 KBytes       
[  5]   1.00-2.00   sec  11.1 MBytes  93.0 Mbits/sec   87   55.8 KBytes       
[  5]   2.00-3.00   sec  11.4 MBytes  95.6 Mbits/sec    0    123 KBytes       
[  5]   3.00-4.00   sec  11.0 MBytes  92.5 Mbits/sec    0    139 KBytes       
[  5]   4.00-5.00   sec  11.4 MBytes  95.6 Mbits/sec    0    153 KBytes       
[  5]   5.00-6.00   sec  11.4 MBytes  95.6 Mbits/sec    0    160 KBytes       
[  5]   6.00-7.00   sec  11.0 MBytes  92.5 Mbits/sec    0    162 KBytes       
[  5]   7.00-8.00   sec  11.4 MBytes  95.6 Mbits/sec    0    162 KBytes       
[  5]   8.00-9.00   sec  11.0 MBytes  92.5 Mbits/sec    0    162 KBytes       
[  5]   9.00-10.00  sec  11.4 MBytes  95.6 Mbits/sec    0    163 KBytes       
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bitrate         Retr
[  5]   0.00-10.00  sec   113 MBytes  94.9 Mbits/sec   87             sender
[  5]   0.00-10.04  sec   112 MBytes  93.8 Mbits/sec                  receiver

D'ailleurs dans l'article vous pourrez lire comment définir une QOS

Je ne vais pas vous traduire ce qui est écrit dans l'article, il est trÚs bien écrit et je pense rendre moins compréhensible que nécessaire.

Cependant, je vais quand mĂȘme expliquer grossiĂšrement ce qu'on a fait.
Dans l'idée, on a créé une rÚgle de contrÎle en sortie "parente" qui est la rÚgle 0 et qui va matcher tous les paquets flaggué avec un bit 32 (tous par défaut donc) et ainsi appliquer une rÚgle de contrÎle de trafic qui ici limite la bande passante à 100mbps et créer une rÚgle de PFIFO (first in / first out).

Maintenant qu'on a validé que le traffic shapping fonctionne, on va l'intégrer au démarrage du systÚme.
Il y a plusieurs méthodes possible :

  • Faire un script et appeler ce script via systemd
  • Utiliser un service systemd qui appel ces deux commandes

Je pars sur le second choix. Du coup :

vim /etc/systemd/system/tc.service 
[Unit]
Description=Traffic controller
Documentation=https://www.procustodibus.com/blog/2022/12/limit-wireguard-bandwidth/
After=network.target

[Service]
Type=oneshot
ExecStartPre=/usr/sbin/tc qdisc add dev eno1 parent root handle 1: hfsc default 1
ExecStart=/usr/sbin/tc class add dev eno1 parent 1: classid 1:1 hfsc sc rate 100mbit ul rate 100mbit
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target

On recharge systemd et on active au démarrage le service qu'on vient de créer.

systemctl daemon-reload
systemctl enable tc

Et maintenant c'est "reboot proof", vous pouvez tester en redémarrant et en testant via iperf3.
Profitez bien de votre machine !

Sur ce, portez-vous bien.

Photo de Onur Binay

Dryusdan

Chasseur de bug et régleur de problÚme (alias DevOps).