Setup Gentoo on a Hetzner server

I really like Gentoo for their awesome package manager, Portage. Gentoo is a really flexible distribution that you can customize (and break) in many ways. It’s a good opportunity to learn a lot about linux. I documented the installation process. Given is an EX server from Hetzner, booted into the Debian rescue system.

As a first step, we setup the partitioning + mdadm Raid + LVM + filesystems:

parted /dev/nvme0n1 --script mklabel gpt
parted /dev/nvme1n1 --script mklabel gpt
parted /dev/nvme0n1 --script mkpart primary ext3 2048s 4095s
parted /dev/nvme1n1 --script mkpart primary ext3 2048s 4095s
parted /dev/nvme0n1 --script mkpart primary ext3 4096s 1953791s
parted /dev/nvme1n1 --script mkpart primary ext3 4096s 1953791s
parted /dev/nvme0n1 --script mkpart primary ext3 1953792s 100%
parted /dev/nvme1n1 --script mkpart primary ext3 1953792s 100%
parted /dev/nvme0n1 --script set 1 bios_grub on
parted /dev/nvme1n1 --script set 1 bios_grub on
mdadm --verbose --create /dev/md/0 --level=1 --raid-devices=2 --metadata=1.2 /dev/nvme0n1p2 /dev/nvme1n1p2
mdadm --verbose --create /dev/md/1 --level=1 --raid-devices=2 --metadata=1.2 /dev/nvme0n1p3 /dev/nvme1n1p3
echo 999999999 > /proc/sys/dev/raid/speed_limit_min
echo 999999999 > /proc/sys/dev/raid/speed_limit_max
until ! grep -q resync /proc/mdstat; do echo "sleeping for 2s"; sleep 2; done
mkfs.ext4 -v /dev/md/1
pvcreate --verbose /dev/md/2
vgcreate --verbose vg0 /dev/md/2
lvcreate --verbose --name root --size 50G vg0
mkfs.ext4 -v /dev/mapper/vg0-root
mount /dev/mapper/vg0-root /mnt/

Next, we download a stage 3 tarball (minimal precompiled Gentoo basically) and verify it:

for file in '' {.CONTENTS.gz,.DIGESTS.asc}; do wget "${url}/${latest}${file}"; done
gpg --keyserver hkps:// --recv-keys 0xBB572E0E2D182910
gpg --verify "${latest}.DIGESTS.asc"
grep " ${latest}.CONTENTS.gz" *.DIGESTS.asc
openssl dgst -r -sha512 "${latest}.CONTENTS.gz"

This will verify the gpg signature in the .asc File. Afterwards we grep the SHA512 checksum for CONTENTS.gz from the .asc file. Then we run openssl to compute the SHA512 checksum on the actual stage 3. Compare the two SHA512 checksums, they have to be identical. If they are, continue with extracting the tarball:

mv stage3-amd64-hardened-selinux-*.tar.xz /mnt/
cd /mnt/
tar xpvf stage3-*.tar.xz --xattrs-include='*.*' --numeric-owner
mount /dev/md/1 /mnt/boot/

Now we can prepare the chroot:

cp --dereference /etc/resolv.conf /mnt/etc/
mount --types proc /proc /mnt/proc
mount --rbind /sys /mnt/sys
mount --make-rslave /mnt/sys
mount --rbind /dev /mnt/dev
mount --make-rslave /mnt/dev
mkdir /mnt/hostlvm
mount --bind /run/lvm /mnt/hostlvm
chroot /mnt/gentoo /bin/bash
ln -s /hostlvm /run/lvm
source /etc/profile
export PS1="(chroot) ${PS1}"

Now we can configure portage:

mkdir /etc/portage/repos.conf
cp /usr/share/portage/config/repos.conf /etc/portage/repos.conf/gentoo.conf
echo 'MAKEOPTS="-j6"' >> /etc/portage/make.conf
echo 'USE="systemd ipv6"' >> /etc/portage/make.conf
sed -i 's/^COMMON_FLAGS.*/COMMON_FLAGS="-march=native -O2 -pipe"/g' /etc/portage/make.conf
emerge --sync
emerge --ask --verbose --update --deep --newuse @world
emerge --depclean
echo '=sec-policy/selinux-base-policy-9999 **' >> /etc/portage/package.accept_keywords
# set profile to hardened..., see eselect profile list
emerge --ask --verbose --unmerge sysvinit eudev
echo 'sys-fs/mdadm static' >> /etc/portage/package.use/mdadm
echo 'sys-fs/lvm2 lvm2create_initr' >> /mnt/etc/portage/package.use/lvm2
echo 'app-admin/puppet augeas diff doc rrdtool' > /etc/portage/package.use/puppet
emerge --ask --autounmask-write --verbose sys-kernel/gentoo-sources sys-apps/systemd vim htop nload iftop iptraf-ng strace lsof gentoolkit intel-microcode pciutils genkernel dstat grub mdadm lvm2 smartmontools dropbear ccze fail2ban tcpdump dev-vcs/git puppet dfc gptfdisk ethtool net-misc/ipcalc ndisc6
echo 'LANG="en_US.utf8"' >> /etc/locale.conf
# setup /etc/systemd/network/
mdadm --detail --scan >> /etc/mdadm.conf
sed -i 's/.*LVM=.*/LVM="yes"/' /etc/genkernel.conf
sed -i 's/.*MICROCODE=.*/MICROCODE="yes"/' /etc/genkernel.conf
sed -i 's/.*SSH=.*/SSH="yes"/' /etc/genkernel.conf
sed -i 's/.*BUSYBOX=.*/BUSYBOX="yes"/' /etc/genkernel.conf
sed -i 's/.*MDADM=.*/MDADM="yes"/' /etc/genkernel.conf
sed -i 's/.*E2FSPROGS=.*/E2FSPROGS="yes"/' /etc/genkernel.conf
genkernel all
sed -i 's/.*GRUB_DISABLE_SUBMENU.*/GRUB_DISABLE_SUBMENU=y/g' /etc/default/grub
sed -i 's/.*GRUB_TIMEOUT=.*/GRUB_TIMEOUT=15/g' /etc/default/grub
sed -i 's|.*#GRUB_CMDLINE_LINUX=.*|GRUB_CMDLINE_LINUX="init=/usr/lib/systemd/systemd dolvm domdadm dossh rootfstype=ext4"|' /etc/default/grub
for dev in /dev/nvme?n1; do grub-install "${dev}"; done
grub-mkconfig -o /boot/grub/grub.cfg
# get UUID with `blkid /dev/mapper/vg0-root /dev/md1` and update /etc/fstab
mkdir ~/.ssh
echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKC4uaKuYzMGK4jlTvPlbnMP9n+gdac65480/eDTMWRw bastelfreak" > ~/.ssh/authorized_keys
sed -i 's/.*PermitRootLogin.*/PermitRootLogin prohibit-password/' /etc/ssh/sshd_config
systemctl enable systemd-networkd sshd

Setup language/locales

echo 'en_US.UTF-8 UTF-8' >> /etc/locale.gen
# verify that our locale is present:
locale -a | grep en_US.utf8
eselect locale set en_US.utf8
echo 'dns_domain_lo=""' >> /etc/conf.d/net
echo 'hostname="hypervisor01"' >> /etc/conf.d/hostname
. /etc/profile
env-update && source /etc/profile

Setup timesyncd and DNS

sed -i 's/#NTP=/' /etc/systemd/timesyncd.conf
rm /etc/localtime
ln -s /usr/share/zoneinfo/Europe/Berlin /etc//localtime
sed -i 's/#DNS=/DNS=2a01:4f8:0:1::add:1010 2a01:4f8:0:1::add:9999 2a01:4f8:0:1::add:9898/' /etc/systemd/resolved.conf
sed -i 's/#Domains=/' /etc/systemd/resolved.conf
systemctl enable systemd-timesyncd systemd-resolved

Now we can reboot! I suggest to configure a password first and/or create a user. After the first boot we can continue with some fancy pancy stuff:

Setup LLDP:

echo 'net-misc/lldpd jansson' > /etc/portage/package.use/lldpd
emerge --ask lldpd
systemctl enable lldpd
systemctl start lldpd

Setup all the fancy dotfiles:

cd ~
git clone
ln -s ~/scripts/vimrc ~/.vimrc
ln -s ~/scripts/bashrc ~/.bashrc
ln -s ~/scripts/bash_profile ~/.bash_profile
mkdir -p ~/.vim/backupdir/
mkdir ~/.vim/ftplugin
echo "set colorcolumn=80" >> ~/.vim/ftplugin/tex.vim
git clone ~/.vim/bundle/Vundle.vim
vim +PluginInstall +qall

And last but not least, you might want to run some virtual machines, so install Qemu and Libvirt:

echo 'app-emulation/libvirt zeroconf virt-network pcap parted lvm' > /etc/portage/package.use/libvirt
echo 'app-emulation/qemu spice virtfs usb usbredir' > /etc/portage/package.use/qemu
emerge --ask qemu libvirt ebtables dmidecode openvswitch bridge-utils
emerge --ask qemu libvirt ebtables dmidecode openvswitch bridge-utils
systemctl enable ovsdb-server
systemctl start ovsdb-server
systemctl start ovs-vswitchd
systemctl enable ovs-vswitchd
ovs-vsctl add-br br0

You now have a proper Gentoo box. I suggest to configure at least backups and a firewall. Please keep in mind that Gentoo is a rolling release distribution, so some of the commands might be obsolete after some time or you need to configure something differently. Still, this walkthrough should give you a good first impression.

This entry was posted in General, Linux, Virtualization. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

Time limit is exhausted. Please reload CAPTCHA.