Virtual Machine Setup Guide
We’ll be using Arch Linux virtual machines (VMs) in CS 326. Arch Linux is a simple distribution that gives us the opportunity to configure our virtual machines exactly as we want. For your reference, the Arch Linux Wiki has a wealth of information on configuring the system, swapping out components, and installing a wide variety of software.
In this lab, you’ll learn how to:
- Create a virtual machine using Linux Kernel-based Virtual Machine (KVM) virtualization
- Partition disks
- Configure a base Linux system from scratch
If you’d like to go beyond the steps outlined on this page, check out the helpful Arch Linux Installation Guide.
Virtual Machine Setup
One of our goals in this class is to get more familiar with Linux (and Unix) systems, particularly with the command line interface (CLI). Instead of giving each student a Linux workstation to use over the course of the semester, we’ll use virtual machines. After all, virtualized infrastructure has revolutionized the computing landscape; rather than maintaining large datacenters with thousands of power-hungry servers, companies can start and stop virtual machines as needed to scale their infrastructure in or out as required.
KVM is a virtualization module that allows Linux to act as a hypervisor, or software component that supervises virtual machines. In VM terminology, you have two types of systems:
- Host - the physical machine VMs run on; it hosts the VMs.
- Guest - the VMs themselves are guests running on the host.
We will use our VM host gojira
to create a VM guest for each student in this lab.
Cloud Computing
What we’re about to do is very similar to creating an Amazon AWS, Google Cloud, Azure, etc.-based virtual machine. The big difference is that instead of using a pre-made template image of a VM, we’re starting from scratch.
After we build the VM, your interactions with it will be like any other Unix-based machine, including setting up SSH keys, managing packages, etc.
Logging into the VM Host
Dust off your USF CS credentials and ssh
into our jump host, stargate.cs.usfca.edu
. Once logged in you can proceed to ssh
to our VM host, gojira
:
# Get to the CS network:
$ ssh mmalensek@stargate.cs.usfca.edu
# Log in to the VM host:
$ ssh mmalensek@gojira
# Let's see who else is logged in:
$ finger
Login Name Tty Idle Login Time
afedosov Alex Fedosov pts/0 4:04 Jan 9 12:20
mmalensek Matthew Malensek pts/1 Jan 9 17:31
# (This output will probably be a bit more exciting once classes start)
IMPORTANT: You will be using ssh
extensively in this class, so you need to set up passwordless ssh if you haven’t already. In other words, you should be able to type ssh stargate.cs.usfca.edu
followed by ssh gojira
without entering a password.
All of our VMs will be hosted on a single server (gojira
), which has 64 hardware threads (32 cores) and 128 GB of RAM. You will be able to log into the VM host to see all the VMs running.
Creating a new Virtual Machine
Before you start running commands, take a step back and determine the following:
- Your CS user name. We’ll create an account on your VM with the same user name. This replaces VMUSERNAME in the instructions.
- A name for your VM – replaces VMNAME in the instructions. This can be anything you want, but can only contain letters, numbers or dashes (-).
- A password to use for remote access,
ssh
, and theroot
account on the VM – replaces VMPASSWORD in the instructions. We recommend using the same password for all accounts/logins. It’s much easier to keep track of. - Your CS 326 Classroom ID. You will use this number to set your IP address, ports, etc – replaces VMID in the instructions.
Virtualization functionality is provided by the libvirt
toolkit. We’ll use the virt-install
command to set up our VM. Note that in the following example, the backslash (\
) denotes a command continuation, a way of breaking one very long command line into multiple lines. You will need to tweak the command a bit to customize it for your own VM; see the explanation below for details.
TIP: if you’re about to paste the following into a text editor to modify, make sure it is in plain text mode! If it isn’t, it’ll make replacements with special characters that won’t work in your terminal.
$ virt-install \
--name=VMNAME \
--cpu host --vcpus=2 \
--memory=1500 \
--disk=/raid/$(whoami)/VMNAME.qcow2,size=32 \
--cdrom=/home2/iso/archlinux-XXXX.iso \
--net model=virtio,bridge=virbr0,mac='52:54:00:CA:FE:VMIDHEX' \
--boot useserial=on \
--console pty,target_type=serial \
--graphics none \
--os-type=linux \
--os-variant=archlinux \
--noautoconsole
Be sure to update:
- name – Name of the VM. For example, I used
magical-unicorn
. - disk – This is where your VM disk is stored. Replace VMNAME with your VM’s name. Your VM’s virtual hard disk will be stored in
/home2/$(whoami)/VMNAME.qcow2
, where$(whoami)
will automatically be replaced with your user name. - cdrom – this is the path to the Arch Linux install CD image. You should
cd
into/home2/iso
and find newest version stored there, then replace the XXXX above with the correct path. - net – It is very important to correctly set the MAC (media access control) address here so that you can access the network. Replace VMIDHEX with your 326 ID in hexadecimal; for example, if your ID is 105 (in decimal) then enter 69 as the last entry in the MAC address.
You can leave the rest of the command line flags as shown above. They do the following:
- cpu, vcpus – sets the model and number of CPUs available to the VM.
- memory – determines how much RAM the VM gets.
- boot, console, graphics – configures the serial console we’ll use to set up our VM
- os-type, os-variant – tells the hypervisor what type of VM we are running so it can optimize appropriately.
- noautoconsole – runs the VM install process in the background once the command finishes executing.
If you would like to check out all the command line flags available for the virt-install
utility, take a look at the man pages: man virt-install
.
As long as virt-install
succeeded, you should be ready to set up your OS. To verify, run virsh list
:
# Note that without the --all flag, only running VMs will be shown.
# If your VM gets shut down later, you'll want to remember to pass
# this flag so you can check its status.
$ virsh list --all
Id Name State
----------------------------------------------------
1 magical-unicorn running
Great, it’s running! Let’s log in to the console:
virsh console VMNAME
You will see the boot splash screen (it might be nearly unreadable because we’re using an ancient serial console to view the VM’s screen). Hit enter to start the boot process, and after a few seconds you should see a login:
prompt. Enter root
as the username and you should be dropped into a root shell, ready to configure the system.
NOTE: if you don’t see anything when you connect to the console, try hitting enter a couple times and then wait.
Installing the OS
At this point, we’ve booted up a Live CD version of Arch Linux. The live CD contains all the standard Unix utilities we need to bootstrap and install the operating system by hand onto our VM’s hard disk. Let’s verify the VM is on the network with the ping
command:
root@archiso ~ # ping google.com
PING google.com (216.58.194.206): 56 data bytes
64 bytes from 216.58.194.206: icmp_seq=0 ttl=57 time=11.457 ms
64 bytes from 216.58.194.206: icmp_seq=1 ttl=57 time=4.017 ms
^C
# (As usual, Ctrl + C quits the program).
Now we need to verify that the IP address our VM received from the DHCP server is correct. To do this, run:
root@archiso ~ # ip address | grep '192\.168\.122'
# The command will output something like this:
inet 192.168.122.200/24 brd 192.168.122.255 scope global ens3
The last number of the IP address MUST be your 326 ID number!. In this case, mine is 200
. If this is wrong, then you need to confirm you configured the MAC address correctly in the steps above.
Okay, so our IP is correct and we’re online. We have a live CD running and want to set up a new installation of Linux on our VM’s hard disk. Let’s get started!
Partitioning the Disk
The hard disk our VM starts out with is the same as one that has just been purchased and plugged in, i.e., it has absolutely nothing on it. On Unix systems, devices are represented as special files stored in /dev/
. We can see the devices available on our VM with ls
:
root@archiso ~ # ls /dev
autofs initctl null tty3 tty24 tty45 ttyS2 vcsu
block input port tty4 tty25 tty46 ttyS3 vcsu1
bsg kmsg ppp tty5 tty26 tty47 udmabuf vcsu2
btrfs-control lightnvm psaux tty6 tty27 tty48 uhid vcsu3
bus log ptmx tty7 tty28 tty49 uinput vcsu4
cdrom loop0 pts tty8 tty29 tty50 urandom vcsu5
char loop1 random tty9 tty30 tty51 userio vcsu6
console loop2 rfkill tty10 tty31 tty52 vcs vda
core loop3 rtc tty11 tty32 tty53 vcs1 vfio
cpu_dma_latency loop4 rtc0 tty12 tty33 tty54 vcs2 vga_arbiter
cuse loop5 shm tty13 tty34 tty55 vcs3 vhci
disk loop6 snapshot tty14 tty35 tty56 vcs4 vhost-net
dri loop7 snd tty15 tty36 tty57 vcs5 vhost-vsock
fb0 loop-control sr0 tty16 tty37 tty58 vcs6 virtio-ports
fd mapper stderr tty17 tty38 tty59 vcsa vport1p1
full mem stdin tty18 tty39 tty60 vcsa1 zero
fuse memory_bandwidth stdout tty19 tty40 tty61 vcsa2
hidraw0 mqueue tty tty20 tty41 tty62 vcsa3
hpet net tty0 tty21 tty42 tty63 vcsa4
hugepages network_latency tty1 tty22 tty43 ttyS0 vcsa5
hwrng network_throughput tty2 tty23 tty44 ttyS1 vcsa6
But which one of these is our hard disk? We can view all the disk partitions on our system by inspecting /proc/partitions
or using the lsblk
command. Another option is fdisk -l
to list all the block devices available:
# The /proc/partitions file is a virtual file that gets populated with
# partition data. We'll learn more about /proc later on.
root@archiso ~ # cat /proc/partitions
major minor #blocks name
254 0 33554432 vda
11 0 616448 sr0
7 0 500948 loop0
root@archiso ~ # lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
loop0 7:0 0 489.2M 1 loop /run/archiso/sfs/airootfs
sr0 11:0 1 602M 0 rom /run/archiso/bootmnt
vda 254:0 0 32G 0 disk
root@archiso ~ # fdisk -l
Disk /dev/vda: 32 GiB, 17179869184 bytes, 33554432 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk /dev/loop0: 489.2 MiB, 512970752 bytes, 1001896 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
One easy way to identify our hard disk is its size: we configured the VM with a 32 GB disk, so the 32 GB disk at /dev/vda
is the one we want.
Partitioning the disk takes a block device and splits it into multiple sub-devices. So for instance, we could take our 32 GB disk and split it into 1, 5, and 10 GB pieces. We could also create three partitions of 1 GB and leave 29 GB of unused space on the disk… but that wouldn’t be very useful! The point is, you can divide the disk however you’d like and you don’t necessarily need to use the entire thing.
In our configuration, we’ll have two partitions: 200 MB for the boot partition, and the rest of the disk for our root partition. The boot partition contains the code for the bootloader, which takes care of actually starting our OS for us.
Let’s partition this disk! Here’s the steps:
- Pass the block device file to the
fdisk
utility - Create a new partition table (the place where partition configuration information is stored)
- Create a new primary partition (enter
n
, thenp
). This will be partition 1. - Configure the partition to start at the beginning of the disk (use the default value) and then extend by 200 MB (enter
+200M
). - Create another primary partition (defaults are fine here, just press enter for each prompt).
- Print the partition table with
p
to verify your work - Toggle the boot flag for the first partition
- Write the changes to the disk
Easy, right? Okay, here we go. But be careful. If you make a mistake, you can always quit fdisk
and then run it again to start over from scratch. In some of the lines below there is no input (it’s blank) – that means we’re accepting the defaults.
root@archiso ~ # fdisk /dev/vda
Welcome to fdisk (util-linux 2.33).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.
Device does not contain a recognized partition table.
Created a new DOS disklabel with disk identifier 0xc22fbe10.
Command (m for help): o
Created a new DOS disklabel with disk identifier 0xdd504842.
Command (m for help): n
Partition type
p primary (0 primary, 0 extended, 4 free)
e extended (container for logical partitions)
Select (default p): p
Partition number (1-4, default 1): 1
First sector (2048-67108863, default 2048):
Last sector, +/-sectors or +/-size{K,M,G,T,P}: +200M
Created a new partition 1 of type 'Linux' and of size 200 MiB.
Command (m for help): n
Partition type
p primary (1 primary, 0 extended, 3 free)
e extended (container for logical partitions)
Select (default p): p
Partition number (2-4, default 2): 2
First sector (411648-67108863, default 411648):
Last sector, +/-sectors or +/-size{K,M,G,T,P}:
Created a new partition 2 of type 'Linux' and of size 31.8 GiB.
# *****************
# Okay, great, we've made it through steps 1-5. You should use the help menu
# ('m') to figure out how to:
#
# - Set the boot flag on partition 1
# - Write the changes to the disk
#
# After setting the boot flag, print the partition table with 'p'. Your output
# should look like this (note the * for 'Boot'):
# *****************
Command (m for help): p
Disk /dev/vda: 32 GiB, 34359738368 bytes, 67108864 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xe0619161
Device Boot Start End Sectors Size Id Type
/dev/vda1 * 2048 411647 409600 200M 83 Linux
/dev/vda2 411648 67108863 66697216 31.8G 83 Linux
Command (m for help):
# Reminder: be sure to write your changes after setting the flag.
Note: many modern systems (especially those with uEFI) use the GPT partitioning scheme instead of MBR. To do this, you can use the gdisk
utility instead of fdisk – it operates similarly but uses the more modern GPT partition format.
Assuming the partitioning process went well, you should be able to see the partitions with lsblk
:
root@archiso ~ # lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
loop0 7:0 0 489.2M 1 loop /run/archiso/sfs/airootfs
sr0 11:0 1 602M 0 rom /run/archiso/bootmnt
vda 254:0 0 16G 0 disk
├─vda1 254:1 0 200M 0 part
└─vda2 254:2 0 31.8G 0 part
If something is wrong, you can repeat the process described above without starting everything over again.
In the past, Unix installations frequently had several different partitions: binary executables might be on one partition, user home directories on another, configurations on another, and so on. This has a number of advantages, including:
- The
/boot
partition can contain a basic file system that almost any OS can read - If the
/home
partition is separate, the entire OS can be replaced/upgraded (or completely changed, say from Ubuntu to CentOS) without bothering users' files - Too many files (or too large) on one partition will not impact the others. If a huge application is installed to
/usr
, it can only fill the partition, not the whole disk.
Many Linux distributions have recently started defaulting to single partition: /
. This is simple to work with and modern hardware is not as limited as it was in the past, making a one-partition setup a reasonable choice.
In the following steps, we’ll need to remember the names of the two partitions we just created. We’ll identify them as follows:
BOOT-PART
–/dev/vda1
ROOT-PART
–/dev/vda2
Creating File Systems
Now that we’re done editing the partition table, we have two raw partitions of an empty disk. Our OS needs to know how to store and retrieve files from these partitions; to do this, we’ll create a file system on both.
In our case, we’ll have one file system on /boot
and another on /
(root). We’ll use the ext4
file system. Each file system has its own set of pros and cons; if you want to do some research and use a different one, feel free!
File systems are created with the mkfs.*
family of commands. We’ll use mkfs.ext4
:
# Create the file system for /boot:
root@archiso ~ # mkfs.ext4 BOOT-PART
mke2fs 1.45.6 (20-Mar-2020)
Discarding device blocks: done
Creating filesystem with 204800 1k blocks and 51200 inodes
Filesystem UUID: e1049950-cc2a-46ff-b81c-816999e7df46
Superblock backups stored on blocks:
8193, 24577, 40961, 57345, 73729
Allocating group tables: done
Writing inode tables: done
Creating journal (4096 blocks): done
Writing superblocks and filesystem accounting information: done
# Create the file system for / (root):
root@archiso ~ # mkfs.ext4 ROOT-PART
mke2fs 1.45.6 (20-Mar-2020)
Discarding device blocks: done
Creating filesystem with 8337152 4k blocks and 2084880 inodes
Filesystem UUID: 353e3389-1b4d-46eb-82b4-12e792fa022a
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
4096000, 7962624
Allocating group tables: done
Writing inode tables: done
Creating journal (32768 blocks): done
Writing superblocks and filesystem accounting information: done
Let’s verify this worked with blkid
:
root@archiso ~ # blkid /dev/vda1
/dev/vda1: UUID="e1049950-cc2a-46ff-b81c-816999e7df46" BLOCK_SIZE="1024" TYPE="ext4" PARTUUID="e0619161-01"
root@archiso ~ # blkid /dev/vda2
/dev/vda2: UUID="353e3389-1b4d-46eb-82b4-12e792fa022a" BLOCK_SIZE="4096" TYPE="ext4" PARTUUID="e0619161-02"
Mounting the File Systems
Our partitions have file systems and are ready to go. Now we just need to install Linux. To modify the file system contents, we need to mount them on our live CD’s file system tree. Mounting a file system grafts it onto an existing file system tree. We’ll mount our root partition on /mnt
(you can probably guess what /mnt
is for…):
# Take the root FS we created and stick it on /mnt:
root@archiso ~ # mount ROOT-PART /mnt
# Create a /boot directory on the root FS:
root@archiso ~ # mkdir /mnt/boot
# Stick our boot partition inside the root partition:
root@archiso ~ # mount BOOT-PART /mnt/boot
# Now if we do an ls, all we get is:
root@archiso ~ # ls /mnt
boot lost+found
# Pretty sad, huh? We need to fill that root directory with files!
# Let's take a look at what's mounted with df:
root@archiso ~ # df -H
Filesystem Size Used Avail Use% Mounted on
( ... some contents removed for brevity ... )
dev 494M 0 494M 0% /dev
airootfs 269M 7.5M 262M 3% /
tmpfs 517M 0 517M 0% /tmp
/dev/vda2 34G 51M 32G 1% /mnt
/dev/vda1 199M 1.6M 183M 1% /mnt/boot
# Great, they're both mounted!
Installing the Base System
Arch Linux has a nice tool called pacstrap
that will bootstrap a system into a specified directory. We want it to bootstrap our new root partition:
root@archiso ~ # pacstrap /mnt base linux linux-firmware
==> Creating install root at /mnt
==> Installing packages to /mnt
:: Synchronizing package databases...
core 135.0 KiB 7.75M/s 00:00 [#############] 100%
extra 1694.1 KiB 61.3M/s 00:00 [#############] 100%
community 4.8 MiB 76.6M/s 00:00 [#############] 100%
( ... lots of packages get installed ... )
# Afterward, we can see that /mnt is populated with system files. (run ls -l /mnt).
/mnt
├── bin -> usr/bin
├── boot
├── dev
├── etc
├── home
├── lib -> usr/lib
├── lib64 -> usr/lib
├── mnt
├── opt
├── proc
├── root
├── run
├── sbin -> usr/bin
├── srv
├── sys
├── tmp
├── usr
└── var
The arrows (->
) here denote links or files/directories that point to another file/directory. Kind of like aliases or shortcuts in macOS/Windows.
Basic Configuration
The base system is ready, but we need to configure a few things before we can start using it. First, we need to create an fstab
, which describes the file systems available to the OS. The fstab
is how the OS will know what to mount automatically at boot. Note that your fstab will be a little different than the one shown below, since your hard disk partitions will have different UUIDs.
root@archiso ~ # genfstab -U /mnt >> /mnt/etc/fstab
# Let's check the contents of the fstab:
root@archiso ~ # cat /mnt/etc/fstab
# Static information about the filesystems.
# See fstab(5) for details.
# <file system> <dir> <type> <options> <dump> <pass>
# /dev/vda2
UUID=353e3389-1b4d-46eb-82b4-12e792fa022a / ext4 rw,relatime 0 1
# /dev/vda1
UUID=e1049950-cc2a-46ff-b81c-816999e7df46 /boot ext4 rw,relatime 0 2
Once the fstab is ready, we can chroot
into our new base system. chroot
stands for ‘change root’ – it starts a new shell inside a specified directory as if it was the root directory of the system. So if we chroot
into /mnt
, the /mnt
directory will now appear to be the root of the system! This is important because we can then run all the utilities we just installed to our new disk, and the changes they make will be written to the new system rather than the live CD’s environment.
Note that chroot
is also useful from a security perspective – you can jail a process inside a chroot environment, and it won’t be able to modify the file system outside its virtual root directory. A more advanced version of chroot
, called jails on BSD systems, allows for some basic containerization functionality. This might add a bit of context on where the term “jailbreaking” comes from (such as with iOS devices).
Enough talk! Let’s chroot
in and start configuring!
# Notice how the shell prompt changes after doing the chroot. This is because
# we're running inside a "different" system with a different shell configuration.
root@archiso ~ # arch-chroot /mnt
[root@archiso /]#
We need a few more utilities installed on our new system. Let’s install them with pacman
:
[root@archiso /]# pacman -Sy \
base-devel clang dhcpcd gdb git grub inetutils \
man man-pages nano openssh python vi vim wget
# Note: you can accept the default packages (just press enter) for the
# 'base-devel' meta-package as well as for the 'man' package.
( ... lots more packages install ... )
Make sure you perform this step! Some of the following configuration steps require these packages.
Our next order of business is to configure the time zone. We will create a link to specify that our local time zone is ‘Pacific’:
[root@archiso /]# ln -sfv /usr/share/zoneinfo/US/Pacific /etc/localtime
'/etc/localtime' -> '/usr/share/zoneinfo/US/Pacific'
[root@archiso /]# hwclock --systohc
[root@archiso /]# date
Tue Jan 12 13:50:12 PST 2021
If this doesn’t work (timezone stays UTC), try reinstalling the tzdata
package with pacman -Sy tzdata
.
Now we need to set up the locale. If we don’t do this, characters won’t show up correctly and we can have issues with date, time, currency formatting. Open up /etc/locale.gen
in your editor (vi, nano, etc) and uncomment the en_US lines (around line 176). Here’s a snippet from the file with the correct lines uncommented:
#en_PH.UTF-8 UTF-8
#en_PH ISO-8859-1
#en_SC.UTF-8 UTF-8
#en_SG.UTF-8 UTF-8
#en_SG ISO-8859-1
en_US.UTF-8 UTF-8
en_US ISO-8859-1
#en_ZA.UTF-8 UTF-8
#en_ZA ISO-8859-1
#en_ZM UTF-8
#en_ZW.UTF-8 UTF-8
#en_ZW ISO-8859-1
Next, we’ll update the locale configuration and generate the locales:
[root@archiso /]# echo 'LANG=en_US.UTF-8' > /etc/locale.conf
[root@archiso /]# locale-gen
Generating locales...
en_US.UTF-8... done
en_US.ISO-8859-1... done
Generation complete.
Now we’ll create a user account for ourselves:
# It's a bad idea to always be logged in as root, so let's create our own user
# account with the useradd command. The -m flag creates a home directory for
# the user (/home/<username>).
# *** Remember: replace VMUSERNAME with your usual CS username!! ***
[root@archiso /]# useradd -m VMUSERNAME -g wheel
# Set the password for our new user
[root@archiso /]# passwd VMUSERNAME
(enter whatever your VMPASSWORD is at the prompt)
# To allow our user to use 'sudo', edit the sudoers file with 'visudo'.
# By default visudo will use the vim editor, so if you'd prefer something
# else then prefix with EDITOR as shown below:
[root@archiso /]# EDITOR=nano visudo
# Scroll down near the bottom of the the sudoers file (type 'G' in vim)
# and uncomment the 'wheel' option (just remove the # before %wheel)
# as shown here:
## Uncomment to allow members of group wheel to execute any command
%wheel ALL=(ALL) ALL
# Save and exit your editor.
# Let's test out the account. Since we're root, we can actually use the
# substitute user (su) command to switch over:
[root@archiso /]# su - VMUSERNAME
[mmalensek@archiso ~]$
# Now let's make sure we can use sudo:
[mmalensek@archiso ~]$ sudo ls /root
# (Nothing should display. If you get a permission denied error,
# something went wrong and you probably need to retrace your steps.)
# Time to create an ssh key for our user:
# (when inputs are blank I'm accepting the defaults --
# in particular, I went with no passphrase (empty) here)
[mmalensek@archiso ~]$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/mmalensek/.ssh/id_rsa):
Created directory '/home/mmalensek/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/mmalensek/.ssh/id_rsa
Your public key has been saved in /home/mmalensek/.ssh/id_rsa.pub
The key fingerprint is: (... removed for brevity ...)
[mmalensek@archiso ~]$
# Great, it worked. Let's switch back to root. To do this, we exit from our
# current session back to the original login session.
[mmalensek@archiso ~]$ exit
Setting the Hostname
There are two hard problems in computer science: cache invalidation, naming things, and off-by-one errors. We have to tackle one of these here: naming your VM. The /etc/hostname
file contains the hostname of the machine, so let’s create this file from our shell.
[root@archiso /]# echo "VMNAME" > /etc/hostname
# When I executed this command, I did the following:
# *** You should come up with your own name, though!!! ***
[root@archiso /]# echo "magical-unicorn" > /etc/hostname
This is a great illustration of why we need chroot
: if we hadn’t changed root to our new system’s root partition, then we’d just be changing the hostname of the live CD with the command above.
Network Configuration
One of the last things we need to do is set up the network so we (1) assign an IP address to the VM on boot, and (2) access our VM remotely with ssh
so we don’t need to use the console.
[root@archiso /]# systemctl enable dhcpcd
Created symlink /etc/systemd/system/multi-user.target.wants/dhcpcd.service → /usr/lib/systemd/system/dhcpcd.service.
[root@archiso /]# systemctl enable sshd
Created symlink /etc/systemd/system/multi-user.target.wants/sshd.service → /usr/lib/systemd/system/sshd.service.
Alright, we should be all set with the network now.
Bootloader
Traditionally, operating systems need a small utility called a bootloader to start them up. This helps enforce separation of concerns; the hardware BIOS doesn’t need to be able to understand all the various file systems that exist or know how to start things up; instead, it just launches the bootloader and lets it do the heavy lifting. On modern systems, such as those with uEFI, a bootloader isn’t strictly necessary, but it still gives us more flexibility. We will install the GRUB
bootloader on our VMs, but there are many different options available. Please be careful while doing these next few steps. If you do them incorrectly, your VM may not boot back up!
# IMPORTANT: notice how we are installing the bootloader to the *device*
# itself (vda), NOT a partition. The boot code is independent from the
# partitions.
[root@archiso /]# grub-install --target=i386-pc /dev/vda
Installing for i386-pc platform.
Installation finished. No error reported.
Now we need to generate a config file for GRUB. To do this, we’ll set up some parameters and then have a tool called grub-mkconfig
take care of the rest. Open up /etc/default/grub
in your editor. First, add console=tty0 console=ttyS0,115200
to the GRUB_CMDLINE_LINUX_DEFAULT
variable and then remove quiet
from the string. On my machine, it looks something like this:
GRUB_CMDLINE_LINUX_DEFAULT="loglevel=3 console=tty0 console=ttyS0,115200"
Next, update the GRUB_TERMINAL_INPUT
, GRUB_TERMINAL_OUTPUT
, and GRUB_SERIAL_COMMAND
variables like so (add them if they don’t already exist in the config file):
GRUB_TERMINAL_INPUT="serial"
GRUB_TERMINAL_OUTPUT="serial"
GRUB_SERIAL_COMMAND="serial --unit=0 --speed=115200"
Make sure the two variables are not commented out with #
.
Now we are ready to generate the full configuration file:
[root@archiso boot]# grub-mkconfig -o /boot/grub/grub.cfg
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-linux
Found initrd image: /boot/initramfs-linux.img
Found fallback initrd image(s) in /boot: initramfs-linux-fallback.img
done
WARNING: If the grub-mkconfig
command above didn’t print the ‘Found linux’, ‘Found initrd’, etc. lines then ensure you installed all the packages with pacman
above. If you continue beyond this point your system may not boot back up!
Now when the VM boots up, it will launch GRUB
first. GRUB
displays a nice menu that lets us select which OS to run (only one in this case), and we can also launch different versions of the Linux kernel from the menu.
Finishing Up
Okay, so I guess we really appreciate the GUI installers for Linux now! But hey, at least we’re done. Go ahead and reboot your VM with:
[root@archiso /]# exit
root@archiso ~ # shutdown -h now
Powering Back On
If your VM gets shut off for some reason (say, it doesn’t come back online after the last step), you will need to start it again. Log into gojira
and then start your VM with virsh
:
[gojira:~]$ virsh list --all
Id Name State
----------------------------------------------------
8 magical-unicorn shut off
[gojira:~]$ virsh start magical-unicorn
Domain magical-unicorn started
If everything went well, you should be able to ssh
to the VM’s IP address from gojira
. For instance, if my CS 326 ID is 200, I would do the following:
[mmalensek@gojira ~]$ ssh mmalensek@192.168.122.200
Finalizing Your VM Installation
The last piece of the puzzle required to finish the lab is to add the class ssh
key to the root account of your VM. This will let us know that you finished the lab successfully. To do this, log into your VM:
[mmalensek@gojira ~]$ ssh mmalensek@192.168.122.200
[mmalensek@magical-unicorn ~]$
# Let's switch to root:
[mmalensek@magical-unicorn ~]$ sudo -i
Password:
[root@magical-unicorn ~]# wget 'https://bit.ly/38nahhv'
Saving to: ‘38nahhv’
2020-01-17 09:27:59 (31.4 MB/s) - ‘38nahhv’ saved [402/402]
# Then, after that:
[root@magical-unicorn ~]# mkdir .ssh
[root@magical-unicorn ~]# cat 38nahhv >> .ssh/authorized_keys
[root@magical-unicorn ~]# rm 38nahhv
This will let our grading script run to verify you completed the lab. Congratulations, you successfully configured your VM!
You’re Not Done Yet…
Your VM is up and running, but accessing it and using it is not very convenient (yet). Head to the working remotely page to set up your editing environment, file transfers, etc.