Last Updated: March 08, 2016
· robjens

ArchLinux manual setup (Virtualbox guest)

I thought I'd share this sudden insight I had after having done a few ArchLinux setups. This weekend I had a (dynamic) .vdi fail and become corrupted. Since it was a pain recalculating the sectors and since I didn't have boot on the disk (it was a clone of another dynamic one, significantly complicating matters and I'm a n00b as far as disk (advanced) formats go, figured it would be a lot quicker to just start all over again. It might contain a few useful tips for anyone else doing a similiar setup.

As you may or may not know, Arch has a great wiki which contains a whole lot of quality information on much of the steps I have to take. Your machine/hardware/config/preferences may very well differ so take what you need and research the rest.

Arch ISO ships with zsh by the way :)

First steps:

pacman -Syy
pacman -S vim

Since the 'disk' is actually stored in RAM, keep the installed software at this point to bare minimum you need. Vim will greatly speed up your process (or emacs but I tend to find nano way underqualified for the job. I want to copy lines, do multi-line edits and more. I don't even bother to go ~/.vimrc and to set nocompatible at this point, since it is temporary data anyway. Next I'll typically want to format my disks. I like to heavily disperse my data over the major FSH top level folders. I used to use gdisk for this but instead, we'll be using sgdisk now.

vim 01
#/root/01 file (inside)
sgdisk -Z /dev/sda
sgdisk -a 4096 /dev/sda

I used vim to create a file named 01 and inside I put two lines (for the moment, to explain) and these zero out the disk (virtual disk, I used a fixed size this time of 50G. The last line sets the advanced format which are sectors of 4096-bytes and which makes more efficient use of available disk space. The block device /dev/sda is now ready to be partitioned. I won't type out every bit of the partitions but enough to get the idea for you, the following lines in the 01 file would be:

sgdisk -n 1:0:+2M -t 1:ef02 -c 1:bios /dev/sda
sgdisk -n 2:0:+200M -t 2:8300 -c 2:boot /dev/sda
sgdisk -n 3:0:+3G -t 3:8300 -c 3:root /dev/sda
sgdisk -n 4:0:+10G -t 4:8300 -c 4:usr /dev/sda
sgdisk -n 5:0:+5G -t 5:8300 -c 5:usr_local /dev/sda
sgdisk -n 9:0:13G -t 9:8300 -c 9:var
sgdisk -n 10:0:0 -t 10:8200 -c 10:swap

I've reserved 2M at the beginning of the disk for the Grub bootloader to install the GPT schema on the post-MBR gap on later. The type is that of bios boot or ef02. Use ef00 if you want to use EFI instead. If you write it out once and yy (yank) lines in vim, ensure you keep the numbers correct, although commands execute in the consecutive order of n, t, c (new disk of size, then type, then name), each one of them needs the partition number (so one could create a new one and on a whole other partition change the name). The 0 size of swap will take any left over space (so calculate the sizes on your partitions so that the rest is about 2x available RAM. Also I like to swap on the end or beginning of the disk for faster access times on especially magnetic disks of course.

Another thing to note is that I like to keep my usr on a separate partition too and it'll require some additional steps later.

Exit the file and execute the script with zsh 01 and the first step is done. Next create a new file vim 02 and write up the file system information, you could do something like this:

for i (${(A)=fslist::= 2 3 4 5 6 7 8}) cmd='mkfs.ext4 /dev/sda$i' && print ${(e)cmd}

mkswap /dev/sda10
mkfs.reiserfs -q /dev/sda9

A few notes. The first expression is my laziness to type more elaborate and long expressions. I try to be succinct in code and verbose on documentation. Usually this short-hand zsh for loops isn't the best practice and should probably be done on the cli itself, not in scripts (since it isn't very readable to begin with). You could always make a job follow the 8}) by adding a { ... } to place the commands in but this is soooo short, I figured this would be ok. Final part evaluates the prepared command to make all ext4 file systems. Finally, the two odd ducks out are mkswap and the file system format reiserfs which is better and faster for partitions that have a lot of disk I/O (like the logs, cache, everything on /var really) going on.

Time to mount the whole shebang. Fire up a new script file e.g. 03 and type something along the lines of:

mount /dev/sda3 /mnt
cd /mnt
mkdir boot usr opt srv home var
mount /dev/sda2 boot
# /dev/sda3 is / and already mounted as such
mount /dev/sda4 usr
# now, make the super-op owned local folder
# this allows to separate usr (root:root) and (sop:sop)
# which e.g. node.js loves and others too as you can
# freely write stuff to disk without root access
mkdir usr/local
mount /dev/sda5 usr/local
mount /dev/sda6 opt
mount /dev/sda7 srv
mount /dev/sda8 home
mount /dev/sda9 var
swapon /dev/sda10

Cool, everything mounted now so we can start to bootstrap ArchLinux and any additional software we like. My initial list of most prefered and needed apps early on is something like below and, of course, I make another file 04 now and execute afterwards:

pacstrap /mnt base base-devel linux-headers dkms zsh sudo tree htop vim dfc git xorg-server xorg-xauth xorg-xhost net-tools dnsutils grub wget httpie elinks virtualbox-guest-utils virtualbox-guest-dkms jshon

The last entry ensures that virtualbox-guest-modules and xorg-xrandr amongst others get installed as they are dependencies of the utils package. Also, before executing this, you may wish to check and modify /etc/pacman.d/mirrorlist and move a server near you (if reliable mirror, some tend to lag or be down on occasion) to the top of the list. Also that is why the elinks and some net-tools are present in my list, to check server status and if needed manually download via the arch linux ../<group>/<package>/download link which resolves always a working server to provide either tarball or makepkg PKGBUILD. The jshon package is a dependency of packer-git a nice bash wrapper for aur (arch user repository) software download. You'll have to get that one using e.g. elinks or wget and then makepkg on the PKGBUILD file.

Next it is time to generate the file /etc/fstab on the new-root install. This will contain the disk information we just created by all the steps before and will allow us to easier boot the chroot once done.

genfstab -U -p /mnt >> /mnt/etc/fstab

This writes our disk partition and mount options to the appropriate place using GUID as opposed to the potentially hijacked by earlier disks form of /dev/sdaN. I usually edit it straight away and for example to tweak performance and speed set a lot of mounts to:


to those who can handle it. I won't provide much details here since a) its security and b) much can go wrong so you're on your own there. Finally I ensure that our /tmp is running on tmpfs with by default half the RAM but may be tweaked of course.

Cool. Time to chroot. But before doing so, you may wish to keep your new scripts for use the next time and be able to more quickly scaffold a new install:

cd && cp 0* install.txt /mnt/root/
arch-chroot /mnt /usr/bin/zsh

The last line will actually chroot using zsh as opposed to the regular bash since it is set as the $SHELL environment variable. Do a quick chsh -s /usr/bin/zsh root if you wish to persist through boot already.

The following options are more or less personal and localized but for completeness sake I'll reference them anyway - tweak as needed obviously:

print 'localhost' >> /etc/hostname

ln -s /usr/share/zoneinfo/Europe/Amsterdam /etc/localtime

# stream editor in-place edit of only matched locales without pound in column 1
sed -i -n -r 's/#((en_US|nl_NL).UTF-8)/\1/p' /etc/locale.gen

# create language files (removes the not used)

cat <<-eos > /etc/locale.conf

cat <<-eos > /etc/vconsole.conf
kbdrate -d 200 -r 30

The advantage of the last 2 forms is that it is very convenient to write multiline files from the console this way as the catdoc (a form of heredoc) will keep creating new lines until it finds the end-of-string eos value. This is equally useful in scripts.

By the way, I forgot install.txt and I like to use it sometimes to read up a few steps as reference. Usually I'll delete the majority of the lines and save since I hate scrolling in a serial console and this way I can use it to keep track of my steps or build a script from it if needed. Use as you please, just know you can always exit the chroot (like I had to get the file) by Ctrl-D signal and the files will still be there (since we didn't reboot did we?) then copy anything you need to /mnt/root or whatever and chroot again using arch-chroot. Just a minor pointer there for newbies among us.

Erh. Let's see. Now comes a very important part, so pay attention if you've been following along and also have a Grub based BIOS disk setup with separate /usr because you can easily fek this up too.

# it needs to find the 2M MBR although at /dev/sda1
grub-install /dev/sda #<--- use /dev/sda   !!

If all goes well you'll see:

Installing for i386-platform.
Installation finished. No error reported.

Ok so now we have a proper BIOS bootloader setup for our disk. I don't use any of the other ones so I can't provide instructions on those but Arch has very well written wiki articles (again, repeating myself) so be sure to check it out.

One of these things I like to do early is to ensure my virtualbox guest modules are properly loaded. So once more, the fabled catdoc is utilized:

cat <<-eos > /etc/modules-load.d/virtualbox.conf

This will ensure loading of the kernel modules at boot time. But for now, you can't use this in a chroot just yet so suffice with enabling the systemd service at boot:

systemctl enable vboxservice

Since these are all system-wide (usually those in /etc) so far so good. Once you've setup your super-operator (which probably has wheel and vboxuser group membership) you will want to have virtualbox support your desktop manager (it must, since your video would not work without) so don't forget by then to do something like:

rm ~/.xinitrc
ln -s ~/.xsession ~/.xinitrc
print '/usr/bin/VBoxClient-all' >> ~/.xinitrc

I do this (removal of ~/.xinitrc since it is actually deprecated and ~/.xsession is the new to be used. Although these changes typically go really slow in on the *nix OS level and it has hardly any impact plus many, many variants of *nix out there that use xserver. Anyway, personal habit and much of my dotfiles are symlinked to my dotfiles git repository anyway.

Edit the initial early boot system initramfsconfiguration file to
ensure that /usr partition gets loaded or boot will fail. Use vim or any other editor and change to this (minimal settings, add others as needed/applicable e.g. ext2 or btrfs etc)

MODULES="ext4 reiserfs"    
HOOKS="base udev autodetect usr modconf block filesystems keyboard fsck shutdown"

Now run: mkinitcpio -p linux to generate the files (ignore the warnings, they happen on the fallback only and you may not even have this hardware - since they are firmware warnings - on your machine: they are aic94xx and smsmdtv and are currently issuing warnings which I don't like but are a fact life atm).

If all other output (and so especially on the first main boot loader entry) looks ok, it is time to generate the Grub bootloader entries:

grub-mkconfig -o /boot/grub/grub.cfg

I could have set some more kernel line options in the /etc/default/grub file but really its not needed since that I don't hibernate a virtual machine like this, so resume= isn't needed and, although it may seem that Arch is still using the old sysinit, this is actually just systemd running sort of like a mask. Since I can use everything from systemctl and journalctl I don't mind. Be sure to check out at least something like systemd-analyze blame if you are a speed-freak optimizer or aspire to be one, since it'll tell you which services take longest to boot asynchronously.

One final tip/pointer or the grub boot partition. I like to make the /boot partition mount ro for additional protection. You may want to make a wrapper function in that case which ensures a mount -o rw,remount /dev/sda2 which runs before any changes to /boot are made. These are any updates to a Linux (as the initramfs image has to be written to that partition, as well as the vmlinuz-linux file but also our just generated grub-mkconfig file will need it. Else you may find yourself with a upgrade now and then failing because these updates/changes cannot be persisted. Having done this, a tool and command as ckboot-init becomes nice as well (it 'll warn you if stuff changed on /boot - a bit of a anti-evil maid like tool).

Now we are almost ready, the install.txt points out that we'll need a password for root so do something like passwd and fill it in. Also you will want to have a super-op user which I like to give visudo group based permissions on %wheel. Something like:

useradd -m -G floppy,optical,storage,power,network,video,scanner,disk,log,wheel,systemd-journal <sop-name>

and subsequently set the passwd <sop-name> as well.

Also you'd do great to manually set-up your network (static, disable ipv6 possibly - what I tend to do) or, if a bit unfamiliar still just enable the service:

systemctl enabled dhcpcd

and you'll be fine. Finally I always setup systemd vconsole autologin for my superuser so I don't have to type the password to login. Or you may wish to boot into a graphical window manager later, your pick.

Exit the chroot and unmount all disks: Ctrl-D and umount -R /mnt. Then reboot. Shutdown the virtual machine and change the boot order of disks possibly, the have the HDD become first and CDROM/DVD (ISO) second to bypass the setup disk image grub bios screen and use the one we just installed to /boot or /dev/sda2.

Of course one could have always used a pre-built Docker or Virtualbox or Vagrant box... but what would be the fun in that? :)

Enjoy and happy learning.