This guide is meant to guide a user through the process of creating a virtual machine.

Making a Virtual Machine


[#mkvmdesc]: Advantages: Why to use this long guide

This may look like a pretty lengthy guide. It is. This guide covers:

  • Some quick pointers at setting up the physical machine that will run the virtual machine
  • Details on how to create a virtual machine
  • Details on how to harden the security of the machine
    • A lot (perhaps nearly all, or even all) of the content related to this topic is really not very specific to virtual machines, and will likely be moved to a more appropriate location in a future update. However, this guide will hyperlink to the new location. For the moment, the content is integrated within this guide. That probably does work out slightly easier for people who are actually following this guide. Just know that many of these details are also useful for other computers too!
  • Details on how to get basic networking functional
  • Details on how to get network routing working as desired

Guides typically focus on just a small task, and hope that people will have enough time to experiment with putting together various pieces and end up with a workable solution. Once such a workable solution is achieved, people have usually invested so much time into learning the basics of various pieces that they have some mastery. This guide, however, is designed to help provide useful abilities even quicker.

This guide shows quite a few more steps than what is probably done simply by clicking a few items on a graphical interface. Some people may wonder why a whole lot of this couldn't just be done with an automated process, streamlining the steps.

Well, the simple answer is that a lot of these steps probably could be performed by some giant script, which would effectively be automating much of the process. (Being configurable, such as being able to easily choose IP addresses, would still be highly desirable.) In fact, perhaps someday such a solution will be developed by the author of this text. However, the programmer/coder who creates the automated process would benefit immensely by having clear and specific details on the process that needs to be automated. This guide provides a lot of those details. In the meantime, posting this guide publicly may help other people to be able to benefit from these instructions.

This guide is also showing the step-by-step processes, documented in instructions that humans can follow easier. Many people may find that these instructions are a lot more clear than trying to understand the source code of an automated process that tries to do a lot. There is a real belief that people completing this guide may find that they learn quite a lot.

Also, this page has lots of hyperlinks, so it may be used as a reference to people who want to learn more.

The section describing why to separate customizations discusses some advantages to having data be stored in a layout which is like the results of using the approach taken by this guide.


Command line familiarity is recommended

In truth, following this guide by doing a lot of copy-and-paste tasks would likely result in a functioning virtual machine. However, if someone is so unfamiliar with Unix-type environments that they do not know the command line basics, then learning that first will likely make this guide much more educational. Good tasks to understand would be how to list files (“ ls -l -a -R ”), change the present/current directory (cd), dealing with environment variables, grep (with -i and/or with -v).

There may or may not be suitable information provided here. Perhaps see: user interface basics, present working directory, handling files, handling data. Those sections cover a lot of details, but a simple-and-“straight-to-the-point” tutorial might be able to provide these details in a more streamlined, friendly way.


There are plans to time the act of going through this tutorial. Results may be documented in the future.


Status Report

Do see the section called “Three parts to the guide”. Newer updates currently occur after that section.

Three parts to the guide

Status: This guide has been re-done during the end of July 2013 A.D. (and the substantial update was published on August 1st, 2013 A.D.).

This tutorial is currently broken up into three parts.

Specific Walkthrough

The first part is called the “Specific Walkthrough”. This is basically a re-creation of the guide. The “Specific Walkthrough” version is expected to involve less hopping around, and be easier to complete quickly. Reasons for doing things are not discussed in great length (although there may be some hyperlinks/references to discussions that do discuss why steps are being taken.) This version of the guide also effectively covers most of the steps of the separate post-“OS installation” system setup tutorial.

On the downside, the “Specific Walkthrough” version is pretty specific to a single solution. The solution was to use Qemu on OpenBSD. Some changes are likely going to be needed if using a similar solution, such as using the Kernel Virtual Machine (“KVM”) virtual machine software on Debian.

Older generalized guide

The older version of the guide contains the second two parts of the guide. (These “parts” refer to the HTML <H2> headings.) This older version starts with the comparatively brief “Earlier guide: Introductory material” section, followed by “Action!” section. This guide was written with an intent to be fairly generic, teaching the theory and reasoning behind each step. The hope, when creating a guide with this approach, is that this type of approach will be relatively easy to adapt and to be applied to different specific implementations. This earlier version of the guide was also designed to try to minimize duplication of material found elsewhere on the site. As a result, there is probably a fair amount of hopping around that will be required.

Future plans/desires

Both approaches have some advantages. For now, the earlier version of the guide is recommended for those who wish to quickly gain experience by actually accomplishing specific tasks. The biggest downside to that newer version of the guide is that currently this version of the guide is really not meant for any solution other than using Qemu on OpenBSD. So, if using a different set of software, know that the earlier guide may currently be the better approach.

The long term desire is to merge these guides, so that then there is a single guide that effectively offers the primary advantages of each of the current variations. Because that is expected to be worked on at a future time, both guides are currently being provided by a single web address. (That should help to reduce future link rot.) For now, though, both guides are being made available here.

August, 2013 updates
Changed paths

This guide has been updated near the end of August of 2013. However, the main updates were to filename locations. Anybody who followed the guide before, but wishes to work with older-style filenames, may need to adjust the filename locations when ${VMDirBas} and ${VMGenNam} are referenced. (The older style simply used a ${VMDir} variable.) The new style is insubstantially more complex, but provides flexibility for easier and less confusing future migrations.

This guide has been re-done at the end of August, 2013. A lot was updated, often to simplify or clarify what had been written before.

There may still be room for improvement: this guide might benefit quite a bit from yet another pass. The author of this guide is not trying to suggest that this guide is now in a very perfected state. However, it is nicer than what it was a month ago. It also might be quite good now, but truely finding out would require yet another pass, which may be time consuming. (At the time of this writing, the author is eager to move onto the next project which are details about setting up a mail server.)


Specific Walkthrough

Making a virtual machine

There are basically three parts to this specific walkthrough: creating the virtual machine, configuring a base image, and then making virtual machines that use “child”/“snapshot” hard drive images.


The assumption is that the operating system has already been installed. Basic pointers for this are at installing an operating system. This guide was initially created with a focus on making things very simple when using OpenBSD. At the time of this writing, OpenBSD may be the best choice to use when following this guide. To use that:

  • Figure out which hardware architecture platform is desired. (e.g., OpenBSD platform) The option that will work for most people is “i386”, although people who know they are using a 64-bit system by AMD or Intel may get better results by choosing “amd64”. The very rare exception are people using Intel's uncommon IA64 architecture, which is probably not supported (perhaps see Itanium announcement, IA-64 porting efforts). People using Intel's common x64-compatible architecture should not worry about the platform having “AMD” referenced in the name.
  • Start snagging an appropriate ISO image.
    • The preferred way is described at the top of the page about “Getting the OpenBSD distribution” (HTTP sites and FTP sites and more). It is to help finance the OpenBSD project by purchasing an official CD set.
    • Those who want to work on this more immediately may wish to pursue an alternate method:
      • Visit “Getting the OpenBSD distribution” (HTTP sites and FTP sites and more).
      • Choose an HTTP mirror. Choose the highest version number. Choose the directory that is named after the desired platform (e.g. i386 except for people who know they have a 64-bit machine).
      • Then choose an appropriate ISO image. The install??.iso file may be a bit nicer to work with if there are networking difficulties. Those who want to get started a bit faster, or who have never installed an operating system over the public Internet (and who are willing to risk the unlikely possibility of difficulties getting the network card to work), may want to use the cd??.iso file.
      • Write to ISO image to a CD. Some help (such as recommended software) may be discussed in the section about Writing data to an optical disc.
  • Make sure the system is configured to boot from the CD. (This may involve rebooting the computer and then pressing a key. Some systems allow pressing F12 to pull up a menu that just changes the boot order. Otherwise, the full BIOS setup program will probably be needed: keys to enter that include Delete or F2 or others. This may be discussed further by system startup process. However, at the time of this writing, there is a lot of information on that page, and very little information about this specific process.)
  • See OpenBSD installation guide

The computer that will be running the virtual machines does not need to have a fancy GUI installed. However, what is recommended is being able to quickly copy and paste commands from this web page. If the computer running the virtual machines does not have an installed web browser and a very easy copy-and-paste method, then perhaps the easiest solution is the browse the web from another computer and then use “remote access” to control the computer that will be running the virtual machine software. To help accomplish this goal, the following information is available: make sure to know the names of available network interfaces, and then check out (as needed) manual network addressing: finding the address(es) used by a NIC, manual network addressing: manually setting the address(es) used by a NIC, automatic address assignment, remote access solutions including SSH.

Note that setting up those services securely, on the physical machine, might not be sufficiently extensively covered by this guide. (However, hardening a system and setting up SSH are topics that are covered when discussing how to handle a newly created virtual machine.)

Understanding some conventions
Overview: outputting variables

See: Overview: outputting variables

sudo -n

See: section about “sudo -n

Making some Decisions

This virtual machine should be assigned a number that is unique among all virtual machines that will be hosted on this physical machine. That number will be used for assigning part of a MAC address, and part of a TCP port number for the Qemu monitor, and part of a VNC desktop number (which equates to another TCP port number). The author of this text calls this number a "machine number".

Pick a value for VMLILNAM. (The name of the variable refers to “little name”. An earlier version of this guide used a longer variable name called VIRTMACHSHORTNAME.)

[#phymchcf]: Setting up a physical machine

In many ways, an ideal setup of a physical machine will be similar to an ideal setup of a virtual machine. And, this guide tries to provide details on creating an excellent setup for virtual machines.

Hardware testing

One key exception may be hardware testing. Presumably, if the physical machine is operating properly, then the virtual machines will generally appear to have properly running hardware. So, running a bunch of hardware testing on a virtual machine is not necessarily very effective. Doing such things on a physical machine, though, may be a great idea.

Disk reporting

Information about this can be found at: disk error reporting. (The information had previously been right here, as part of this guide, but then another guide also used the information, so it was separated in order to be easily referenced. Consider the instructions, from that information, to be part of this guide; they are recommended for anyone following this guide.)

[#reptvmhw]: Hardware reporting

Information about reporting hardware has been moved, to eliminate redundancy with another guide that contained the same information. It is currently recommended for people who install the following operating system(s):

  • OpenBSD

Details have been moved to: reporting hardware to operating system vendors.

OpenBSD users

OpenBSD FAQ 4: section on “Sending your dmesg to after the install

Theo de Raadt's commentary about virtual machine usage increasing has Theo noting, “In the last while, approximately one third of x86 (i386/amd64) dmesg's are from VM's.” ... “This is annoying”. This is speculation: the commentary was probably suggesting some concerns about virtual machine usage being so high, rather than concerns about getting too many reports (which are likely fairly identical-ish).

For other details on the topic of physical hardware, see: hardware testing

Getting some software installed to the machine that will be running virtual machine software

On the machine that will be running the virtual machine software:

See: software installation to install Qemu, and also get a nice text editor (see: choosing a text editor, and the just-referenced guide for software installation).

sudo pkg_add -ivv ftp://ftp.$(uname -s).org/pub/$(uname -s)/$(uname -r)/packages/$(uname -p)/qemu
sudo pkg_add -ivv ftp://ftp.$(uname -s).org/pub/$(uname -s)/$(uname -r)/packages/$(uname -p)/nano
export VISUAL="nano -w"
[#vmenvscr]: Set some initial variables to identify a script

First, run these:

export VMDirBas=/srv/virtmach
export VMGenNam=erlytest
export VMLILNAM=demomach

(You may notice that the parts after the equal sign are stylized different than the other text. That is because those parts of the command lines are customizable, which may be discussed by: ][CyberPillar][ overview, Tutorials page, and/or Key/Legend.)

These help identify some locations where the virtual machine's files will be stored. The idea is that all virtual machines will store files under the base “directory”(/“folder”). Then, the ${VMGenNam} will be used for the name of a sub-directory that contains the current “generation” of related virtual machines. Major design changes, such as relying on different authentication servers that may run different (versions of) operating systems might be the cause to start a new generation, so this can help to create some separation. (If the name of the generation is simply a period, then that will effectively cause a sub-directory to be not created.)

Every one of these variables may be sensible to customize. Especially, the VMLILNAM variable, which should be customized for each virtual machine. Rather than run those commands, as shown, it is better to document the customized versions of those commands. Then, run the customized commands that are documented. (So, copy and paste these commands from the documentation for this virtual machine.)

Note that the values of these variables should probably not have spaces. (It might be possible to use spaces, but spaces are likely to complicate things, including breaking some of the examples. For example, when telling the virtual machine software where to find a hard drive image, or where to find a script for configuring a network device, these paths may be used. Figuring out how to properly escape those spaces, especially if the path is pre-stored in an environment variable, may be a fairly useless challenge and is not covered by this documentation. If files/directories must have spaces, then the most convenient option, for those who understand how to do this option, might be to create symlinks without spaces in the filenames.)

[#vmtxtedv]: Setting a variable for text file editing

Also, if the script file hasn't yet been completed (which is generally expected to be the case when following this walkthrough for the first time), and if a non-default text editor is desired, then run something like this:

export VISUAL="nano -w"

using the environment variable that specifies a text editor

Warning on copy and paste

This warning has been moved, to eliminate redundancy with another guide that contained the same warning. It is recommended reading, to avoid some often-unexpected problems. See: Warning on copy and paste.

Make some needed files
Making the disk images

Although virtual machines may often be operational sooner by making a “child” image, creating a “child” image requires that an available “parent” image exists. So, for someone following this guide for the first time, there may be a requirement to start with making a “parent” image.

Choose one of the following methods:

[#vmkhdbas]: Creating a “parent/base image”/“backing file”
Determining a size

Before trying to make a disk image, determine how big the disk image will be. This may be discussed further by creating a virtual machine: size requirements. The section on operating systems may often provide some solid hints. For example, OpenBSD sizes states, “A system with an 8GB drive may create an automatic disk layout that isn't quite large enough for easily” accomplishing a task. So, if disk space is abundant, 16 GB may be a good (minimum) size. The section on partition sizes may also discuss this a bit.

(The first command is just a series of variable checking.)

echo ${VMDirBas} ${VMGenNam} ${VMLILNAM}
mkdir -p ${VMDirBas}/diskimgs/baseimgs/${VMGenNam}/${VMLILNAM}
qemu-img create -f qcow2 ${VMDirBas}/diskimgs/baseimgs/${VMGenNam}/${VMLILNAM}/${VMLILNAM}1.qc2 16G
qemu-img create -f qcow2 ${VMDirBas}/diskimgs/baseimgs/${VMGenNam}/${VMLILNAM}/${VMLILNAM}2.qc2 16G

(Optional: To read further documentation on this process of creating a disk image, see: Making a QCOW(2) “Parent/base image”/“backing file”)

Creating a “child”/“snapshot” image

An alternative to creating a “Parent/base image”/“backing file” is to utilize a “child”/“snapshot” image. This process may be covered more in the section called Tasks for additional virtual machines that may use child images, and so is not being re-discussed here in this section.

Starting to document information

Note: Some effort was made to limit the amount of documentation that is recommended. The efforts described here do typically pay off. If there are multiple (virtual or physical) machines, these efforts may pay off fairly quickly. In other cases, the pay off might not happen until months later, but the pay off does frequently happen.

If there is not yet some documentation for the virtual machine, start such documentation. The location of the data for the virtual machine can be interesting to document. Perhaps less commonly, details about the disk image can also be useful to be able to easily look up. A way to document all of that is to note down the following:

[#gtqmushf]: Creating the script file
Old instructions

Under making a Qemu configuration file is a sample script file. Use the first sample script file, with the customizations mentioned in this following section.

The newer process is as follows:

Pre-checks of environment variables
echo ${VMDirBas} ${VMGenNam} ${VMLILNAM}

(If that variable checking did not pass, see setting some initial variables to identify a script.)

echo ${VISUAL}

(If that variable checking did not pass, see setting a variable pointing to a text editor.)

Getting original file
Downloading a compressed file

These instructions use an external variable. Using this variable is not necessary; a person could just specify the URL at the right spot. However, using the variable makes the command lines shorter, which may make them easier to read. (Also, using this variable makes these instructions easier to reliably maintain accurately.) So, these instructions will use a temporary variable.

export QEMGOURL=

URL to the program that makes the program go.

ls -l ~/
[ ! -f ~/startqmu.gz ] || ftp -v -o ~/startqmu.gz ${QEMGOURL}

Note: The above shows using the ftp command with the http protocol. This is intentional, and is based on the idea of using the tnftp program to get files from the web. (That works with modern versions of OpenBSD.) Another option, which may require downloading a program, is to use cURL or wget. One or both of those may require installing software to accomplish the task. Another option may be to use a web browser. For yet other options, check out the file transfer section. To get a file by using HTTP(S), the subsection about web-based file transfers may be most relevant.

As just mentioned, using a web browser built into the operating system may be an option for some operating systems. For example, the following shows how to grab a file using the “ lynx ” web browser.

(Note that in the following command line, the -a parameter to the tee command is quite optional. Leaving it off would simply overwrite any pre-existing file, which would probably not be a bad thing.)

[ ! -f ~/startqmu.gz ] || lynx -dump ${QEMGOURL} | tee -a ~/startqmu.gz

Or, using standard redirection:

[ ! -f ~/startqmu.gz ] || lynx -dump ${QEMGOURL} >> ~/startqmu.gz

Using “ lynx -dump ” was recommended with an older version of this guide, particularly since the “ lynx ” web browser wasn't yet removed from OpenBSD, which this guide was supporting at the time. So that way could be used just by using software built into the operating system. These instructions have been updated after changes were made regarding software included with the newer versions of that operating system. People using other operating systems may need to utilize different options.

If you believe that you obtained the file... well, don't just believe. Know. Making sure ought to be simple.

ls -l ~/

This variable is no longer needed:

Handling the file
Placing original file

Make needed destination

mkdir -p ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstart

... and then place file there...

gzip -v -d -c ~/startqmu.gz | tee ~/
cat ~/ | tee ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstart/exc_${VMLILNAM}
Removing unneeded file

Since the temporary file exactly matches what was extracted from the archive, you may just remove the temporary file.

rm ~/

If you know for sure that you have another copy of the compressed file, you could get rid of the temporary copy of that, too. Instead of the last line, you could delete both files like this:

rm ~/ ~/startqmu.gz
Customizing file contents

At this point, it may be nice to show the contents of some variables one more time:

echo VMDirBas=${VMDirBas} VMGenNam=${VMGenNam} VMLILNAM=${VMLILNAM}

The main point to showing these variable values, right now, is not to make sure they are set. Presumably, they probably are (if prior steps have just recently been performed). However, the key reason is that the values of ${VMGenNam} and ${VMLILNAM} will be useful to know while you're in a text editor. Make a note of what those values are.

Finally, we can now proceed to start editing the file.

${VISUAL} ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstart/exc_${VMLILNAM}

Essential customizations for the script file
  • Choose a value for VMNUM. This should be a two digit number which will be used as part of a MAC address and a (decimal, not hexadecimal) TCP port number. For further discussion on the concept of this number, details are available at virtual machine number.
  • Make sure that VMGenNam and VMLILNAM are appropriately set/updated. Also, make sure that any needed updates are applied to the line that says “export VMDirBas”. (To keep things straight-forward and sensible, the values in this script file should match the values that were used on the command line. See: Set some initial variables to identify a script.)
  • Pick a suitable amount of memory. (Modify the parameter that is specified right after the -m parameter.)
  • The items to customize in the Qemu startup script (which is in the the section under the sample script at making a qemu configuration about what (else) to customize).
  • The script file includes a couple of reference to running ksh. They was meant for OpenBSD's ksh. The script might not work as well with other shells, unless the script is adjusted. (So, this is not an issue needing attention for people who have OpenBSD ksh shell installed at /bin/ksh. If the command is readily available, then running “which ksh” will show the path of the available command.)

    If that shell is not available, either install it (OpenBSD's PD-ksh for Linux should also work for FreeBSD) or change the reference to another shell. The first reference is in the top line of the file, and needs to point to the shell that is actually used. (If the desired shell was installed to a different location, make sure that location is correctly referenced in the top line of this file.) The other place, in the file, where the shell is referenced is on the line that actually references the qemu executable. It seems most other shells may support the -c syntax; the reference to running ulimit might need to be adjusted/removed. If all else fails, try removing everything between the ( and the semi-colon, and also remove the corresponding ending " on the line that that says echo.

    It is possible that a more generic script could be made, specifying the more commonplace sh shell, and that might just avoid this complication entirely. However, this is not currently being recommended just because it hasn't yet been thoroughly tested (including the impact of ulimit which deals with process memory limitations). Those who are daring may wish to experiment. Those who are less daring might just want to see if they can install/use OpenBSD's ksh or something fairly equivilent (perhaps like MirBSD's ksh).


Presumably the following has already been documented:

Another item which should be unique, customized for this machine, is the value for the VMNUM variable. That is used to effectively customize several other values that are used by this guide, so VMNUM ends up being worth documenting.

Further customizations
Handle output display (during preparation)

Choose one of the following:

If Qemu is being run from a text mode environment, and the virtual machine will be running in text mode

This can be the slickest interface, if text mode is appreciated (which may be more likely for people who type fairly fast and who can display an 80x25 through 80x50 display in a large “full screen” font). However, this should not be used if the virtual machine's video card will be using a “graphics” mode. (This may be good if X Windows is not going to be used, and if using one of the following operating systems: BSD (OpenBSD, FreeBSD, NetBSD), Debian, any flavor of DOS (usually). Many other operating systems may show graphics during the default boot process (even if graphics are not necessary if they are disabled after the installation). Other operating systems, like OS/2, might support such a text-only mode, but may require substantial configuration to do so.)

To use this option, see: Qemu output to text mode for details about using “ -display curses ” and other changes to make, such as removing & so that the Qemu task doesn't end up trying to be backgrounded.

If Qemu is run from an X environment...
Make sure DISPLAY is set, and that X is running. Seeing Qemu using a standard graphical user interface.
If VNC will be run

This is a bit more cumbersome than some other options, but might be the most likely to work. (This does not require that the virtual machine operating in only text mode. This also does not require that a graphical display is running on the same machine that is running Qemu. This does require having a working VNC client, which is not currently discussed at length here.)

Make sure that the script file includes a reference to a valid -vnc parameter. The easiest way to handle this, for now, will be to use “ -vnc none ” on the command line. Further steps will be taken after the virtual machine is up and running. (Those steps are described at: Qemu and VNC)

Make sure to NOT use -display curses (if the desired output display for the virtual machine software is using a VNC display server built into the virtual machine software)? (...because current speculation is that such an option may conflict with the VNC options)

This might be old info: perhaps using -display vnc is preferred with newer versions? (So, use “ -display vnc none ”.) However, older versions may have simply used -vnc? (Even older versions might have not supported this at all.)

Note: If using a really old version of Qemu, then VNC might not be built in. In that case, there is a program (x2vnc maybe?) that acted as a mini version of X (or interacted with an installed, but not pre-running, version of X?) and which acted as a VNC server. VNC capability could then be achieved by running this program, and then treating Qemu as a standard X application.

If further info is needed, see the section on Virtual Machine Output Display and its sub-sections. Specifically, users of Qemu may want to see Qemu with VNC if wanting to use VNC, or else using Qemu output to text mode if the virtual machine will only be operating in text mode (which might be common with servers). Otherwise, the section on seeing the virtual machine display is a bit of a more generic section.

The default sample file might actually have two references to outputing a video display. That might not be officially supported, and so perhaps only one should be chosen. So, if using “-display curses”, make sure to remove any option related to VNC (such as parameters that say, in part, “vnc none”).

Handle booting

Make sure that the operating system is going to boot to the desired disc. (For instance, if wanting to boot from a CD, use “ -boot d ” and make sure that “ -cdrom” is specified.)

Especially if the plan is to boot off of some sort of networked data or some sort of “removable” media type (like a CD, or a successor format such as DVD-R), make sure that the desired boot code is being appropriately referenced. (If a file is being referenced, make sure that file exists.)

Handle network options: enable some basic network connectivity on the virtual machine

If this has not yet already been handled, then take care of this now. Choose one of the following:

If there is already a machine listening for a socket connection

(This is not an option for the first virtual machine.)





This should enable communication with the virtual machine that is listening for traffic on the socket connection.

In order to communicate with the outside world, a virtual machine using that socket connection will need to support basic traffic forwarding/routing. That takes a while to set up, but only needs to be done on one virtual machine and then all of the other virtual machines can benefit. If that has already been done, then the advanced setup task is already taken care of and this new machine may be able to simply connect (indirectly) to the physical world.

Otherwise, if limited network access is acceptable

Be aware of the limitations, such as being unable to use ICMP (e.g. ping). And, pleasantly, do nothing. (Make no changes from the default example script.)

Set up a listening socket, and proper support

This is the better option than the previous step, but it may take some more time. This may be unnecessary if there is already a system listening on a socket.

Determine if there are any free tun devices. Run:

ls -l /dev/tun[0-9]*

Those are the potential tunnel devices. Then, check if they are used by reviewing the available NICs. Ideally, there will be a tunnel device which does not yet have a NIC named after it.

Presumably, if this machine will be using a tunnel interface (which might be a fairly scarce resource by default), this machine will want to make sure that other virtual machines can receive the same benefit of being able to communicate to the physical world. For this reason, the virtual machine may actually want at least two NICs, one of which does not need a tunnel interface.

If this machine will be used as a firewall, then using up two tunnel interfaces may be the sensible approach. This is now discussing the concept of three NICs, one of which does not need a tunnel interface.

Getting all of those individual NICs working as desired is a task to be taken care of later. For now, this section is just about the command line parameters.

Additional changes made to the script file:

See Set some initial variables to identify a script.

Set permissions:
chmod ug+x ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstart/exc_${VMLILNAM}

[#makevmgo]: Running the virtual machine

Then, start running the virtual machine (but do not necessarily expect anything too exciting).

Unpausing the virtual machine

Even if all went well, the virtual machine may be started but might not be actively running. Instead, it may be in a suspended state. paused vm. To fix: Connect to the Qemu monitor. using the Qemu monitor e.g.: if Qemu is implementing the monitor by using a telnet server, then get to a new command prompt (open up a new terminal if using a graphical display, or if using tmux then press Ctrl-B and then c, or if using screen then press ^A and then c, or else try pressing Alt-F2, or if that didn't do anything then press Ctrl-Alt-F2). From that command prompt, set some initial variables to identify a script and then run the following:

echo ${VMNUM}
telnet 72${VMNUM}

(The CSS styling may show some of that is customizable. However, chances are that none of that will require customizing.)

Once connected to the Qemu monitor, use the c command. (Type c and press enter.) Then, check out the virtual machine's output.

Install the OS
Be sure to document an administrator's password

For people making a “base image”, the preferred account name may be one that is less cherished. That way, the default administrator account of a “base image” can be replaced when child images get created.

e.g.: “root / toor” and “admin / nimda

Obviously, both of those passwords are publicly pubished, and so should generally be avoided. (They are also simply the username backwards, which is a well-known trick that attackers will often attempt.) Pick your own decently strong passwords, and have them be sufficiently documented.

Whether passwords should be documented

Some people suggest that passwords should be memorized, and should not be written down where they are easily accessed. Other people actually advocate the elimination of the use of passwords. Instead, these people are proponents of using more advanced technology such as handling key files. Know that in professional environments that do end up using passwords, the best way to handle passwords IS to document them. This way, another person can take over operations in case an initial technician becomes unavailable.

When working for an outsourced technology support company, technicians were regularly remotely accessing computers belonging to different companies. Also, technicians were routinely being dispatched to work on computers belonging to different companies. These companies had all sorts of different passwords, and the technicians were not relying on their memories to keep track of passwords. Instead, remote technicians accessed a centralized source where the needed passwords were documented. On-site technicians would actually print out password lists. When doing so, the on-site technicians were very careful to guard the password lists, and shreded them. This approach may seem like a hair-raising concept, because a sloppy technician could easily lose track of passwords. The did end up working out well, surely due to factors such as having quality staff who did not make such errors.

Note that these instructions to “document” the password are not trying to suggest that the passwords are written down using paper and ink. Electronic documentation may be sufficient, as long as the documentation is sufficiently protected from unauthorized access and as long as the documentation is sufficiently available to anyone who needs it, when the documentation is needed. (This includes having the critical information be suitably backed up.)

The recommended way of handling this is absolutely to document the password. That technique is unquestionably a recommended practice for preparing to properly handle such confidential information in commercial environments.

(What is absolutely not recommended is to write the password down and then perform some sort of action that, from a security perspective, is silly. Such actions, widely seen as actually done, include posting the password on a sticky note attached to a computer monitor, posting the password on a wall, or hiding it under a keyboard. The only solution that is similar to those activities, which is even close to acceptable, is to have the password written and attached to a clipboard, and then covered up by another piece of paper attached to the clipboard. That would sufficiently hide low-risk passwords from the eyes of a many passer-bys, although would be widely scoffed for being insufficient handling of a sensitive (important) password.

For help with installing the oeprating system, see the tutorial for: Information on installing an operating system. If installing OpenBSD, OpenBSD installation guide provides details. Here's a brief summary of some highlights (recommended customizations/non-defaults):

  • Usernames and passwords should be customized.
  • Say that yes, starting ntpd by default is a good thing.
  • When creating a partition, consider the size of the hard drive image. As noted by a section about “Determine how big of hard drive space to use”, making a very large hard drive might be a sensible choice. However, the partition then needs to be made into a reasonable size. The section on OpenBSD disk space usage sizes discusses the size: a 16GB partition would be 33,554,432 half-KB sectors in size (although a 16 GB hard drive seemed to default to starting at sector 64 and being 33,543,656 sectors in size... just choosing 33,543,210 or 33,500,000 would only be about 21MB smaller). Details on using OpenBSD's partitioning software may be found at: OpenBSD fdisk. If that program is still not understood, consider just making the hard drive image more reasonably sized.
  • The main changes to make in disklabel -E are:

    • Ensure that /usr/obj is big enough
      • (This is not needed if there is only one mount point for all of /usr or, even more broadly (and probably likely), only one point for all of the / directory. This is only needed if, as recommended, there are separate mount points for directories under /usr/, most notably including a /usr/obj directory.)

        If needed, at the disklabel -E prompt, enter the p command to view the disklabel layout. The size is shown in sectors which are half-Kilobytes, so 2,097,152 sectors would equate to 1GB.

        For details on what is a safer size: /usr/obj size. Depending on how large of a hard drive is being used, the default size might be too small, largely depending on the size of the disk.

      • If it is not large enough:
        • Delete the partition related to /usr/obj

          (At the disklabel -E prompt, enter the p command to view the partition table. After verifying the drive letter, enter a command like the following. (The following example is if the partition is the k:.)

          d j

        • Modify the partition related to /usr/src so that it also takes up the space that was being taken up by /usr/obj partition. Doing this before deleting /home might make the resize easier, because the size could be entered as * (but the results of that should be checked).

          To do all this, enter p to verify which partition is related to /usr/src or /usr/obj. If the partition is i:, then enter “m i” to modify partition i:. Otherwise, specify whichever other partition is more appropriate. Press Enter to use the default offset. For the size, specify * (by pressing * and then pressing Enter). (That will not be likely to be too large, because the size will be limited by either the start of a new disklabel entry, or by the boundaries which defaults to a location which is automatically selected based on the standard partition).

          Press p to verify the new size.

        • Make sure the partition mounts as /usr/obj instead of /usr/src (if there is only one of those directories listed).

          May use the n command on the partition that starts out being for /usr/src. So, if that partition is the i: then type the following at disklabel -E's prompt:

          n i

          Change it to be: /usr/obj

          (note: untested)

          (Note: This could also be changed using the m command. Doing it that way just involves going through more prompts.)

    • Delete the mount point related to /home

      (At the disklabel -E prompt, enter the p command to view the partition table. After verifying the drive letter, enter a command like the following. (The following example is if the partition is the k:.)

      d k

    • Save with either q or w and then x.

      If using the latter approach, and if the program says that changes are not saved, that may just refer to changes since the last time that changes were written to disk.

    • For installing sets:
      • If using cd??.iso then there may be only one set. In that case, do look for sets available via a network (such as the public Internet).
      • Do go ahead and install the set (which might be de-selected by default).
      • Those who are interested in avoiding unexpected pain (caused from packages relying on X) may wish to install X, even if X is not expected to be used.
Quitting the virtual machine

After installing the operating system to the virtual machine, shut down the virtual machine so that some tasks may be done with the disk iamge.

Once the virtual machine's OS is installed, use:
halt -p

That might not power down when booted from a CD image. (Normally running “ sysctl hw.allowpowerdown ” will show a value of 1, on a regular system that allows powering down. However, when booting installation media from a CD, that sysctl value might be non-existing/blank/unused.) So, close the virtual machine software program. (The most preferred way is to let the virtual machine software know to stop the virtual machine. With Qemu, this may be done using the Qemu monitor to use the q command. Alternative ways may be described by the section on adjusting what is running.)

Saving the current disk image state
[#dskimchd]: Compressing a disk image

A lot of experienced technicians have decided to dismiss the concept of compressing a hard drive, due to reasons which may be quite old and less relevant with modern technology. Before dismissing the concept of compressing a disk image, review compressed hard drive myths.

If using Qemu and Qcow2

If using Qemu, then using info from Compressing qcow2 images provides the necessary information. After making sure the variables are set (see: Set some initial variables to identify a script).

Handling multiple possibilities

(This section is unnecessary for people who are only using the latest version of the guide. Other people may proceed to the section called nice commands to run just before starting to compress. This simply discusses compatibility for old directions. In a nutshell, file paths need to be specified correctly.)

echo old-vmdir-var=${VMDir} old-name-var=${VMLILNAM}

If the problem is that the file was not found, try running:

ls -l ${VMDir}/diskimgs/baseimgs/${VMLILNAM}/
ls -l ${VMDirBas}/diskimgs/baseimgs/${VMGenNam}/${VMLILNAM}/

If the second ls command finds a file, but not the first ls command, then simply adjust the example qemu-img command to point to the right file.

More variable handling

The following permits a bit more code re-usability:

[ "X${VMAgeDir}" = "X" ] && export VMAgeDir="baseimgs"
echo ${VMAgeDir}
[ "X${VMDskNum}" = "X" ] && export VMDskNum=1
echo ${VMDskNum}
[ "X${VMMorNam}" = "X" ] && export VMMorNam=right-after-install
echo ${VMMorNam}
[#dskichdc]: Nice commands to run just before starting to compress
df -hi
Converting data to a compressed variation

Then, proceed with running the conversion. Be sure to customize the resulting destination filename if this shown default is not the desired output filename.

If using the new syntax, the result may look like the following command line.

A sample command line, which might not need any adjustment at all, is:

time qemu-img convert -c -p -f qcow2 -O qcow2 ${VMDirBas}/diskimgs/${VMAgeDir}/${VMGenNam}/${VMLILNAM}/${VMLILNAM}${VMDskNum}.qc2 ${VMDirBas}/diskimgs/${VMAgeDir}/${VMGenNam}/${VMLILNAM}/${VMLILNAM}${VMDskNum}-${VMMorNam}.qc2

(The VMMorNam variable is storing some text which ends up being an additional part of a filename.)

Dealing with problems in the conversion
An older example...

A previous version of this guide used some slightly different filenames. The older command is being provided here for reference in case anybody may have a file that was created using the older version of the guide.

After verifying that the needed environment variables are properly set on the command line that is being looked at:

echo ${VMMorNam}
time qemu-img convert -c -p -f qcow2 -O qcow2 ${VMDir}/diskimgs/${VMAgeDir}/${VMLILNAM}/${VMLILNAM}${VMDskNum}.qc2 ${VMDir}/diskimgs/${VMAgeDir}/${VMLILNAM}/${VMLILNAM}${VMDskNum}-${VMMorNam}.qc2
Dealing with older conversion software

If qemu-img immediately quits with an error message about an invalid syntax, try this alternate syntax which, through experimentation, was sometimes found to work better than the documented approach. (Presumably this was just an issue with older versions of qemu-img.)

echo ${VMMorNam}
time qemu-img convert -c -f qcow2 ${VMDirBas}/diskimgs/${VMAgeDir}/${VMGenNam}/${VMLILNAM}/${VMLILNAM}${VMDskNum}.qc2 -O qcow2 ${VMDirBas}/diskimgs/${VMAgeDir}/${VMGenNam}/${VMLILNAM}/${VMLILNAM}${VMDskNum}-${VMMorNam}.qc2

or, using older sample file locations:

echo ${VMMorNam}
df -hi
time qemu-img convert -c -f qcow2 ${VMDir}/diskimgs/${VMAgeDir}/${VMLILNAM}/${VMLILNAM}${VMDskNum}.qc2 -O qcow2 ${VMDir}/diskimgs/${VMAgeDir}/${VMLILNAM}/${VMLILNAM}${VMDskNum}-${VMMorNam}.qc2

If the software looked like it successfully worked to compress the disk image, then check out the results.

echo $?
ls -l ${VMDirBas}/diskimgs/${VMAgeDir}/${VMGenNam}/${VMLILNAM}/

If you find that the “compressed” disk image seems much bigger than a child image, then that may be because the new compressed image is containing a compressed copy of the data used from the parent image. In that case, if the parent image is surely going to be reliably available, making a copy of the uncompressed child image might actually be the option that uses up the least amount of disk space.

Perform a bit of clean-up of the environment space:

unset VMDskNum
or, if using Hyper-V
Compacting VHD files discusses compacting, and mentions the concept of compressing

If not using Qemu, perhaps: Images of “Primary Storage” devices: making a compressed hard drive image

[#mkvmhdro]: Modifying permissions

The disk probably does not need any further changes, and might be useful for future deployments. If the type of disk being used supports a parent/child relationship, then the current (optimized (e.g. compressed)) disk file might be a good set of data for storing an unaltered copy. One option may be to back up the entire file right now. Another option, which can be done in addition to the backup, is to remove write permissions. Doing that may help to prevent accidental, unnecessary change.

(The following example is designed to modify a disk with “1” as part of the filename. If the virtual machine's disk to be worked on is a different number, then the following needs to be adapted.)

echo bas=${VMDirBas} age=${VMAgeDir} gen=${VMGenNam} nam=${VMLILNAM} img=${VMMorNam}
chmod a-w ${VMDirBas}/diskimgs/${VMAgeDir}/${VMGenNam}/${VMLILNAM}/${VMLILNAM}1-${VMMorNam}.qc2
ls -l ${VMDirBas}/diskimgs/${VMAgeDir}/${VMGenNam}/${VMLILNAM}/${VMLILNAM}1-${VMMorNam}.qc2
[#rechldrv]: Changing disk images (“re-childing” a drive)
ls -l ${VMDirBas}/diskimgs/${VMAgeDir}/${VMGenNam}/${VMLILNAM}/${VMLILNAM}1.qc2
mv ${VMDirBas}/diskimgs/${VMAgeDir}/${VMGenNam}/${VMLILNAM}/${VMLILNAM}1.qc2 ${VMDirBas}/diskimgs/${VMAgeDir}/${VMGenNam}/${VMLILNAM}/${VMLILNAM}1-uncompressed.qc2

After verifying that the compressed copy seems to be working okay, the uncompressed copy will, in all probability, just be a less efficient way of storing the same information. So, the uncompressed copy will, at that time, be something that should be deleted.

Make a child image. The following works with newer versions of qemu-img:

echo ${VMMorNam}
qemu-img create -f qcow2 -o backing_file=${VMDirBas}/diskimgs/${VMAgeDir}/${VMGenNam}/${VMLILNAM}/${VMLILNAM}1-${VMMorNam}.qc2 ${VMDirBas}/diskimgs/${VMAgeDir}/${VMGenNam}/${VMLILNAM}/${VMLILNAM}1.qc2

Older versions of qemu-img may need to use a differnet syntax (using “ -b filename ” insetad of “ -o backing_file=filename ”), as shown by: Images of “Primary Storage” devices: using a “child disk” image.

The name of this new file is intentionally using the same filename that was being used before we compressed the image. The virtual machine is configured to look for that file. By using the same filename for the hard drive image, no changes are required for the virtual machine to be using this latest hard drive image.

ls -l ${VMDirBas}/diskimgs/${VMAgeDir}/${VMGenNam}/${VMLILNAM}/
Adjusting startup script file

After the operating system is installed, do not keep booting off of the CD drive. (Change the “ -boot d ” to “ -boot c ”.)

If needed, re-do the Set some initial variables to identify a script. Then, run:

echo ${VISUAL} ${VMDirBas} ${VMGenNam} ${VMLILNAM}
${VISUAL} ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstart/exc_${VMLILNAM}

If you are confident that you won't be using the CD boot image any more, you may stop using the CD image. (If you are confident that the CD boot image won't move, then continuing to use it may be fairly harmless.)

Once the administrator has experienced the thrill of seeing the whole boot process, there may be very little reason to keep starting the machine in a suspended state.

Comment out the line that says “-S \” (or, if not using OpenBSD's ksh, perhaps commenting the line may be a noteworthy challenge, and just deleting it may actually be more sensible).

Early steps

If the virtual machine is not currently running, then run the virtual machine.

Adjusting which kernel gets used

If the machine supports multiple processor cores, take advantage of this capability.
[ -f /bsd ] && [ ! -e /bsd.sp ] && [ -f / ] && ( sudo mv /bsd /bsd.sp ; sudo ln -s / /bsd )

Then, check the results:

ls -l /bsd*
Understanding the conditions

Note: The square brackets are branching instructions. These likely get processed by the shell, so a manula page like OpenBSD's manual page for ksh may be the most relevant, technically. The syntax is essentially the same as using the test command, which also may be built into the shell (so the manual page for the shell would be the most relevant man page). However, the manual page for the (external) test command may be an easier manual page to use for quickly comprehending these options. (Technically, the manual page for the external test command is not strictly relevant when the shell is using an internal test command. However, the internal command and the external command likely function similar enough that the documentation ends up being sufficient.)

Handling Time: Part 1 of 3

If this machine may be running Microsoft Windows, then abandon the Unix standard for time (which is to use UTC/GMT) and follow the PC standard of having your clock be set to local time. This also requires letting the OS know what time zone to use.

This is listed first so that log entries and filesystem entry modification times can have accurate times.

Kernel file handling

First, specify the desired kernel. If /bsd is a single-core kernel, any renaming/etc. should be done before making any other desired adjustments to the kernel file.

[ -h /bsd ] && [ ! -e /bsdltime ] && ( sudo cp /bsd /bsdltime && sudo rm /bsd ; sudo ln -s /bsdltime /bsd )

This copies the kernel (assuming that the condition test passed). Copying the kernel (rather than just making a link, or using mv) is desirable so that the old kernel can still be referenced (and used to boot the system) in case there is a problem with the new kernel.

This could be made more elaborate, by having /bsdltime actually be a symlink to / (or /bsdltime.sp) which could be the actual file copy. However, that step is not being followed by these example instructions, namely just to keep these example instrucktions a bit simpler. If desired, though, feel free to do that, as there is no compelling reason not to do that (correctly).

ls -l /bsd*

See: setting system clock. For instance, run:

sudo config -ef /bsd

Normally this guide always recommends backing up files before changing them. This is a minor exception, because the backup software hasn't yet been installed. It does make sense to have timekeeping working as desired before installing even that backup software. However, since we are modifying a copy of an original file, and the original file is still quite available, there is little need to back up the pre-changed file (in this unusual case).

Making the changes

(The following may need a bit of testing to verify that these directions work/function as expected.)

In summer (mostly when OpenBSD's latest released version number has a final digit which is an odd digit), type:

timezone 480 1

(hmm... unverified... and that would just be for Pacific) Getting the kernel to use the desired offset, so clock may be set to local time

Use the quit command to both save changes and quit the config program.

If the kernel being modified is /bsd then it will likely boot automatically. If the kernel being modified is a filename that the “boot” program doesn't automatically try,

Then, reboot so that the new kernel configuration may occur.

Then, the ntpd command might be quite slow at fixing the time. So, set the time. Using information from the section on setting the clock, the following should work well:

time sudo rdate -v
echo Err/Res = $?

That may or may not work well. It has been known to take nearly 8 1/2 minutes before seeming to succeed brilliantly. If it does not succeed, don't worry too much about it, becasue the next step should help resolve the time issue.

Adding a pleasant text editor (if needed)

A lot of people don't care much for vi and may be even less familiar with emacs or mg.

The following is a crude way to get nano installed. (A more elegant way of easily enabling programs to be installed, and saved when they are downloaded, can come later.)

For now, these directions do not involve setting PKG_CACHE. Note that nano does have atleast one dependency (libiconv), so that package will also not be getting cached if nano isn't getting cached.

sudo pkg_add -ivv ftp://ftp.$(uname -s).org/pub/$(uname -s)/$(uname -r)/packages/$(uname -p)/nano
export VISUAL="nano -w"

(Each of the references to “$(uname -(something))” could be simplified. This slightly more complex command was chosen for independence from any specific version, platform, and possibly even operating system.)

Note: For those wanting more details (or following a more elaborate process), see: software installation and choosing a text editor.

Simplistic backup

There may be various options at CyberPillar's backup page. One is the cpytobak command. Copy the source code from CyberPillar's backup page, and paste it into a file. Or, if that isn't convenient, but if the computer does have functional networking (including DNS), then an option may be to run:

ls -l ~/cpytobak
lynx -dump > ~/cpytobak
cat ~/cpytobak | sudo -n tee -a /usr/local/bin/cpytobak
rm ~/cpytobak
chmod ug+x /usr/local/bin/cpytobak
Handling Time, part 2 of 3

The second part of handling time is going to be keeping time accurate. (The goal here is not just to get time set correctly once, but to make sure it remains accurate over time.) This is done by setting up ntpd. To test out this functionality for an initial (virtual) machine, using a public time server is a fine idea.

Part 3 of 3 will be to adjust things later so that the vast majority of machines ends up using privately run time servers, and not the public time servers. That will be discussed later. (That might not be part of this guide, at least not at this time.)

[#vmopntpd]: Setting up ntpd

Make a file, if needed. Back up the file, if not yet done.

[ -f /etc/ntpd.conf.local ] && cpytobak /etc/ntpd.conf.local
[ -f /etc/ntpd.conf ] && [ ! -f /etc/ntpd.conf.local ] && sudo cp -i /etc/ntpd.conf /etc/ntpd.conf.local
[ -f /etc/ntpd.conf.local ] && which cpytobak 2>> /dev/null && cpytobak /etc/ntpd.conf.local
[ -f /etc/ntpd.conf.local ] && [ ! -f /etc/ntpd.conf.local.orig ] && sudo cp /etc/ntpd.conf.local /etc/ntpd.conf.local.orig

Modify a file that will contain the settings used by this machine.

echo listen on \* | sudo -n tee -a /etc/ntpd.conf.local
echo servers | sudo -n tee -a /etc/ntpd.conf.local
[#ntpdsvch]: Choosing which time server to use

In the above example text, is shown. In some cases that may initially work fine. In some cases, that may not be a very good choice.

For machines using the IPv6 Internet, a post about IPv6 NTP notes that returns AAAA records successfully. (That was information dated June 2013, and will likely become outdated as other systems support IPv6 over time.)


NIST Internet Time Servers provides a list that may be good for Americans, as well as the following warning:

All users should ensure that their software NEVER queries a server more frequently than once every 4 seconds. Systems that exceed this rate will be refused service. In extreme cases, systems that exceed this limit may be considered as attempting a denial-of-service attack. page for vendors states, “You must absolutely not use the default zone names as the default configuration in your application or appliance.” (The apparent exception is that vendors may set up a “vendor zone”.)

Recommended rates

A generally recommended rate of contacting the public time servers is no more than once every few hours. ( Vendor contribution page refers to “every 3 hours” Vendors page states, “Reasonable query intervals are typically from once or twice a day to a 4-5 times an hour depending on the application.” It also references “43200 seconds” which is 12 hours.

Using the pool a bit heavier than these types of timeframes (hours per query) is probably not going to be frowned upon, at all, when the time queries are made for initial implementation testing and interactive manual troubleshooting. After all, an administrator will likely only need to send several queries to be satisfied, which is neglible when thinking about the amount of traffic sent over a year. Devices that automatically use the network is a different story, so the traffic allowed for these types of queries should be minimized.

WARNING: Using a public time server, as shown by this documentation, may be good for the first virtual machine. It is not good to have a bunch of virtual machines all querying the same external server. Because of the text that was just quoted, doing so could end up causing problems (e.g. blacklists). Also, this unnecessarily wastes local Internet bandwidth. Instead, pick one server (which may be a physical server, or a virtual server) on your network to be a time synchronization server. Other computers at the same location should then use the local time synchronization server (without needing to send traffic to a remote location). Being configured for a local server may make a bit less sense for mobile devices (laptops), especially if there are concerns that the mobile devices may need time synchronization more often (possibly to offset problems from suspension/hibernation?). However, using a local server DOES make sense for immobile equipment (servers, desktops). Just make sure that the local time server does use an external time source (and doesn't use a standard configuration file that is utilized by all the other computers on the local network).

People performing this as part of a group type environment, such as a classroom, may want to ask the leader (/teacher/instructor/professor) if there is a local time server that is preferred (instead of using a public one).

Then, adjust the system startup script to use this file. The details on how to do this may vary among different operating systems: system startup: system startup configuration files (and system startup: automatically started files). The following shows how to do this well in OpenBSD:

[ -f /etc/rc.conf.local ] && cpytobak /etc/rc.conf.local
[ -f /etc/rc.conf.local ] && [ ! -f /etc/rc.conf.local.orig ] && sudo cp -i /etc/rc.conf.local /etc/rc.conf.local.orig
echo ntpd_flags=\"-f /etc/ntpd.conf.local -s\" | sudo -n tee -a /etc/rc.conf.local

Then, for immediate effect (to be performed before rebooting the system again), stop any running copy of the software and start up the software so that it uses the new configuration file. To stop any running copy of the software, use:

sudo pkill ntpd

That should work for OpenBSD. For other operating systems that don't have the pkill command, either see adjusting what is running or simply reboot the machine.

Once the software has been stopped, the time can be updated before the machine is rebooted. This will help to verify that the time updating works as expected. If the machine was not just rebooted (after adjusting the configuration files), run:

sudo ntpd -f /etc/ntpd.conf.local -s

Then, the OpenBSD manual page for the settimeofday() system call, “Caveats” section suggests rebooting again. So,

sudo reboot
Setting the system host name
Check the system hostname. If needed, change it.
Handling logging

Now that the system's time and hostname are up to date, and a pleasant text editor has been added (if desired), there may be little reason to delay this any further. Or, this may be done at a later time.

There might not even be anything to do with this step. In fact, this guide does not currently provide many details about any steps to perform. This note is simply saying that if there are changes to be made to the logging, then doing so sooner (rather than later) may be preferred.

(One option is to enable the shell's *history* file by setting the HISTFILE environment variable. That is actually covered by section about setting some environment variables when users log in.)

One option may be to enable accounting (see information later in this guide related to accton for more details on pursuing that option). Another may be to enable centralized logging.

Some environment variables

This could be done much later, so having this be done even before securing the computer may seem eyebrow-raising for some people. There are some benefits to doing this early.

  • One reason to do this nice and early is because it starts to show the system name in the command prompt. That is nice to start having available very early, including while running the commands that help to secure the system further.
  • Doing this before creating users may cause these customizations to affect newly created users. This may be especially nice to do before there are even three users. Doing this after the users are created may require a bit more effort.
  • This may cause commands to start being logged earlier, which could make the logs more useful.

Make a /etc/profdef file.

echo ${VISUAL}
sudo ${VISUAL} /etc/profdef

Have the file say:

[ "$VISUAL" ] || export VISUAL="nano -w -L"
[ "$EDITOR" ] || export EDITOR=$VISUAL
[ "$PAGER" ] || export PAGER=less
[ "$PAGER" ] || export PAGER=${VISUAL:=less}
[ "$MANPAGER" ] || export MANPAGER=${PAGER:=${VISUAL}}
[ X"$PS1" = X"\$ " ] && export PS1=""
[ "$PS1" ] || export PS1=\{\\!\}\\u@\\l:\\h:\\w/\\$" "
[ "$HISTFILE" ] || export HISTFILE=$HOME/.sh_history

Then, make this file easier for users to execute:

sudo chmod a+x /etc/profdef

Optional: run the script file now.

. /etc/profdef

Have this login profile affect the current user every time the current user logs in:

export CURRUSERDIR=$(eval echo ~$(whoami))
cpytobak ${CURRUSERDIR}/.profile
sudo cp -i ${CURRUSERDIR}/.profile ${CURRUSERDIR}/.profile-orig
echo . /etc/profdef | sudo -n tee -a ${CURRUSERDIR}/.profile

Make sure this is affecting the current user's login as expected.


For every other user that is going to be affected by this customization, use:

export CURRUSERDIR=~username
cpytobak ${CURRUSERDIR}/.profile
sudo cp -i ${CURRUSERDIR}/.profile ${CURRUSERDIR}/.profile-orig
echo . /etc/profdef | sudo -n tee -a ${CURRUSERDIR}/.profile

Make sure to do this at least for root and whatever account is regularly logged into by network administrators. This will change the command prompts to show the system name, which can be helpful for administrators who may work on multiple systems. (Seeing the system name may prevent an administrator from thinking that a command prompt is on one computer system when the command prompt is really on another computer system.) If there are a large number of users, then utilizing the for command (built into some command line shells), perhaps also by placing commands in a script file, may be the most effective way of making this change for all users.

If any sort of bulk/automated process was done to perform this on all users, and if this was also done manually for the currently logged in user, then adjust the ~/.profile file (for the administrator user that has been being used) so that it doesn't call /etc/profdef twice. (Running that program twice would likely be a non-problem with the sample /etc/profdef file shown, but is less than ideal and may become more of a problem if that file, in the future, is customized to do something else. There's no compelling reason to not just fix it right now.)

Also, have this affect new users.

export CURRUSERDIR=/etc/skel
cpytobak ${CURRUSERDIR}/.profile
sudo cp -i ${CURRUSERDIR}/.profile ${CURRUSERDIR}/.profile-orig
echo . /etc/profdef | sudo -n tee -a ${CURRUSERDIR}/.profile

Perform this tiny bit of clean-up.

Making a user account

Make sure there is an account other than “root”. “ ls -l /home ” might show users. The more official way is to review /etc/passwd file. Try running:

grep -v ":/sbin/nologin" /etc/passwd

Back up the user database:

[#bakusrdb]: Back up the user database:

(The commands for this section came from: backing up user account data.)

  • Optional: List the files to be backed up:
    ls -1aF /etc/*group /etc/*passwd* /etc/*pwd.db* /etc/*shadow* 2>&1 | grep -v "No such file or directory"
  • For the next command, be aware that the “for” line is fairly long, and has been known to be long enough to cause pasting issues when the command line was copied and pasted. If copying and pasting the command line (which is a quite sensible thing to do), make sure the end of the command looks right.
  • Optional: See the command that will be used to back up the data:
    for x in $( ls -1aF /etc/*group /etc/*passwd* /etc/*pwd.db* /etc/*shadow* 2>&1 | grep -v "No such file or directory" | xargs ) ; do echo \#cpytobak $x ; done
  • That should have shown a bunch of “cpytobak” commands that could be run, but have not been run yet.
  • Now that we have a list of individual files that need to be backed up, go ahead and back those up.
    • Make sure that the cpytobak command is installed.
    • If the filenames seem sensible, then take out the word “echo” from the for line. (In other words, run the same for but modified, with the phrase “echo \#” removed.
    • With the phrase “echo \#” removed:

      for x in $( ls -1aF /etc/*group /etc/*passwd* /etc/*pwd.db* /etc/*shadow* 2>&1 | grep -v "No such file or directory" | xargs ) ; do cpytobak $x ; done

For instructions on how to actually add a user, if that is needed, sece the section about adding users.

Make sure the user can log in as root

At this point, it is assumed that there is an account for an administrator, and that account is named something other than “root”. If not, follow the previous instructions about adding a user.

Make the user part of wheel

This probably isn't needed at all, if the user was created as part of the OpenBSD installation process. Otherwise, the administrator could have put the user into wheel when the user account was being created. So, start by verifying what groups the user is a part of. If the user's login name is “adminusr”, then listing groups would indicate to run:

grep -i "[\:,]adminusr" /etc/group

(As noted by the section about listing groups, that should list most of the groups that the user is in.)

If this user account needs to be changed, ideally start by proceeding to Back up the user database.

Make sure user is part of wheel. Specific directions to add a user in a group may be found at putting a user into one or more groups. (Some related information, in case it is needed/helpful: the more broad/general “user group information” section contains details about checking what group(s) a user is in.)

Enabling wheel to sudo

Make sure that wheel can log in as root. The elaborate details are at Authorizing wheel to run sudo, but here's a quick rundown. First, back up the file that is about to be changed.

cpytobak /etc/sudoers

If you want to make sure that you'll be using nano instead of vi, then run the following:

export VISUAL="nano -w"
echo ${VISUAL}

(Otherwise, there are instructions for using vi for this specific task, documented under the running as root: editors section.)

Use the proper command (which performs a file-locking safety process) to edit the file.

sudo visudo

(If ${VISUAL} is set then the effect of that command is similar to running “ ${VISUAL} /etc/sudoers ”, but using visudo does also perform a file-locking safety process.)

For the next step, users of nano may want to know about using Ctrl-K to cut a whole line, and Ctrl-U to “Uncut” (which really means paste). To make two copies of a line, cut it once and then uncut it twice.

Make the necessary changes in the file. For specifics, see: Modifying the /etc/sudoers file to enable the “wheel” group to sudo

Securing a default account

Log in as the new user. (Additional details, which are probably unnecessary but which are available for those who are interested, which describe why to do the next steps as the new user, are covered by setup guide: login as new-acct to disable superuser.)

Back up the user database.

Disabling root

(Note: These instructions for disabling root's standard login should only be done after the prior instructions, which are to be logged in using the new account, and backing up the user database.)

Use the new user to disable the account named “root”. Since the “root” account will presumably not have an SSH key, or other alternate login method, a simple password block may be effective. To do this:

echo v=${VISUAL} e=${EDITOR}

If ${VISUAL} is unset (which may be true because of recently logging in as a different user now), run:

export VISUAL="nano -w"
echo v=${VISUAL} e=${EDITOR}

Now, if the ${VISUAL} variable has the desired command, and if the ${EDITOR} variable does not, then run:


(The assumption here is that ${VISUAL} has been set already, but that ${EDITOR} has not been. The vipw command honors ${EDITOR}. However, unlike visudo, the vipw command does not honor the ${VISUAL} environment variable.)

(See also: Why vipw should be used.)

sudo vipw

After the root:, insert an asterisk (“*”) or a bang symbol (“!”). (For those who aren't familiar with that symbol being called “bang”, that is a term that is used by Unix administrators.) (This is done according to the instructions for disabling Unix system user accounts by modifying login password/credential information.)

[#mkvmsshd]: Hardening and enabling a remote access program

The following files might not exist. Don't worry about error messages about the files not existing. However, if they do exist, back them up:

cpytobak /etc/hosts.allow /etc/hosts.deny

Run the following commands, which will probably create files that do not yet exist.

echo sshd : ALL | sudo -n tee -a /etc/hosts.allow
echo ALL : ALL | sudo -n tee -a /etc/hosts.deny


cpytobak /etc/ssh/sshd_config

Then also follow: OpenSSH server recommended configuration changes. (Run the four commands that start with the word echo, but feel free to customize the TCP port number to something customized/non-standard.)

After making those changes, reload the OpenSSH configuration file.

One of those recommended changes is to add a line that says “AllowGroup”. This is a line to help to strictly control which user accounts may be logging in, but does require a bit of additional configuration.

  • Make sure the group exists. (The guide to making groups would suggest running “ sudo groupadd -v _okssh ”, if that is the name of the group.)
  • Make sure that any user who should be able to SSH in is part of the group specified by the AllowGroup line (which was added when applying the recommended configuration changes). If any users need to be changed, ideally start by proceeding to Back up the user database. Then, specific directions to add a user in a group may be found at putting a user into one or more groups. (Some related information, in case it is needed/helpful: the more broad/general “user group information” section contains details about checking what group(s) a user is in.)
    • The following commands might work fine (or may be a disaster if the user was in different groups). This is only expected to work if logged in as the user that needs to be modified, and if that user has sufficient permissions to make such a change. This is also assuming an sh-compatible shell for handling environment variables.
      export USRTOMOD=$(whoami)
      grep -i "[\:,]${USRTOMOD}" /etc/group
      user info ${USRTOMOD} | grep ^groups
      sudo usermod -G ${USRTOMOD},wheel,_okssh ${USRTOMOD}
      unset ${USRTOMOD}

Try logging in. Even if networking on a virtual machine hasn't been fully configured, just try logging in locally. (That may be done with the following command.)

ssh -p 22 -l $( whoami ) ::1

If the user successfully logs in, that is a good thing. However, go ahead and press Ctrl-D to log off of the SSH session. (The reason to log off right away is simply to do so before forgetting that the visible command prompt is being run over a (loopback) SSH session.)

Ensure that a remote system can actually access the computer

This is intended to be done after the remote access is sufficiently hardened.

If not yet already done, a decision should be made about what IP address(es) the machine should be using. (This may be a specific address(es), or information on what address range should be getting used by an “automatic address assignment method.)

Optional (but recommended) for computers joining existing networks

If a DHCP server is already operational, and if a DHCP reserveration is desired for this machine, then edit the DHCP configuration to support the MAC address of an appropriate NIC on this computer. That MAC address may be determined by either obtaining the “link layer address” on the system, or by viewing the configuration of the virtual machine. Details on creating a reservation may be somewhere under the section on automatic network address assignment. Updating the name of the DNS zone may also be appropriate. This would be adjusting the DNS server: see DNS server software.

For experienced administrators, it should go without saying that after adjusting any configuration files for these servers, make sure to inform any running copies of the server software (so that the software starts using the new configuration). (This might not be needed with some software: changes made to Microsoft's servers, using Microsoft's GUIs, may often be real-time changes that take immediate effect.) Methods of getting servers to update their configurations may vary based on different implementations. In Unix, the fastest rather standard method may be to send a SIGHUP. A slightly more time consuming method, which is more likely to work (but which might adjust some downtime) may be to restart the service. See adjusting what is running for details on restarting software.

[#choosubn]: Choosing IP address ranges for new networks

For tips on how to choose a good address, see network address planning.

Following the advice of general IPv4 addressing guidelines, including the specific advice not using low sequential subnets, and including the specific advice in the section on counting like RFC 1219, and even more specifically using the “RFC 1219”-based charts, numbers to use could include subnets in the following order:

128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 96, 240, 8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248, 4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244, 12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252.

That is only about the first quarter of possible subnets. (It is the first quarter of possible subnets using that counting method, except zero was intentionally put off).

Considering the order just provided, a subnet of 192.168.128/24 would be a good sensible first IPv4 subnet. A subnet of 192.168.64/24 would be a good sensible second IPv4 subnet.

(Note: using “RFC 3131”-based charts may be even more preferable due to allowing cushioning cleared-to-zero bits on both sides.)

Setting and testing the IP address

Make sure that the computer can respond to its own ICMP requests. Test to ensure that it can ping itself on a non-loopback IP address. Resources to help with this may include: manual network addressing: finding the address(es) used by a NIC, manual network addressing: manually setting the address(es) used by a NIC, automatic address assignment, the ping command (and similar commands).

[#mkvmncwk]: Enabling communication from the host machine

Once the computer can respond to its own communications, then make sure that another machine (the physical machine may be easiest) can communicate with the virtual machine.

Before providing some specific directions, some references are being made to additional created guiding resources. Those resources may be more broad/general, and may be a bit more confusing/challenging, but may be additional resources if there are any issues with just following the more specific steps in this guide. Additional available information includes the section on virtual machine network configuration contains several resources, including the specific implementations of virtual machine networking.

The goal here is for the physical machine to be able to send ICMP and to get response from the virtual machine. Both ICMPv6 and ICMP/IPv4 ought to be able to work.

If using Qemu

If using Qemu, modify the script file (which, if this tutorial has been followed closely, may be the ${VMDir}/execbin/${VMLILNAM}/sysstart/exc_${VMLILNAM} file).

If this is the first machine

Heavier changes may be warranted. This may take a bit of time. There are quite a few steps to really enable proper full network communication between the physical machine and the first Qemu virtual machine. So many steps, in fact, that these instructions have been split off into a separate guide: Qemu TAP. Complete that guide.

For subsequent machines:

Find the line in the example script file that says:

# export CLIOPTVMFIRSTNIC=" -net socket,vlan=1,connect= "

(This line was part of the initial example script file that was found at: guide to making a Qemu configuration.)

Simply uncomment that line. Then save the script file.

After making any needed changes to the script file (on the machine that is running the Qemu virtual machine software), safely shut down the operating system on the virtual machine, and quit the virtual machine software. (Then restart the virtual machine, which should restart the operating system.)

If using different virtual machine software

(Specific instructions are not currently being provided by this guide.)

Checking some basic networking

Verify that any needed IP address is set. (If the machine was restarted, an IP address may need to be set again. See: manual network addressing: manually setting the address(es) used by a NIC.)

Verify that remote access (to the virtual machine) is working as desired.

[#vmiphnrt]: Handling traffic routing
Newer text
Tasks to do on the virtual machine

Note that this section will involve quite a lot of customization. This is a blanket warning: the individual steps are not going to keep reminding of the need for customizing in this small section.

Any references to if0 need to be customized to reflect the actual name of the NIC on the virtual machine.

On the virtual machine:

cpytobak /etc/hostname.if0
echo ${VISUAL}
sudo ${VISUAL} /etc/hostname.if0

Add a command to get a route set up. (For reference, see: adding a route.) The first line is for IPv4 and is generally unneeded if DHCP/IPv4 is actually working already (which is generally not the case, so the line is generally needed at this point).

!route add default

Network addresses and prefix lengths will also need to be customized. Any reference made to is meant to be the IPv4 address on the tunnel NIC on the computer running the virtual machine software.

!route add -inet6 default 2001:db8::1

Any references made to 2001:db8::1 is meant to be the IPv6 address on the tunnel NIC on the computer running the virtual machine software.

Additional notes

These notes probably are not needed, but are provided in case they do end up being helpful.

The earlier reference to 2001:db8:: is meant to be a reference to the network that contains the virtual machine's NIC and the tunnel adapter on the computer running the virtual machine software. The prefix length should also be customized as appropriate.

The previously-provided command line shows setting up an IPv6 default gateway. The following shows an alternate syntax (of the network configuration file) that may be useful for other routes:

!route add -inet6 2001:db8:: -prefixlen 64 2001:db8::1

Reset the network adapter. This may cause some insignificant downtime (hopefully the downtime will be a matter of seconds), and verifies that these changes have the desired effect when the machine reboots. For crucial machines, this test could be done during scheduled downtime, and the commands just run manually. Once again, be careful to customize the reference to if0 to instead reflect the actual NIC name.

sudo $SHELL /etc/netstart if0

Other than causing the downtime, this probably will have no visible effect yet.

Tasks to do on the computer running the virtual machine software
[#mkip4nat]: Enabling NAT for IPv4 communications
Editing the primary /etc/pf.conf file
cpytobak /etc/pf.conf
echo ${VISUAL}
sudo $VISUAL /etc/pf.conf

Beware that these commands may allow outgoing traffic to the Internet from any private address, including the newly created virtual machine or any other machine on the network. This may be tightened down more later, but for now we'll consider the internal network to be trusted because it makes these directions simpler. If the internal network is actually not trustworthy, check out some of the other referenced resources, and take care of this more carefully.


include "/etc/pf/pfnics.cnf"

# IETF BCP5 represents "private" IPv4 addresses
table <ietfbcp5> persist { 10/8 172.16/12 192.168/16 }

# We never want to pass out traffic from a private address.
# (Rule is optional if another device, outside this network, addresses this.)
pass out on $ext_if inet from { <ietfbcp5> } to any nat-to ($ext_if:0)

Note that the above only handles IPv4. IPv6 would need similar functionality, and should handle the FD00::/8 block and perhaps also the FEC0::/10 block.

The “nat-to” is specific to certain versions of pf (probably first widely introduced by May 2010's OpenBSD 4.7 upgrade guide: pf NAT syntax change). Older versions of pf used a different syntax. Further details may be found in the documentation about firewall implementations. (Also, it would not be surprising if the OpenBSD team released some additional documentation. Perhaps that was done, so that could be looked into.) However, upgrading to a newer version of the firewall software is likely to generally a better idea, for security reasons, than trying to customize rulesets to be using an older version of security-related software.

Making another required file

Since the firewall rules are referencing an external file, that needs to be made. The names of NICs also needs to be addressed put somewhere, and this design has that information be placed in the new file that is about to be created.

sudo mkdir -p /etc/pf
echo ${VISUAL}
sudo ${VISUAL} /etc/pf/pfnics.cnf

Customize the NIC name (to the right of the equal sign).

Performing a configuration check
sudo pfctl -n -f /etc/pf.conf
Having the firewall use new rules.
sudo pfctl -d
sudo pfctl -e -f /etc/pf.conf

There is a bit more to do in order to fully support a network of virtual machines (which is to add routing onto the machine running the virtual machine software). However, in a simple setup, the actions performed so far may allow outgoing traffic from the virtual machine to the public Internet, as well as enabling response traffic. So, if things are currently working well, there's currently little need to muck further with the routing yet. The task, of getting the rest of the routing set up, is something that may make more sense to do when the task is actually needed. The results will also be easier to test then. Expect to need to do that task after the second virtual machine is created.

Test reaching a site on the public Internet using an IP address.

ping -c 3

If there are any problems, consider checking out the “Older text” that follows, including some of the referenced resources.

Older text

Right about now, some people may wonder why the virtual machine can communicate to the physical machine, but no other machines. Fixing that involves focusing more on network traffic handling, which may make more sense to worry about later when working on setting up a firewall and automatic distribution of network settings. This guide does not, at this time, have tested/proven step-by-step guide on how to get that working (yet). However, for those who have an earlier need/desire to get traffic routing going, here are some pointers. Note that this may require a bit of an adventurous spirit, being willing to invest some time in this task.

An inability to communicate with remote private machines/devices is probably the first item to tackle. See if the virtual machine can communicate with the default gateway of the physical machine. To find the default gateway, check the routing tables. To simplify the output, use “ route show | grep default ” or the faster “ netstat -nr | grep default

If it is indeed true that an internal machine cannot be reached, make sure that the virtual machine's default gateway is set. If not, see: adding routes to get that added. If the virtual machine does have the routing (e.g. the default gateway) set, and things are still not working (which may be common), see: enabling traffic forwarding, and most especially the subsection about handling traffic in both directions.

Then, the virtual machine might be able to communicate with all private IPv4 addresses but not public IPv4 addresses other than the default gateway. If that is the case, then NAT may need to be used.

Other tips may be found in the broader section about routing network traffic.

Getting name resolution working

If there are troubles with connecting to the Internet via IP addresses, fix that problem before trying to use any public DNS servers.

On the virtual machine:

cpytobak /etc/resolv.conf
echo ${VISUAL}
sudo ${VISUAL} /etc/resolv.conf

Have the first line of the file state:


Of course, that the the /24 block should never be used except for documentation/examples. So, the IP address to really specify there should be DNS servers for clients to use. (Do not use an address that starts with FEC0:0:0:ffff: unless a server has already been placed at that privately-run address.) For example:



ping -c 3
[#btsetnet]: Making network configuration happen on each boot

Finally, once this communication is working, make sure that it will continue to work. For instance, if an IP address was set manually, make sure that will happen every time the system is started. (Perhaps see: automatically started files.)

Some example files are shown. Unless otherwise specified, this needs to be done on the virtual machine.

Setting up automatic network configuration for OpenBSD

Note that on OpenBSD, the filenames will likely need to be customized. The filenames need to include the actual name of the network card. To find the actual name of the network card, see: available network interfaces. (For Qemu virtual machines, common network interface names may be em0 or ne3.)

export CURNIC=if0

To clarify, that must be customized.

The following commands may also assume that the file pre-exists, but the file does not need to pre-exist. (There may simply be some errors about a non-existent file.) The following shows some example commands, to be run on the virtual machine.

cpytobak /etc/hostname.${CURNIC}
[ ! -f /etc/hostname-orig.$CURNIC ]&&sudo cp -i /etc/hostname.$CURNIC /etc/hostname-orig.$CURNIC
sudo rm /etc/hostname.${CURNIC}

(The optional curly braces were left off of the second line because otherwise the line was exceeding a length limit on how much may be safely pasted.)

If a static IPv6 address and prefix length are going to be used:

echo inet6 alias 2001:db8::2 64 | sudo -n tee -a /etc/hostname.${CURNIC}
Supporting IPv4

The following shows a command, to be run on the virtual machine, if DHCP/IPv4 is being used.

echo dhcp | sudo -n tee -a /etc/hostname.${CURNIC}

Otherwise, if this is going to use a static IPv4 address instead of using DHCP/IPv4, then use something like:

echo inet NONE description \"IPv4\" | sudo -n tee -a /etc/hostname.${CURNIC}

This is based on OpenBSD's manual page for hostname.if file, which shows a description on an IPv4 line (in a couple of examples). However, it is believed that the description actually ends up getting applied NIC-wide, so it should reference the purpose of the connection rather than the specific IPv4 address. (This description would be applied just as visibly to any IPv6 on the NIC.)

Enable the card. (This is typically done after specifying the IPv4 configuration, and before specifying the IPv6 configuration.)

echo up | sudo -n tee -a /etc/hostname.${CURNIC}
Enable proper IPv6 router solicitation support:
The quick and easy way:
echo rtsol | sudo -n tee -a /etc/hostname.${CURNIC}
The better way

Obtain a DHCPv6 client, if needed. The software installation section has details about how to add software. For example, with OpenBSD:

sudo -i -u root pkg_add -ivv isc-dhcp-client


sudo -i -u root pkg_add -ivv wide-dhcpv6

Have this software be used. Currently this guide does not provide details. However, some pointers may be found in the guide to building a network. Example commands are anticipated to be placed into this guide in a not-very-distant update.

Handling routing

In some cases, routes may be handled automatically and so there might not need to be any routing commands. If routing commands are required, then fully setting up routing (including the routing of reply traffic) can be a bit of a time consuming task. Handling routing is something that people may wish to delay a bit, while even more critical tasks are addressed. (In other words, this task may be reasonably skippable, with the expectation of returning to the task later, editing any necessary configurations at that time.)

Note: handling routing might not be immediately desirable. For instance, if there is a guide showing a walkthrough of the process of setting up a system, full Internet connectivity might not be desirable until after certain steps are taken to “harden” the security of the computer. These routing instructions are not meant to suggest that routing should be tackled yet. However, if there are known changes that are needed to make routing work, this documentation is simply showing how to apply those changes (when the time is right).

If there are any networking routing commands needed (which is generally NOT the case for IPv4 if DHCP/IPv4 is used), place the commands in the text file but start the line with an exclamation point. So, adding a default gateway for IPv6 would look like:

echo !route add -inet6 2001:db8:: -prefixlen 32 2001:db::1 | sudo -n tee -a /etc/hostname.${CURNIC}

The first address is actually the Network ID of a subnet, and the next address is the destination. More details on routing are available for anyone spending the time trying to get routing to work at this time: For more details on routing, see: adding a route, walkthrough for making a virtual machine: adding IP routes, troubleshooting network traffic.

Note that the filename in the previous examples was meant to be customized to include a reference to the available NIC. If that wasn't done properly, just back up the correct file and then move the incorrect filename over the correct filename, as shown below.

cpytobak /etc/hostname.${CURNIC}
sudo mv /etc/incorrectly-named-file /etc/hostname.${CURNIC}

This may leave the permissions of the file to be “insecure”, which is a term used by OpenBSD's startup script. (OpenBSD's startup script will fix the problem when the system is restarted.)

For a quick test:

sudo $SHELL -c ". /etc/netstart ${CURNIC}"

Unset the custom variable that likely won't ever be used again.

unset CURNIC

For an even more thorough test on what will happen when the system reboots:

sudo reboot

Then verify network communication.

Enabling easy remote shutdown

The elaborate instructions are available at: sys stop: using a special, dedicated user account to reboot. Check that out if further details are needed. Here are the steamlined directions:

Create a (dummy) pair of key files. (See: generating key files.)

Decide upon a username. The guide at at sys stop: using a special, dedicated user account to reboot discusses possible usernames.

export STOPUSER=_sysoff

Create a user that will be used for this specific task. (sudo adduser)

Group handling

Make sure the user is part of the group that is allowed to SSH (if that security measure is being utilized). See: listing groups.

grep -i "[\:,]${STOPUSER}" /etc/group

(As noted by the section about listing groups, that should list most of the groups that the user is in.)

If changes need to be made, see: putting a user into one or more groups.

Set EDITOR variable if desired, and then use sudo vipw to disable using standard logins for the user. (Details: disabling user standard login passwords.)

[#keytooff]: Allow the user to log in using a specific key

Make a useful .ssh/authorized_keys file. For example, if the user's name is _termall, then create a ~_termall/.ssh subdirectory. Then create a ~_termall/.ssh/authorized_keys file.

sudo mkdir $(eval echo ~${STOPUSER})/.ssh
echo v=${VISUAL} e=${EDITOR}
[ "${VISUAL}X" = "X" ] && export VISUAL="nano -w -L"
echo v=${VISUAL} e=${EDITOR}
sudo ${VISUAL} $(eval echo ~${STOPUSER})/.ssh/authorized_keys

Have the file start with the following text:

command="sudo /sbin/shutdown -hp now Shutdown initiated with SSH by \\"$USER\\" CONN rem/lcl=\\"$SSH_CONNECTION\\" CLI rem/lcl=\\"$SSH_CLIENT\\" CMD=\\"$SSH_ORIGINAL_COMMAND\\"",no-agent-forwarding,no-port-forwarding,no-X11-forwarding 

After the last word, let there be a space and then the contents of the SSH public key file. If the temporary SSH key was made on the same computer, this might be done most efficiently by saving changes and quitting the text editor and then running:

ls -l
cat | sudo -n tee -a $(eval echo ~${STOPUSER})/.ssh/authorized_keys
sudo ${VISUAL} $(eval echo ~${STOPUSER})/.ssh/authorized_keys

The purpose of editing the text file is just to carefully check what it looks like. For instance, make sure that the key got added to the same line as the previous text.

For a DSA key, the resulting file may have text that looks something like:

command="...",...,no-X11-forwarding ssh-dss AAAAB3NzaC1kc3MAAACB...== comment-which-defaults-to-user

(This sample file comes from concepts documented at Using an (OpenSSH) SSH key to use (only certain) commands and customized with information found at Using a special, dedicated user account to shut down a system.)

Providing some needed permissions
SSH keys

Permissions may be needed. (This process is just a slightly streamlined, but more specific, process than what is shown by Permissions related to user keys on the computer running the SSH server.)

Adjust permissions: authorized key file permissions, and information from the “Follow up work” section to check details, would indicate to run something like the following:

sudo chmod go-w $(eval echo ~${STOPUSER})/ $(eval echo ~${STOPUSER})/.ssh/
sudo $SHELL -c "chmod go-w $(eval echo ~${STOPUSER})/.ssh/authorized_keys*"

Similarly, adjust ownerships. (This might be needed if the .ssh/ directory or the .ssh/authorized_keys file were made by a user other than the user who needs to own the files.)

sudo chown ${STOPUSER}:${STOPUSER} $(eval echo ~${STOPUSER})/ $(eval echo ~${STOPUSER})/.ssh/
sudo $SHELL -c "chown ${STOPUSER}:${STOPUSER} $(eval echo ~${STOPUSER})/.ssh/authorized_keys*"
cpytobak /etc/sudoers
echo ${VISUAL}
sudo visudo

Allow the user to shut down the system: see modifying the /etc/sudoers file to allow a system shutdown. (However, make sure to specify the correct username. The example that has been getting used is a user named _sysoff but those instructions use a different example username of _endsys. Neither username is particularly better than the other, but one consistent username should be getting used throughout this whole process.)

That probably ends the short streak of heavily specifying that username a lot on the command line.


Make sure that the private key file is inaccessible by others. The following may be run on the system to be shut down, or on a different system. (The filename may need to be customized, and the last line may need some more customization.)

This is designed to be run on whichever machine has the private key file. (For temporary keys, it does not really matter whether this is on the virtual machine or the computer that runs the virtual machine software.)

ls -l privkey
chmod go-rwx privkey
ls -l privkey
ssh -p 22 -i privkey -l myusrnam

If the server accepts the SSH connection but then requests a password, then the SSH key was not accepted. Check that the client's command line did specify the SSH key. If so, the problem is usually related to permissions related to user keys on the computer running the SSH server and, on the computer running sshd, the /var/log/authlog file may mention that it found a key which had some problems.

[#mkoffscr]: Using the ability to remotely shut down

Once a verified command line has been found to work, place that command line into a script.

(Although, some people may wish to delay this when working on a base/parent image, thinking that it makes more sense to do this later when setting up the SSH keys for the child image. Still, for those who have never done this before, it is not a harmful step to perform and to start seeing its usefulness.)

(This is designed to be run from the computer that runs the virtual machine software.)

echo ${VMDirBas} ${VMGenNam} ${VMLILNAM}
mkdir ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstop
echo \#!/bin/sh | tee -a ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstop/off_${VMLILNAM}
echo echo Now shutting down system... | tee -a ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstop/off_${VMLILNAM}
echo ssh -p 22 -i privkey -l myusrnam off_${VMLILNAM}-script \$1 | tee -a ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstop/off_${VMLILNAM}
echo date | tee -a ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstop/off_${VMLILNAM}
echo echo Lamely creating race condition by simply waiting 90 seconds... | tee -a ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstop/off_${VMLILNAM}
echo sleep 90 | tee -a ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstop/off_${VMLILNAM}
echo echo Hopefully virtual machine is now stopped. Exiting... | tee -a ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstop/off_${VMLILNAM}
chmod ug+rx ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstop/off_${VMLILNAM}

Note: This is actually a really bad example of software design: It relies on a race condition. If the virtual machine takes longer than 90 seconds to shut down, there may be problems for any software that expects the machine to be completely shut down. For instance, if the physical computer running virtual machine software ends up shutting down before the virtual machine is done, then the virtual machine software will probably be ended improperly. This could lead to data loss. Less critical (than data loss) is that if the process takes up substantially less than 90 seconds, there can be a very unuseful wait that people may be forced to endure.

The advantage to this lousy method is simply that it was an easy method to create. At the time of this writing, attempts to provide a superior method have met with mixed success. Therefore, no superior solution was being provided here.

Note: The above sample file needs to be customized, including:

  • username to log in
  • IP address
  • possibly TCP port number


echo ${VISUAL}
${VISUAL} ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstop/off_${VMLILNAM}

If there are multiple virtual machines to be shut down, this could get quite slow. For instance, shutting down four virtual machines will result in waiting more than six minutes. Having actions operating in parallel, as well as real detection on when the virtual machine software has ended, would be highly preferred over this example.

With these warnings made, feel free to proceed with testing the script file.

${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstop/off_${VMLILNAM} "optionalComment"

(If no comment is desired, then the quotation marks are optional.)

If that script works, then have the script be run as part of the shutdown process of the computer that runs the virtual machine software:

[#vmparoff]: Handling the shutdown of the computer running the virtual machines
A simple approach: Automatically shutting down virtual machines during the shutdown process of the computer that runs the virtual machines

Note: This is not necessarily the most preferred method to try to perform right away. An even better approach would be to try to get the virtual machine transferred to run on a different physical computer, ideally in a way so that the virtual machine notices very minimal downtime. (Some solutions have been made so that there is very nearly no downtime at all.)

This guide currently does not perform that elaborate of a procedure, and instead aims simply to perform a shutdown of the virtual machine, which is hopefully sufficient to avoid data corruption on the virtual machine.

The specific details may commonly vary between even similar operating systems, as noted by the section on system shutdown. The following ought to work well with OpenBSD:

cpytobak /etc/rc.shutdown
echo ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstop/off_${VMLILNAM} \"parent rc.shutdown\" | sudo -n tee -a /etc/rc.shutdown
Other approaches

(At this time, no extensive guide of details is currently being provided here.)

After testing full functionality, delete the key files (both the public key file and, if this was dummy/temporary key files, the private key files) on the base image. Ideally, actual key files to be used won't be anywhere on the base image. Also, modify the .ssh/authorized_keys file to remove the key that will no longer be used. (It may be helpful to leave the rest of the line, but comment it out. Simply remove the key portion, which starts with mentioning the key type (e.g. ssh-dss for DSA keys), and everything on the line after that key type. Optionally, to make this file valid, place a # comment character at the start of the line. However, that character will then need to be removed when making the file useful again later.) (If using nano, the -L option may be useful for this operation.) Even if the file is blank, leave the file there (undeleted). Later, attempts to change the file's contents will probably not modify the permissions, whereas deleting the file and re-creating it later may be quite likely to result in a file that (by default) has unusable permissions.

For a child image, this won't function until a key file is placed. That may be better than having a key installed by default, as if there is ever a problem with that key then it would be good to not have it installed by default on all future child machines.

(A desirable key could be installed from a second hard drive image, if support for a second hard drive is implemented.)

Adjusting virtual machine's operating system's startup process
Automatic disk repair

This is perhaps one of the more controversial steps. So, do read about this, and agree whether it is desired, before proceeding. These steps involve working around some of the decisions that were made by whomever designed the operating system's behavior.

By default, if the system is shut down improperly, the used and writable filesystems may become inaccessible without manual intervention. This means that the filesystem used for the /var mount point may become unusable, and the mount points for /usr and / may also become unusable unless (usually manual) customizations were performed to change those to read-only. If the main / mount point is not writable, that can cause the /etc and, perhaps most critically, the /dev directories (a.k.a. “folders”) to become inaccessible.

The result in all this is that the system doesn't function right; the only solution is often to improperly shut down the system (again) and manually perform some maintenance on the system.

The solution presented is designed to be more aggressive in performing the required maintenance automatically. The downside is that there is some greater possibility of data loss on these mount points. However, there should be relatively little customized data on those mount points, and so that customized data can be easily backed up. Those customizations should also be documented. So, in the seeable and likely worst-case scenario, the consequences will require manual intervention (as the data may need to be restored backup), which isn't much different than the unpleasant default approach.

Offering a CLI

This presents any interactive user with an option to boot to a command prompt with full administrator access. This is always an option for those who want to boot into safe mode, but presenting the prompt is simply an additional convenience. This might be especially nice for those who may take several seconds to initiate a VNC connection to be able to see the system.

Although this substantially thwarts the operating system's security, the security damage is not really worse than other options that exist. This is discussed by the bottom of OpenBSD instructions for when a root password is lost. Note that remote access to an administrator prompt on a physical machine that runs virtual machine software may be just as compromising to the virtual machines as physical access to a physical machine.

Overwriting files on the root filesystem

The idea here is to enable support for a companion drive. This may allow multiple variations of machines that use an identical base drive, and have all the customized content on a companion drive.

[#nwbtscux]: Inserting custom commands early in the process

The disk repair commands need to be performed before the operating system raises the “securelevel” (which has some similarities to the concept of “runlevel” in Linux, although the security benefits of OpenBSD's “securelevel” are a bit greater). Fortunately, there is a fairly painless way to do that.

(These commands are meant to be run on the virtual machine.)

cpytobak /etc/rc.securelevel
sudo cp -i /etc/rc.securelevel /etc/rc.securelevel-backup-of-orig
echo Warning: Note that the next command does not specify -a so data is overwrtten.
echo . /etc/seclevlz | sudo -n tee /etc/rc.securelevel
cat /etc/rc.securelevel-backup-of-orig | sudo -n tee -a /etc/rc.securelevel

(The above example is fairly crude, and puts a line of text at the top of a file. Actually, a more appropriate spot for the new line might be just above the existing code, below the file's comment. However, this approach was fairly easy to create directions that may be copied and pasted.)

echo ${VISUAL}
sudo ${VISUAL} /etc/seclevlz

(The following text has enough special characters that using a text editor is probably best. Trying to just use echo this from a command line may be more pain than running a text editor.)

echo Current SecureLevel: $(sysctl kern.securelevel)

. /etc/
. /etc/

mount /srv/hddcfg
[ -f /srv/hddcfg/hddcfg.tgz ] && tar xzzvf /srv/hddcfg/hddcfg.tgz -C /
[ -d /srv/hddcfg/extract/. ] && cp -Rp /srv/hddcfg/extract/. /.
[ -d /srv/hddcfg/multidir ]&&\
(for x in /srv/hddcfg/multidir/*.tgz;do tar xvvzPf ${x} -C /;done)
[ -d /srv/hddcfg/multidir/. ] && cp -Rp /srv/hddcfg/multidir/extract/*/. /.
[ -x /srv/hddcfg/hddcfg ] && /srv/hddcfg/hddcfg
[ -f /srv/hddcfg/ ] && /srv/hddcfg/

Now, this file made references to several other files. So, several other files need to be created.

Offering a command line

This makes use of two files. The /usr/local/bin/ file is currently designed for OpenBSD's ksh.

Use a text editor to create these files. (Downloads may be provided in the near future, especially if requested.)


Run this code:

echo ${VISUAL}
sudo ${VISUAL} /etc/

... and place the following contents into the file:

# The above is a fancy way for OpenBSD's ksh and/or the bash shell to implement:
# if [ ! X"$1" = X"" ] ; then offerCmd="$1";else offerCmd=/bin/sh;fi

echo Press the Enter key within 10 seconds if it is desired to now run:
echo ${offerCmd}
/usr/local/bin/ 10
# if [ Text"${timedrdResults}" = Text"" ] ; then
if [ ! "${?}" = "0" ] ; then
echo Timeout occurred. Not running the command.
# echo Input was detected. Line of text was:
# echo ${timedrdResults}
echo Starting ${offerCmd}
echo The offered command...
echo ${offerCmd}
echo ... has ended with return value of ${ofrcmdrs}

Run this code:

echo ${VISUAL}
sudo ${VISUAL} /usr/local/bin/

... and place the following contents into the file:


# This is meant for the ksh in OpenBSD.
# Other environments may require adaptation.

timedrdterm() {
kill "${$}" 2> /dev/null
# The above value may effectivley get lost.  Do not expect it stays set.
timedrdusr() {
timedrd() {
trap 'timedrdusr' USR1
(sleep "${1}" && kill -USR1 "${$}" && timedrdterm ) & sleepPID=${!}
trap 'echo TERM signal received - reading is stopped. > /dev/null' TERM
read "${2}"
# ${?} - results of the read command - is zero.
# echo Currently after the read command

# simply unset any special handling
trap - TERM
trap - USR1

# echo Term History ${tmdrdhst}
if [ Text"${tmdrdhst}" = Text"DidSIGUSR" ] ; then
echo Did Terminate > /dev/null
# recommend returning 142 (implies reason for exit was SIGALRM)
# to be like bash when using read -t
# echo About to term sleep PID
kill "${sleepPID}" 2> /dev/null
# echo Did not Terminate
# recommend returning zero
trap - EXIT
return "${tmdrdret}"

# The above is a fancy way for the OpenBSD ksh, or for bash, to implement:
# if [ ! X"$1" = X"" ] ; then timdrswt="$1";else timdrswt=10;fi

timedrd ${timdrswt} timedrdResults

echo Obtained varresult: \[${timedrdResults}\]

return ${tmdrdret}

Run this code:

echo ${VISUAL}
sudo ${VISUAL} /etc/

... and place the following contents into the file. (Apparently having most of the file all be tabbed was rather intentional.)



# checks whether a mount point is writable.
# Will check / unless a different directory is given as a parameter.
# Return codes have roughly the same meaning as what is shown by
# Returns 0 if all was (and is) okay. Returns 1 if problems got fixed.
# Returns 2 if the system probably just needs a reboot after
# this script ends.
# Returns 4 if problems likely remain.
# Returns 8 if script encountered issues.  Likely fsck returned 2 so
# in that case, system should be rebooted.

# The above is a fancy way for the OpenBSD's ksh shell, and/or
# the bash shell, to implement:
# if [ ! X"$1" = X"" ] ; then mntckdir="$1";else mntckdir=/;fi

echo Attempting to make sure that ${mntckdir} is writable.
mount -uw ${mntckdir}
if [ "${retCode}" = "0" ] ; then
echo No problem found with the ${mntckdir} mount which is writable.
echo Setting ${mntckdir} to writable failed: return code ${retCode}
echo Perhaps unclean filesystem ${mntckdir} caused this.
echo Will try preening.
fsck -p ${mntckdir}
echo Results from preen were ${retCode}
if [ ! "${retCode}" -le "1" ] ; then
echo Retrying mount
mount -uw ${mntckdir}
if [ "${retCode}" = "0" ] ; then
echo It does seem the preening fixed ${mntckdir}
echo Mount ${mntckdir} still failing.  Trying more major repairs...
elif [ "${retCode}" = "2" ] ; then
echo Preen indicates reboot is needed.  Will reboot.
echo Sleeping 15 seconds.
sleep 15
echo Initiating reboot.
echo Sleeping while initiated reboot occurs.
sleep 999
echo Reboot seems to have failed.  Manual intervention may be needed.  Running shell.
elif [ "${retCode}" = "4" ] ; then
echoPreen was insufficient.  Trying more major repairs...
elif [ "${retCode}" = "32" ] ; then
echoSeems preen was aborted manually.  Enjoy a shell.
echo Shell exited with return code of ${mntckret} so setting return code to ${mntckret}
elif [ "${retCode}" gt "4" ] ; then
echo Preen results seem problematic. &nsbp;Exit code was ${?}.  Will apply major repairs.

if [ Text"${slshfsck}" = Text"TryFull" ] ; then
echo Will try full repair.
fsck -y ${mntckdir}
echo Result from full repairs: Exit code was ${retCode}
if [ ! "${retCode}" -le "1" ] ; then
echo Retrying mount
mount -uw ${mntckdir}
if [ "${retCode}" = "0" ] ; then
echo It does seem Full Repairs fixed ${mntckdir}
echo Mount ${mntckdir} still failing.
elif [ "${retCode}" = "2" ] ; then
echo Full repair process indicates reboot is needed.  Will reboot.
echo Sleeping 15 seconds.
sleep 15
echo Initiating reboot.
echo Sleeping while initiated reboot occurs.
sleep 999
echo Reboot seems to have failed.  Manual intervention may be needed.  Running shell.
elif [ "${retCode}" = "32" ] ; then
echoFull Repairs seem to have been aborted manually.  Enjoy a shell.
echo Shell exited with return code of ${mntckret} so setting return code to ${mntckret}
elif [ "${retCode}" gt "4" ] ; then
echo Preen results seem problematic. &nsbp;Exit code was ${?}.

After making those files, ensure the permissions are suitable:

sudo chmod ug+rx /etc/ /etc/
sudo chmod a+rx /usr/local/bin/
[#rnaltdsk]: Automatically accessing the second disk: supporting the /srv/hddcfg mount point

This is the first of two sections documenting steps related to supporting a second disk. This section is focused on making the computer try to use files located on the other hard drive (if such files may be found). (The other piece to this is making an alternate disk be usable.)

Accessing files from second disk

Note: When doing this, /etc/fstab will be edited (if that wasn't done yet). If /usr/obj was deleted but /usr/src wasn't, and if /etc/fstab has a reference to /usr/src but not /usr/obj, then changing that now is probably a good idea. First, make sure that there isn't a reference to /usr/obj. Then, if there is a reference to /usr/src, then change that reference from /usr/src and change it to /usr/obj.

cpytobak /etc/fstab
sudo cp -i /etc/fstab /etc/fstab-orig
echo 0123456789abcdef.a /srv/hddcfg ext2fs ro,nodev,nosuid,noauto 0 0 | sudo -n tee -a /etc/fstab
echo ${PAGER}
sudo cat /etc/fstab | ${PAGER}
sudo mkdir -p /srv/hddcfg
sudo chmod o-rwx /srv/hddcfg
Adjusting the (virtual machine) system's shutdown process

system shutdown event handling mentions there may be a file called /etc/rc.shutdown.

cpytobak /etc/rc.shutdown
sudo echo ${VISUAL}
sudo ${VISUAL} /etc/rc.shutdown

Place these lines somewhere in the file.

[ -x /srv/hddcfg/hddcfgdn ] && /srv/hddcfg/hddcfgdn
[ -f /srv/hddcfg/ ] && /srv/hddcfg/
Some thoughts...

Additional steps may be interesting, such as synchronizing data on system shutdown and then copying that data to the primary hard drive on system startup (even if the copy was erased from the primary hard drive due to a re-creation of a virtual machine child image). However, that process sounds potentially complicated (especially troubleshooting if the system gets shut off before a synchronization is completed), so such a solution may require some further design, troubleshooting, and perhaps even some external software like the package called rsync. In the meanwhile, simply including these lines will provide flexibility to perform these sorts of tasks, if desired, or other tasks.

If any really elaborate process gets needed, then placing the commands in a separate file may be a better idea than trying to make a very complicated /etc/shutdown.rc file. (Simply have the /etc/shutdown.rc run a script file that contains all of the elaborate steps.) The reason to keep /etc/shutdown.rc lean is that a default /etc/shutdown.rc may get installed when installing the operating system (including re-installing the operating system, possibly as part of a process of upgrading the operating system). If and when that happens, simply adding a single line, which calls a separate script, may be much easier than trying to copy screens full of code, perhaps especially if that code starts to have complexity such as using custom functions.

[#mkvmpkga]: Adding software: Handling ports

The first steps are implementing what is discussed by: Making OpenBSD package management easy:

Decide where files will be saved. (Feel free to customize the following location, if such customization is at all desired.)

Some of the following examples do refer to root's home directory (“~root/”). Actually, making a custom user for this is an even better idea, as it might allow the “root” account to be more fully disabled (by setting its shell to the location of the “nologin” executable). Creating a special account for this may be a fairly good idea. (Having the account's name start with an underscore may also be a good idea.) The exact username should not be based off of widely public documentation (or else attackers may become prone to using the username, reducing any effectiveness of the reason to use an account other than the one named root). If doing so, be sure to document the name of the account being used.

export PKG_CACHE=~root/pkgcache

Make sure the required directory exists.

sudo mkdir -p ${PKG_CACHE}

Make a file that uses this information.

sudo mkdir ~root/bin
echo export PKG_CACHE=${PKG_CACHE} | sudo -n tee -a ~root/bin/pkgcmd
echo export PKG_PATH=\${PKG_CACHE}/.\:/media/opnbsdcd/\$\(uname -r\)/packages/\$\(machine -a\)\:\\ | sudo -n tee -a ~root/bin/pkgcmd
echo ftp://ftp.\$\(uname -s\).org/pub/\$\(uname -s\)/\$\(uname -r\)/packages/\$\(machine -a\)/ | sudo -n tee -a ~root/bin/pkgcmd

Have the preferred configuration load.

sudo -n cp -i ~root/.profile ~root/.profile-orig
echo . \~root/bin/pkgcmd | sudo tee -a ~root/.profile

See what packages are installed already:


You may see some dependencies listed. To view only the packages that have been installed manually:

pkg_info -m

If there is really a desire to have a local copy of those packages (which is not a bad idea!), either download them manually or remove the packages (using “pkg_delete package-name ” and then re-add each package (using “ pkg_add -ivv package-name ”). If trying to save the files needed for the software, make sure to also do this for any dependencies (not just the manually-installed software). For instance, if nano is the only manually-installed package so far, then the following might work out fairly well:

pkg_info -m
sudo pkg_delete -vvv -X
sudo -i -u root pkg_add -ivv nano

The pkg_* lists software related to these types of tasks, and Showing software installed with pkgtools discusses how to view installed packages and actually goes into a further discussion about re-installing software as a group (rather than one package at a time).

For ideas of what other software to install, see: installing common software. Another archive to become familiar with may be SecTools. There are various ideas on how much software to install: see software population on base images.


sudo -i -u root pkg_add -ivv nano
sudo -i -u root pkg_add -ivv pv
sudo -i -u root pkg_add -ivv p7zip-rar
sudo -i -u root pkg_add -ivv xz
sudo -i -u root pkg_add -ivv aide
sudo -i -u root pkg_add -ivv integrit
sudo -i -u root pkg_add -ivv clamav
sudo -i -u root pkg_add -ivv curl
sudo -i -u root pkg_add -ivv e2fsprogs
sudo -i -u root pkg_add -ivv sharity-light
sudo -i -u root pkg_add -ivv memtester
sudo -i -u root pkg_add -ivv smartmontools
echo Other ideas may include (other?) software for SMART, NUT, hardware sensors, etc.
More programs with more options

Here's another program to add:

sudo -i -u root pkg_add -ivv ytalk

Perhaps unlike others mentioned earlier in the list, this might ask about a package flavor. The simple answer is that selecting packages that are “no_x11” or “static” are insignificantly more likely to work, with some possible downsides like using up (probably neglible amounts of) additional disk space. In the rare cases when using “static” is likely to have any impact whatsoever, having a “static” version is likely going to be a much nicer experience, so don't be afraid of investing the disk space. Variations of software may be discussed further by OpenBSD FAQ about port flavors and subpackages/OpenBSD Ports documentation: section on flavors and subpackages. The no_x11 variants are also discussed by FAQ 15: crazy errors with ports which notes, “Another common failure is a missing X11 installation. Even if the port you try to build has no direct dependency on X11, a subpackage of it or its dependencies may require X11 headers and libraries.”

Here is another example, using software which does not make sense to install except for systems that will be having a graphical environment (called “X Windows”) installed:

sudo -i -u root pkg_add -ivv chromium

The page for Chromium has a brief description of an available “flavor” called “proprietary”. The description is: “enables patented multimedia codecs (H.264, MP3 etc)”. So, that flavor enables some additional functionality.

Note: The package called “Chromium B.S.U.” is unrealted. For details on Chromium in OpenBSD, see: Chromium Browser on OpenBSD.

If cURL is unavailable, snag wget instead.

Check if tmux is installed, by running: which tmux ”. If the system does not come with tmux, install tmux. If that is not an option, install the older program called “screen” so that the system has a nice terminal multiplexer.

And, if a graphical interface is installed on the machine:

date | tee -a /tmp/timestamp-before-adding-gui-programs
sudo -i -u root pkg_add -ivv icewm
sudo -i -u root pkg_add -ivv scite
sudo -i -u root pkg_add -ivv seamonkey
sudo -i -u root pkg_add -ivv firefox
sudo -i -u root pkg_add -ivv xscreensaver

Also, grab at least this file:

sudo -i ${SHELL}
echo ${PKG_CACHE}/..
curl -C - -L -R -v -o ${PKG_CACHE}/../$(uname -r)ports.tgz ftp://ftp.$(uname -s).org/pub/$(uname -s)/$(uname -r)/ports.tar.gz

(Simply having those files may provide options when trying to work with older systems, where these files and the packages may have been removed from at least some (and possibly all of the main) public distribution sites.)

Following are some additional files. (This is largely just provided for reference. Pointlessly putting them on the virtual machines might approximately double the size of the virtual hard drives; this is not necessarily recommended unless there is an expectation that the files may be used.)

curl -C - -L -R -v -o ${PKG_CACHE}/../$(uname -r)sys.tgz ftp://ftp.$(uname -s).org/pub/$(uname -s)/$(uname -r)/sys.tar.gz
curl -C - -L -R -v -o ${PKG_CACHE}/../$(uname -r)src.tgz ftp://ftp.$(uname -s).org/pub/$(uname -s)/$(uname -r)/src.tar.gz
curl -C - -L -R -v -o ${PKG_CACHE}/../$(uname -r)xenocara.tgz ftp://ftp.$(uname -s).org/pub/$(uname -s)/$(uname -r)/xenocara.tar.gz

If a sub-shell was created (as a convenient was of setting PKG_CACHE variable):


(Simply having those files may provide options when trying to work with older systems, where these files and the packages may have been removed.)

Other software which may be worth getting: mail (re-alpine/alpine/mutt/thunderbird), chat (pidgin/ytalk/google-talk/jabber ???), backup (bacula/amanda/???)

There is lots of other software which is rumored to be very interesting, like Asterisk. However, this is not meant to just be a list of software that might be interesting. (If so, some games might be added to that list. Wine also might be. Office software may also be.) Rather, this is a list of software which is rather suspected to be a good idea to install on each and every machine. (E-Mail clients possibly being an exception.) Perhaps snort should be added to the list? Or Remmina? NMap? (Network sniffing could also be a good idea: e.g. Wireshark. See Network watching)

At the current time, this may include some software recommendations which seem good, in theory, but which are not yet fully documented. (Additional testing/research may seem like a good idea before trying to provide directions.) However, the software may have been mentioned due to a general belief that the software would be good (eventually).

Performing file integrity checking

The file integrity checking page provides details about various options. This guide is specifically focused on using AIDE.

First, get some information about the installed version of AIDE. Pre-AIDE checking and the next section “Customize the config file” at least enough to run the 3 grep lines to see existing rules.

Create a readily accessible backup copy of the original version of the file:

[ -f /etc/aide.conf.orig ] || sudo cp -i /etc/aide.conf /etc/aide.conf.orig

Performing a standard backup should probably also be done, probably simply to help re-inforce a good routine habit worth performing.

cpytobak /etc/aide.conf
cpytobak /etc/aide.conf.orig

Run the few grep commands shown by removing existing rules section. Then disable the rules using:

sudo ${VISUAL} /etc/aide.conf

(The rules may be commented out by using two comment (“#”) characters. Using the two characters can be done in order to distinguish these manually commented out lines from any comments that pre-exist by default.)

If in doubt on whether all of the rules were successfully removed or commented out, then just re-run those grep commands.

Creating a /etc/aide.conf configuration file
Making the file on the system

Modify the existing configuration file to remove those pre-existing rules.

sudo ${VISUAL} /etc/aide.conf

The next step involves customizing the configuration file. The steps shown by the file integiry checking guide have actually been so substantial that problems have occurred by pasting the commands to a command prompt. The command prompt just didn't keep up. (The pasting was done from PuTTY, and worked fine when copying the commands into a text editor.) So, create a text file containing the desired commands:

[ -f /tmp/ ] && rm /tmp/

Create the desired file using one of the following two methods:


This method is faster.

lynx -dump > ~/modcnfv1.gz
gzip -d -c ~/modcnfv1.gz | tee /tmp/
Older, more manual method

These are some older instructions, and are not recommended for quickly completing the steps. However, these contain references to show how the downloadable file was created.

${VISUAL} /tmp/

Inside this text file, copy the example commands shown from each of the following sections of the guide. Do copy these sections in order.

Set the fintckcf variable that is referenced by the script file.

export fintckcf=/etc/aide.conf

Then, run the script file that was just created:

chmod u+x /tmp/
time /tmp/

Finally, make some changes to the configuration file:

echo ${VISUAL}
sudo ${VISUAL} /etc/aide.conf

Make the changes described by Additional recommended changes section (which contains both the Automatic compression, and verbosity increase and Output sections).


At some point, a valid working configuration file is expected to just be made downloadable.

That option has not been made available quite yet.

Next initial steps

Check that the configuration file is valid. (Details are at the bottom of the Additional recommended changes section.)

Initialize the AIDE database

[#aiderotu]: Rotate and update

Rotating AIDE's database files. (Using OpenBSD's ksh, just run all of the commands in the “Abbreviated method” section, starting with the export commands.)

Run the commands shown in “Creating the updated database file” section of the Compare and update AIDE databases section. (There is no need to run a command from the “Overview/plan” sub-section, but do make sure to not miss the “Required initial step” sub-section before moving onto running the command that actually compares and updates the database.) The “Required initial step” shows a couple of commands that need to be done only the first time. (Doing them each time should show one warning/error message but otherwise be harmless, other than just showing an error message but be harmless other than that, but those particular steps are unncessary.) Then, run either the command in the section called “Preferred syntax” (if using a shell that supports that syntax), or run the command in the “Other shells” section.)

While the update is running, go ahead and read about the AIDE return code. When AIDE is done updating, if the “Preferred syntax” was not used, then check the error code right away. Regardless of which syntax was used to update the database, check out the report by following the steps in the section called “Seeing the report”. Those who were able to use the “Preferred syntax” can then check the error code, as it will show at the bottom of the log. (The bottom log will say “Err=”.)

Considering results

The first time this is done, it seems that a number of files may be added. These files may, for example, be files in the home directories of users (including the administrator, and the user that is used for shutting down the computer).

This is not harmful, but certainly shouldn't happen more than once. If you'd like to see a cleaner report, simply rotate the database and update the database again. (Follow all of the instructions in the section about rotating and updating AIDE's database files.)

Future steps

To update the databases again, simply follow the steps by the “Creating the updated database file” section of the Compare and update AIDE databases section.

Later parts of the Compare and update AIDE databases discuss how to interpret the results.

That completes the initial steps that have been prepared at this time.

For anyone interested in developing this further, here are some steps to consider spending more time on:

  • Fine tuning the configuration file may provide more useful reports. What this means is making changes to the list of which files to ignore and which files to check.
  • Automatically updating the databases, and alerting (e.g. sending an E-Mail) when the reports seem problematic, may be additional steps to investigate.
  • Details on AIDE code signing are currently sparse/non-existent.

Info is available at Anti-Malware.

Solutions for Unix
(Possible options to explore are available: AV for Unix.)

[#clmavini]: Using ClamAV

First, install ClamAV.

sudo -i pkg_add -ivv clamav

Follow the steps from Early steps to take, which involves:

Updating the configuration file

Edit the main program configuration file:

First, check if there is a line that says “Example” without starting with a “hash”/“comment” character.

grep ^Example /etc/clamd.conf
echo $?

If there is a line that starts with the word “Example”, and the line is not a comment (meaning that the line does not have a “comment” character at the start), then the configuration file was likely still the default. So, if the second command showed results of 0, then follow this first section. (Otherwise, if the second command showed results of 1, then follow the next section.)

If the configuration file has been the default
cpytobak /etc/clamd.conf
echo ${VISUAL}
sudo ${VISUAL} /etc/clamd.conf

First, comment out the uncommented line that says “Example”.

Then, save the text file, quit the text editor, and just simply run these commands.

cpytobak /etc/clamd.conf
echo LocalSocket /tmp/clamd.socket | sudo -n tee -a /etc/clamd.conf
echo User _clamav | sudo -n tee -a /etc/clamd.conf
echo PidFile /var/run/clamd/ | sudo -n tee -a /etc/clamd.conf
echo LogFile /var/log/clamd.log | sudo -n tee -a /etc/clamd.conf
echo LogFileMaxSize 2M | sudo -n tee -a /etc/clamd.conf
echo LogTime yes | sudo -n tee -a /etc/clamd.conf
echo LogVerbose yes | sudo -n tee -a /etc/clamd.conf
echo ExtendedDetectionInfo yes | sudo -n tee -a /etc/clamd.conf
echo DetectPUA yes | sudo -n tee -a /etc/clamd.conf
echo MaxCirectoryRecursion 99 | sudo -n tee -a /etc/clamd.conf
echo ExcludePath ^/proc/ | sudo -n tee -a /etc/clamd.conf
echo ExcludePath ^/dev/ | sudo -n tee -a /etc/clamd.conf
echo ExcludePath ^/srv/virtmach/ | sudo -n tee -a /etc/clamd.conf
echo "VirusEvent logger -st clamdconfig Detection occurred!  %v" | sudo -n tee -a /etc/clamd.conf
If the configuration file was not default

Follow the lengthier set of instructions from: editing the /etc/clamd.conf file.

[#clmdspgp]: AllowSupplementaryGroups

Additionally, if there are plans to later use AMaViSd-new, then the following may be useful. The main side effect is that then clamd needs to be started as root. (This came from a recommendation in comments of the default /etc/amavisd.conf file.)

(Note: indicates the file might be /etc/amavis/amavisd.conf)

echo AllowSupplementaryGroups yes | sudo -n tee -a /etc/clamd.conf
Ensuring Files Can Properly Exist
Log file

Make a file.

sudo touch /var/log/clamd.log

Set permissions on the file. Note that some different distributions (probably meaning: different operating systems) might have a different name for the username and group, so this may need to be customized slightly.

sudo chown _clamav:_clamav /var/log/clamd.log
[#clmpidow]: PID file

Make sure that ClamAV can write to its PID file. First, see the filename for the PID file that ClamAV is configured to use:

grep -i PidFile /etc/clamd.conf

For example, if the file's name is /var/run/clamd/ and the user's account is called _clamav then:

sudo mkdir /var/run/clamd
sudo chown _clamav:_clamav /var/run/clamd

(Yes, /var/run/ is allowed to have subdirectories for programs, based on FHS documentation of /var/run/ directory.)

(Note: The directions for configuration ClamAV showed /etc/clamd.conf set: “PidFile /var/run/clamd/”, so that is what this example uses. The comment in the default configuration file shows: #PidFile /var/run/”. However, that path should not work so well if the ClamAV user does not have access to write to all files in /var/run/. Pre-creating the file once, and then adjusting ownership, is insufficient because the file's custom ownership will be effectively lost when clamd deletes the file as it exits.)

Changing freshclam.conf

The changes to freshclam.conf may be more numerous.

Note that if this is a base image for multiple virtual machines, we may want to point this to using a local server. That way, we don't need to hammer the public servers more than necessary, and we cut down on bandwidth to the public Internet locations (which is not only good for the public Internet locations, but also decreases local Internet usage).

View Modifying freshclam.conf and follow the directions.

  • The intro portion has a command line that copies a file from a template, if needed. Run that command line.
  • Run:

    echo ${VISUAL}
    ${VISUAL} /etc/freshclam.conf
  • Handle the “Example” line in this text file (as described by the section on Modifying freshclam.conf).
  • Follow the section called “This guide's recommendations”.
    • Copy the large block of text (in the section about Modifying freshclam.conf) and place those contents to the start of the /etc/freshclam.conf file. (It should go to the start so that DatabaseMirror entires can show up before the default DatabaseMirror entry that can act as a backup.)
    • Also copy the smaller bunch of configuration lines, like the ones that start with OnErrorExecute and OnErrorExecute, placing the entire contents of those lines into the /etc/freshclam.conf file.
    • Optionally: use more localized database mirrors. See commentary in freshclam.conf comments.
    • Save the text file, and run the remaining command lines.
Updating definition files

Proceeding with freshclam should not be done until the configuration file is sufficiently updated (e.g. pointing at a private server).

For base images, it might make sense to not download a starting set of defs, so that clients don't end up wasting their time with a hopelessly out-of-date set of defs. However, if most of the child virtual machines are expected to be created soon/quickly, then putting defs on the base image may be a sensible way to save disk space, bandwidth, and time.


Note that this may take some time to perform. On an Internet connection capable of much higher speeds, downloading about 70MB took over ten minutes. Such speed performance probably varies at different times, but know that performing a backgrounded update may be preferable to using this method.

ls -lR /var/db/clamav/.
date ; sudo time freshclam -v
echo $?


sudo freshclam -vd
echo $?

Also, modify the operating system's auto-start files. Some general details to help with that are available at automatically started files. Some more specific advice for OpenBSD is to run:

cpytobak /etc/rc.local
echo $(which freshclam) -vd | sudo -n tee -a /etc/rc.local

Checking the results of background downloads is a process that may vary based on how freshclamd's /etc/freshclam.conf file is configured. (The remaining discussion about log files may be speculation made after reading relevant documentation.) To know what to look for, check the /etc/freshclam.conf for uncommented lines that start with the substring “On” (e.g. “OnUpdateExecute”). If the customization directions from this guide were followed, the sample commands will create log entries which may be viewed with:

tail -f /var/log/freshclam.log

The tail -f will never end; press Ctrl-C to stop waiting for and displaying new messages.

Running a scan
Details on running a scan are at: “Performing an instant scan”.
[#clamdgo]: Starting the memory resident portion

The ClamAV software may start up significantly faster if clamd is left running. This is probably a good idea if the server will be running scans frequently (such as on an E-Mail server), or if the server is likely to run multiple scans per reboot (which will hopefully be likely for most computers).

Note, though, that this will use up memory constantly. People wishing to create virtual machines with minimal memory may want to pass on this. (The ClamAV package has been known to take up more memory, just for that one program, than all of the memory required for running an operating system and a useful server and having some spare unused available memory. So, more-than doubling the memory requirement may understandably be less appealing for some people.)

err, speculation: use zPING on the command line; maybe it doesn't just ping and exit, but outputs and then runs?

To prepare for scanning:

time sudo clamd -V
time sudo clamd

(The following might, or might not, be a good idea to do in addition to, or instead of, the previous command.)

time sudo clamd zPING

Note: When starting clamd, this may take some time before the software returns back to the command prompt. Startup times exceeding three minutes are not unheard of.

Further steps

As noted before, details on running an instant scan are at: “Performing an instant scan”.

Details about “Enabling real-time scanning” may be found on the page about ClamAV for Unix. At the time of this writing, no very satisfactory solution has been documented here. Details about handling problems may be found in the section called “Reporting issues when problems are noticed”.

Solutions for Microsoft Windows

Some free solutions are available for Microsoft Windows:

  • See sections on legality and getting the software. ][CyberPillar]['s main MSE page notes:

    The one basic recommendation for knowledgable computer users is to uncheck the “Scan my computer for potential threats after getting the latest updates.” before clicking the “Finish” button. This is so that a scan isn't likely to happen before there is a reasonable amount of time to be able to choose the selectable behaviors of automatic actions.

    Then, see the Configuring “Microsoft Security Essentials” software section.

  • For the Clamwin related software packages, be careful when downloading. ClamWin's main site is often showing advertisements for other software packages, with “Download” hyperlinks that actually downloads other software. (In at least one case, the software downloaded was widely reported to be malware.) Actually, the best installer to use might not even be on the ClamWin site. Recommendation for the fast downloads of ClamWin are described by /dirsver/1/mainsite/techns/bhndscen/protsoft/antimalw/antivir/avmswin/clamwin/getclmwn/getclmwn.htm
  • Simply installing ClamWin won't offer any additional protection. Make sure to set up updates, and either a real-time scanning solution or (probably less effectively) a scheduled scan (or both).

e.g.: code signing: No simple directions are provided here.

Additional recommended adjustments
Enabling auto-reboots

These might be desirable for systems that may be a challenge to interact with, but which should be up.

Unix panic

cpytobak /etc/sysctl.conf
sudo cp -i /etc/sysctl.conf /etc/sysctl.conf-orig
echo ddb.panic=0 | sudo -n tee -a /etc/sysctl.conf
Checking for unsupported hardware
dmesg | grep "not configured"

Got any? If so, see: detecting hardware.

Preparing the image to be a base image
mount option optimization
cpytobak /etc/fstab
echo ${VISUAL}
${VISUAL} /etc/fstab

Although mount option optimization is a widely cherished practice, the benefits may be minimal and related problems can be surprising. This is discussed by the referenced section, and so mount option optimization is not being recommended here at this time. However, if mount option optimization is desired, then now (when configuring the base image) may be a fairly sensible time for such a thing. If this is going to be done, then the recommended action is to modify /etc/fstab to the following:

  • /usr should be set to rw,nodev
  • /home should be set to rw,nodev,nosuid
  • /var should be set to rw,nodev,nosuid
  • /tmp should be set to rw,nodev,nosuid,noexec

These are based on some documented defaults from OpenBSD. It is believed that there are some various educated opinions, so consider these to be a basic recommendation and not something that is universally agreed upon.

Note that this only applies to mount points that pre-exist. For instance, if /home does not pre-exist, then it won't show up in the /etc/fstab file. In that case, a decision may be made on whether to go through the effort of creating a separate mount point with different mount options.

  • Even more aggressive: Some people may try making /usr read-only (and still nodev, so the mount options would say: “ro,nodev”), or perhaps even / as read-only. (Make them say “ro” instead of “rw”.)

The recommendations are meant to apply to sub-directory mount locations. So, since /usr should be set to rw,nodev then other mount points like /usr/X11R6 and /usr/local and /usr/src and /usr/obj (if these additional sub-locations do exist as separate mount points) should also have the nodev flag.

Optimizing a volume

e.g. optimizing a volume (e.g. defragmenting). Note that this isn't a step that is necessarily recommended. Often, the results may simply be mostly an unbeneficial waste of time. However, if this is going to be done, then doing so before finalizing a drive image may make the most sense.

Specifying local servers

Remember what the name is of the local network. For instance, run:


If the network name seems undesirable, see: setting up an installed operating system: section on setting the host name.

[#ntpdlcsv]: Make sure to specify a local time server

(Note: This is recommended. However, may still be untested at the time of this writing...

This is highly recommended/required in order to avoid being blacklisted from commonly used public servers. As noted by guide to setting up ntpd, having too many requests from the same Internet location may be treated like a “denial-of-service attack”. That may sound extreme, but the problem can be easily avoided by having computers specify a local time server.

Since most child images should be using a local time server, make sure that the name of a local machine is what got placed into the ntpd configuration. Additional details are avialable in the section on setting up ntpd, but basically what we want is to place a private domain name in the configuration file.

This sample code is based on using the custom configuration file that is shown by the examples described in the section on setting up ntpd.

echo ${VISUAL}
sudo ${VISUAL} /etc/ntpd.conf.local




servers ntp.time.mynet

... where “mynet” is the name of a network that does, or will, be handled by a private DNS server (that can be re-configured as desired). For example:


Then, look up that name in DNS. e.g.:

nslookup ntp.time.mynet

If that DNS name does not exist, but if a private DNS server does exist, then add that name to the DNS server. (Once again, it is hereby pointed out that the “mynet” portion of that name is meant to be the customized name of a local network.) If a private DNS server does not exist yet, then perhaps just don't worry about the problem until a local DNS server becomes operational (which hopefully won't take too long). When altering the DNS server's zone configuration, a simple solution may be to add a DNS CNAME that points to or something better.

Here are some ideas of what might be better:

Additional discussion/options
DNS name

It is best to use a DNS name that references time. For instance, if the NTP server is going to be the same machine as the web server, then use a DNS CNAME that points to the name of the web server. Have all of the clients use the DNS name that relates to time. This way, if there is ever interest in having clients start using a different NTP server instead, a simple DNS change will start to point clients to the new desired location.

If there is not a time server set up yet, the best approach would be to simply designate a machine that will act as a time server. Any machine that will be online regularly, has no problems keeping time, and which can handle the minimal traffic that NTP could handle, would work.

A workaround may be to just have the private DNS name be a DNS CNAME that points to a public server. That should effectively work until a local time server is operational, and allows the base image to be set up immediately. However, it would not be a bad idea to check the DNS setting whenever setting up a machine. Do eventually fix the problem (by setting up a local time server).


(This is likely extra information that does not need to be acted on, and is simply offered for explanation to the curious.)

OpenBSD's manual page for a ntpd.conf file docuements the meaning of “weight”, and does so under the section for “sensor”. The topic then does not seem to be brought up again, similar to how the optional “rtable” word is discussed in the section for the “server” option, but then is not re-dicussed when discussing the “servers” option.

Ubuntu manual page for OpenNTPD's ntpd.conf file discusses weight near the top of the file, which makes it seem to apply to all options.

Anti-virus data

The penalty for not doing this may seem less harsh than with time servers, as Anti-Virus might be less prone to blacklist people (realizing that even greater impacts may be likely when their services are not provide). However, there are still the general benefits of providing less load upon the public servers, and using less private Internet bandwidth.


In /etc/freshclam.conf prepend a line to specify a local, privately run server.

If there are plans to put up a private server in the future, then placing the server's name in the configuration file may be good thing to do, even if the private server isn't yet deployed. Until the private server is deployed, this may delay computers from updating (by perhaps half a minute or a couple of minutes), but that shouldn't be a big deal since the updating process should be a background process. It is better to make sure this configuration is done before being forgotten about.

Ideally, choose a DNS name that is unique to ClamAV updates, and not a general purpose web server. That will allow easier future adjustments, in they become desired.

(Directions for this are not being provided until a set of throughly tested instructions are provided. A reference to official documentation would also be preferred.)

Other update patches

Private servers may be efficient ways to store data related to operating system updates, and perhaps updates of other software.

This idea is not being mentioned before because of the task being critical to do for a small-scale network. Instead, this is simply an idea that sounds good and may be expanded upon in the future.

For now, this guide does not have substantial further details about this topic.

There may be details related to operating system updates. For example, the section about OpenBSD has a sub-section called “Upgrading/Updating OpenBSD” (which hyperlinks to a file about updating OpenBSD). Users of other operating systems may check the section about operating systems to see if there is similar information provided for another specific operating system.

Files exist that may be good to delete from base images

(This process is documented later, as it may be a process that makes more sense to perform later. However, it is a process that is related to base images, so it is being mentioned here for reference.)

(The instructions are in a later section called Removing files that re-generate uniquely, but are probably not best to perform quite yet.)

[#mkaltdsk]: Utilizing a second drive

Note: This is a section largely about putting a drive to use, including formatting the filesystem. An earlier step prepared the computer to try to automatically accessing the second disk: supporting the /srv/hddcfg mount point.

Identify the drive

To determine the name of the drive, see: detecting drives (in BSD), making a file system: destination name

For this entire section, choosing the right drive is most certainly CRITICAL to avoid data loss! If using a drive name different than the examples, be very careful, with each example, to make sure that work is being done on the desired drive!

sudo fdisk wd1

Make this this is the right drive. (If unsure, also make fdisk reports on other drives that were detected.) If following the directions of this tutorial, presumably the second drive might still be blank. Drives may be identified using details such as the size of the drive and its partitions, as well as partition types. If still unclear, there might be additional methods such as viewing a drive ID. An option that does likely exist is to mount existing partitions (if they are unmounted) and seeing what is on the partitions. (However, mounting is an activity that has been known to lead to system instability when working with corrupt drives. So, that might not be the first choice for a system that may be actively being used by other people or automated processes.)

Make an MBR partition
sudo fdisk -e wd1

In the program:

Print the partition table:


Edit an unused partition entry.

e 0

Choose a partition type. e.g., for Linux Ext2, we would specify data handled by Linux, by specifying MBR type 0x83. (If we wanted OpenBSD FFS, we would use A6.)


Press Enter twice ([n], followed by the initial offset [0]).

For the size, it might default to maximum which is probably okay, so if that happens then press Enter a third time. If the default size is zero, then press * (and then press Enter) to make a full-size partition, if full-size is desired. Otherwise, enter the desired size. If editing a pre-existing partition and wanting to enlargen the partition to the maximm size, enter a size of *.

Write changes, and exit, by typing the following:

Editing the disklabel
sudo disklabel wd1
sudo disklabel -E wd1
Updating the UID

List the current values:


See the lines that say “label:” and “duid:”.

Update the numeric ID.


Now type in the disklabel UID that /etc/fstab expects to find. (Or, make up something that will be unique for this disk, and will not be used for any other disk on this virtual machine.)


The change may be verified by listing the current values again:


(This is not suggesting that the change has taken full effect: these directions have not yet caused the change to be saved. So, the change is not written to disk yet. However, seeing the change does verify that the disklabel program applied the input as expected.)

Creating a disklabel section

Show the current contents.


In OpenBSD and NetBSD, we need to have multiple entries. One entry will be for the entire disk, and is automatically created. The size of that entry is not modifiable. There needs to be another entry (which might also want to cover the entire disk).

Choose one of the following methods. (If this is a second hard drive that will be used for data, rather than booting the filesystem, then use the first of these options.)

To manually make a single partition:

Specify to add a disklabel entry.


The default “drive letter” (a: for the first disklabel entry) is fine.

The default offset is almost certainly fine.

size may be fine (or enter * if modifying an existing disklabel entry and, if the default size isn't the entire space, and if the largest available space is the desired size).

For FS type, the input is case insensitive. If we want Ext2, then use ext2fs. If we want FAT, then MSDOS is the best value to type. If we want FFS(2)/UFS(2), then the default (4.2BSD) is fine. If a decision hasn't been made yet, feel free to take a gander at the section about deciding which filesystem to use. (Hint: another part of this guide may have specified ext2fs. That may be what is specified by the /etc/fstab file. For drives under Ext2's filesystem limits, like the largest 32TB limit, Ext2FS may often be an excellent choice, due to rather widespread compatability/support. This might be even more true for drives that are 2TB or smaller.)

To make a bunch of different disklabel partitions:

The command of disklabel's “A” command might make several partitions. This is probably not desired for a drive that won't be booting the operating system.


Show the current contents.

Saving changes

The w command writes changes to the disklabel. The q command writes changes to the disklabel and then quits (and says “No label changes.” if there were no changes since the disklabel was either loaded or written). Alternatively, the x command will exit without writing to the disklabel (although the “exit” command does not undo any changes that were already written to the disk).

Updating /etc/fstab

To prevent an accidental early mount attempt (which will likely just generate a harmless error message), this should probably ideally be done after formatting the filesystem volume. However, getting this over with, before this task is forgotten, may not be a bad idea either.

Make sure that if /etc/fstab is using disklabel UID's, then the disklabel UID used by /etc/fstab matches the value that disklabel shows for the drive's disklabel UID.

(It is possible that no changes are required.)

The following commands are just shown for convenient copying and pasting, in case that is helpful.

cpytobak /etc/fstab
echo v=${VISUAL} e=${EDITOR}
${VISUAL} /etc/fstab
Creating a partition

First, BSD will want the “BSD disklabel”/“bsdlabel” entry updated. The filesystem formatting software will reference the disk section by a reference to a device that is named after the “BSD disklabel”/“bsdlabel” entry.

There's actually quite a bit to read from the material that is about to be referenced. The filesystem formats may have the most specific information about creating a specific type of filesystem. e.g. making an Ext2fs filesystem. Otherwise, the more general guide to making a filesystem may guide through the process (perhaps especially the “Making a filesystem volume in Unix” section). Of particular note, if the plan is to use Ext2, then see the Ext2fs warning about mixing packages.

As a generalization, if Ext2fs is desired then, in most cases, the following will probably work out fairly okay:

which newfs_ext2fs
sudo time newfs -t ext2fs wd1a

The time taken will vary based on different criteria, such as how fast the hardware is (most especially the speed of the drive writing the data), and how large the partition is. Filesystem format and technique can also be impactful: a command that checks the disk may take a number of additional hours while some other software, or software options, may be able to make an equally functional filesystem within seconds.

If the filesystem formatting looks like it will take a very long time, there are a couple of possible responses. One is to consider whether the drive was made too large unnecessarily. (See Partition size section's sub-section titled “Overview: Why not to allocate every byte”.) Perhaps it is possible, safe, and quick to abort the process, and make the drive a different way.

Another possible response is to do something else, such as proceeding to the next section about documentation. (Work on that while the computer is writing to the drive.) Since modern operating systems offer multi-tasking, the computer can often be used for other purposes while waiting for a time consuming task. (Exceptions may exist, such as when an overloaded USB hub did not allow keyboard or mouse movement to work right when accessing a drive via USB. However, such a situation is quite uncommon, and possibly dangerous because the bugginess suggests strong possibility of data unreliability.)

Post-creation filesystem changes in Unix refers to adjusting/tuning filesystems and other tips to perform.


If documentation related to this computer has not yet been made, then start making it.

Why now?

Trying to remember a bunch of names and IP addresses and logins may become increasingly difficult over time if different names and IP addresses and logins start to be used later. Having the information in some documentation is likely to prove to be very useful. (An exception may be in a classroom environment, where the virtual machine may be expected to be erased soon. In that case, the details may be useless, but the experience in making the documentation may be... far less useless.)

Documenting things now may be easier; if information is not remembered then perhaps what will be remembered is what file contained the information, so the information can be looked up more quickly now.

The following are some of the most desirable details to make sure to be documented.

System name(s)
Primary system name

There may be several ways to retrieve the base host name:

  • after setting some initial variables to identify a script, document ${VMLILNAM}
  • The system hostname may also be shown by running hostname (in Unix or Microsoft Windows, tested in Windows 7)
  • Other servers may have information related to this system: a name resolution (DNS) server and perhaps also an automatic addressing (DHCP) server.
  • In Microsoft Windows, access the System control panel applet

Some of those methods might just show a host name, while others might show a longer (more “qualified”) domain that includes a reference to the network that the machine is a part of. Other than that simple difference, hopefully all of those names match (although some might be more abbreviated, showing just the system name, while other names may show a longer name including, and also match the DNS name for the machine.

Additional names

If the system has a “service tag”, that might be useful for being able to look up warranty information. This can often be retrieved by using SMBIOS. (See skeleton system documentation's section on “SMBIOS”.) If SMBIOS is not providing the details, and especially if the details are not physically written on the computer case, but if the details are in the BIOS, then document the information (now while it may be relatively convenient), so that later the information can be retrieved without needing to reboot the computer when rebooting would be far less convenient.

System Purpose

Describe the purpose of the system.

This does not need to go into a lot of details: there is a later documentation section called “Software uniqueness” for that purpose. This is just a quick description, in case the name is insufficient, to help somebody be able to quickly determine whether this computer is likely to be responsible for whatever a person is looking for. (It lets a person quickly determine to review the rest of the documentation for this computer, or move on to checking the documentation for another computer.) There may be little to no need for such a description when the computers are well-named. However, computer names should be short (less than nine characters) for convenience, and various technical limitations (perhaps often just for compatibility) may require that names are less than a certain length. This is a chance to just jot down a sentence, or even just a phrase, or two, which may describe the purposes described by this machine.

Longer details can be noted in the “software uniqueness” or “hardware uniqueness” sections, as appropriate.

System network addresses

Especially note the IP addresses.

Also, the MAC address can be useful for setting up DHCP reservations, and it can also be useful for sending a “WOL” (“Wake-on-LAN”) “magic” Ethernet packet to just this computer. However, opinions on documenting a MAC address may be mixed. (People may commonly find that recording the MAC address may be overkill for computers that don't have an address reserved by DHCP.) The author of this text recommends recording that, knowing that this is a specific item that people may disagree with.)

If the system has any specific/unique known DNS name(s), include any important/useful such name(s) in the documentation.

Login details

Provide answers for each of the following:

Remote Administration
Using a remote access protocol

How can an administrator get access to the system?

For networked computers, this may be as simple as referencing the network, and referring to documentation on the network. (However, if this is the first system on a network, then that network documentation probably needs to be created and to have that detail.)

Make sure to document:


Document at least one protocol that can be used to remotely administer the device. Visual people might want documentation for a method of sharing a visual output display although less graphical servers might choose to use any of the remote access methods. If a visual method is available, and a streamlined text-only method is also available, documenting both is not a terrible idea.

Also document the TCP port number or UDP port number, if not standard. (The standard may be a public standard, such as IANA's port numbers. Or, if this remote access is only meant for internal use by an organization, and the organization has selected another port as a default in that organization, then referencing that standard/policy can be sufficient.)

User account
The user account to be used to log in

For virtual machine base images only: just storing passwords is typically the most sensible approach.

For all other machines: note stored passwords if required, but it is preferred to record the/a location of the private key that gets used to log into this machine.

Where high security is desired over convenience, storing a copy of the public key's fingerprint (and related “artwork” when using modern OpenSSH software) could also be documented. This can be used by clients to help verify that connections are being made to the intended server (rather than a server performing a MITM-style attack).

Extreme security processes could also document the entire public key that is used when logging in.



ssh -P 22 -i /somepath/privkey username@sysname.netwknam
sudo -u $(whoami) sh
Remotely accessing the local console

Is there a way to view the system while it boots up? For instance, if the bootup process provides an ability to set up BIOS configuration (quite common on physical machines), or to access an option ROM such as being able to adjust the setup of a hardware RAID configuration card, then are these activities able to be accessed remotely? Commonly the answer may be “no” for physical machines, although the hardware section has a classification of “Remote access hardware” (such as an IP-capable KVM switch). For virtual machines, accessing the local display(s) of virtual machine(s) may provide some information.

When documenting an individual computer system, this documentation does not necessarily need to be extensive. For instance, the documentation might be as simple as referencing the type of remote access card that gets used, as well as its IP address, and a reference to a document on how an organization typically configures such a remote access card. (The details for the section on “Using a remote access protocol” should also be covered here, but all of those details might be able to be figured out from the inforamtion that is thoroughly discussed in the documentation on how an organization typically configures such a remote access card.)

Local administration

If a person is standing in front of the computer, how can the person log in? (Hint number one: the details may be very similar to details recorded in the section about remotely accessing the computer. Hint number two: relying on an SSH key is probably not going to be a sufficient answer. Hint number three: having an answer to this is often a good idea for physical machines. However, it is possible to have a computer that does not provide an easy way to do this.)

Standard user login, common user(s)

Can a standard user log in? What remote access methods might a standard user typically use to access the computer?

Presumably any member of an organization's IT department may access the computer at any time. What other usernames can log in? Who will typically log in? (e.g., for a laptop, that might be a single user. For a workstation in a specific room, the answer might be a role such as “supervisors of customer service representatives”.)

System location
For a physical machine
“In the primary Seattle data center, server room on the fourth floor, second shelf.” If the system is properly labelled with the name of the computer (such as with an easily visible sticker that is on the front of the machine), that may be sufficient.
For a virtual machine

Mention a physical computer that runs the virtual machine. If that computer does not have useful virtual machine management software (because the virtual machine is somehow remotely managed), then also mention a computer that provides the virtual machine's management software.

Mention the location of any hard drive image(s) that get stored. The location should include the name of the computer/device storing the image, and also the directory/folder of any file used. If there are “snapshot”/“child” images being used, then multiple hard drive images are being used, so make sure that all such files can be easily found by using the documentation.

(If this guide was followed when using Qemu, then there was a recommendation to record the command(s) used to create the guides. If the qemu-img command was supplied with full paths, that would effectively document the directory name(s) and filename(s) for ay hard drive image file that was used when the drive was created. So, that may be suitable documentation of those hard drive images as long as the drives did not get moved later.)

System startup method

For a virtual machine, what computer is running the virtual machine, and what command is started?

For physical machines, if the primary power button is not on the front side of the computer's case, and is not on the front portion of the top side of the case, then noting the location of the primary power button can sometimes be helpful.

For physical machines: if a remote access method of turning on the machine is supported, note that. e.g.: WOL (“Wake-on-LAN” “magic” Ethernet packet), which might be useless information unless the MAC address is also noted. Alternative methods, such as waking up on a keyboard stroke sequence, or waking up from a dial-up modem call, are less common.

System shutdown method

Is there a command that can be run to safely shut down the computer?

For a physical machine: will just pressing the power button once (quickly, not held down for multiple seconds to initiate an ATX power down) result in the operating system starting to perform a clean system shutdown?

Hardware uniqueness

For virtual machines, these details may be visible by looking at the virtual machine configuration. The virtual machine configuration should be either defined, or at least conveniently referenced, by the command that is used to start the virtual machine, so having the “system startup method” documented is useful. Depending on the level of desired thoroughness, the level of details to document could be as simple as mentioning the command used to start up the machine, and a reference to any sort of standardized template that was used when creating the machine.

For physical machines: Note any unusual adapters. If there is a power button but it is not on the front of the case, and it is not on the front side of the top of the case, document that. If the machine sticks out (like a bright green case that nVidia had released as a promotion), perhaps document that.

e.g.: “Only power button is on the actual PSU.”

(That comment assumes familiarity with the fact that PSUs of stationary computers (meaning computers that are not commonly moved like what laptops may commonly be) are typically on the back of machines. If the documentation is likely to be handled by novices, a better description would be: “The only power button is right by where power cord goes into the back of the machine.” The level of detail required will depend on the expected audience for the machine.)

Software uniqueness

Is there a standard template that is being used to determine what software to install? (Possible references: installing common software, the “Handling ports” section of this guide.

What software has been added? The best way for this to be documented is to make a note of software when installing software, especially if the software is not part of some centralized standard list of commonly installed software. However, here are some tips for checking for additional software that may have been installed.

Finding out what software has been added

The following are some hints on how to see a list of software that has been installed.

if using pkg_*

Run the following:

pkg_info -mq | tee pkglst-m.txt
pkg_info -q | tee pkgsall.txt

(This is based on: sohwing software installed with pkg_*.)


echo ${PKG_CACHE}
ls -l ${PKG_CACHE} | tee -a pkgfiles.txt

Then, see viewing a text file.

Microsoft Windows

Perhaps run:

WMIC Product GET /FORMAT:LIST >> products.txt
type products.txt


WMIC Product GET /FORMAT:TABLE >> prodstbl.txt
type prodstbl.txt

Unfortunately, that list is probably going to be very incomplete. See also: Programs-related Control Panel icon, installation of software in Microsoft Windows, and running:

dir "%ProgramFiles%" "%ProgramFiles(x86)%" "%ProgramData%\Microsoft\Windows\Start Menu" "%APPDATA%\Microsoft\Windows\Start Menu" "%ProgramData%" >> progs.txt
for /D %X in (%USERPROFILE%\..\*) do dir "%X\AppData\Roaming\Microsoft\Windows\Start Menu" >> progs.txt
type progs.txt | more

The methods just described might reveal some programs that have been installed. More thorough checks for installed programs (or possibly other important files) may be determined by looking at the results of a recent file integrity check.

Standard details

What are the primary services offered by the machine?

What should be regularly backed up? (e.g., for a DNS server, the configuration files may be sufficient. For a DHCP server, the configuration should be backed up, and the program's running data (which are the DHCP leases) would also be preferred (but is often non-essential) to have backed up. For an organization's primary E-Mail server, the configuration is good to have documented but the program's running data (which are people's E-Mails) may be considered to be some of the most critical data for an organization.


When was the machine initially setup/deployed?

Other than that detail, this section might initially start out fairly blank.

Are there known or suspected problems related to this machine?

Have any of the parts been replaced? Since the machine was initially deployed, has there been prior work done to make the machine be able to function as desired?

Anytime that SSH keys are changed (including simply deleting them), that should be documented in the history. If anybody ends up using a device that remembers information about the prior key, the SSH software may display some alarming message (e.g. the message shown in the section of dealing with a(n  unauthorized) SSH key change). A person presented with such an alarming message may be able to quickly figure out what happened to cause this alert, if the SSH key destruction is documented.

Other useful details

If following the steps of this guide, a detail worth documenting include the virtual machine number (${VMNUM}) may be worthwhile. Also, some details worth being documented include the ${VMLILNAM} variable and other variables discussed in the section about setting some initial variables to identify a script. However, those variables (other than the virtual machine number (${VMNUM})) might already be documented in the section that showed the commands used to create the hard drive image.

Those are probably the most commonly useful details. Other details related to system documentation may be available at the section about network documentation, including documenting systems, and also in TOOGAM's tutorial on building a network.

Final changes to the disk
Scheduled script(s)

Some preliminary experience suggests that there may be quite a few changes made at the end of the first day, when OpenBSD's /etc/daily script is run. Therefore, there may be some benefit to (perhaps either running the script manually?, or) waiting a day for the script to run, and then updating the file integrity database, and then compressing/archiving a parent/base image at that time. The benefit is that each child may then have file integrity check reports that don't report all of the new directories made by the /etc/daily script.

Note that this may make several changes to the hard drive. This guide does not provide details on how to back up files that may be changed from this process. (However, this is something that the operating system vendor has scheduled to run automatically, so chances are much higher than not that the impact will be bneficial, and not harmful.)

If you want to try running that script (which might be a good idea, or might not be a good idea... this is still speculative), then run:

time sudo $SHELL /etc/daily

On a side note, there are other scheduled scripts as well. They might also run overnight, depending on the date.

[#vmbrmunq]: Removing files that re-generate uniquely

Note: This section is particularly meant just for finalizing a “parent/base image”/“backing file”. If these instructions are being reviewed/followed when creating a child/snapshot image, then this particular step is probably NOT desired. (The files listed here probably ARE desirable for child/snapshot images, and so the files should not be deleted for that type of image.) A virtual machine hard drive images probably should only have these files be deleted when the hard drive image is intended to be used as a “parent/base image”/“backing file”.

Some files should be re-created uniquely on each child image. Hopefully randomization will notice updated times and/or other unique details, and cause different files to be created with each new child image.

Remove (with sudo rm filespec) the following files. (A sample command line will output the name of each existing file, and can easily be adapted to become a command line that deletes files.)

It is abundantly important that this be done on the right computer! This is meant to be done on the virtual machine.

  • (High priority) - System key files mentioned by system SSH keys. These include /etc/ssh/ssh_host_*key and /etc/ssh/ssh_host_* files.
  • (Uncertain priority) - ISAKMPd files: These include /etc/isakmpd/private/local.key and /etc/isakmpd/
  • (Uncertain priority) - IKEd files: /etc/iked/private/local.key and /etc/iked/
  • (Perhaps unlikely, but high priority if applicable) - WIDE-DHCPv6 UID: /var/db/dhcp6c_duid or, if that doesn't exist, /var/lib/dhcpv6/dhcp6c_duid or, if that also does not exist, perhaps dhcp6c_duid in some other location.
  • (Low priority, but better if deleted) - DHCP client lease(s): /var/db/dhclient.leases.*
  • Speculation: Maybe: Anti-virus defs (files in /var/db/clamav/), if they are expected to be old when most new virtual machines are created. (Or are old definition files useful for upgrading? In which case they should not be deleted.)

If the SSH keys were deleted, then relevant data from SSH clients may also be a good idea. In Unix, review ~/.ssh/known_hosts and find any line with the IP address of the system that had its keys removed. All such lines in that text file are useless, and should be removed. For other SSH software, see when there is no saved SSH key.

Here is a command line that may help:

echo $( sudo $SHELL -c "eval ls /etc/ssh/ssh_host_*key /etc/ssh/ssh_host_* /etc/{isakmpd,iked}/private/local.{key,pub} /etc/iked/private/local.{key,pub} /var/db/dhcp6c_duid /var/lib/dhcpv6/dhcp6c_duid /var/db/dhclient.leases.* 2> /dev/null ")

Note that the above command is just a test, and does not actually do anything. If the results look good, replace the echo with “sudo ls -l ” and if the results still look good, replace that with “sudo rm -i

If the base image gets started again, then some of those files will be re-created (and so will need to be deleted again). Keep this in mind if a reboot happens.

Removal of these files may prevent some services from working. For instance, sshd seems to keep working for existing connections, but refuses to accept any new connections. This may be a non-problem if there are expectations to be stopping the system soon.

Also, see:

[#sshkyrmf]: Following up with deleting SSH keys

Also, when deleting the SSH keys from a server, document this fact in the documentation related to the virtual machine. This is because documenting SSH key changes should simply be standard practice. By following that practice, hopefully people can quickly figure out what happened when authorized key changes have taken place. (That may help them to understand what is happening when an authorized key change takes place. Also, if an unauthorized key change takes place, this standard practice might help by appropriately raise concern when a key change doesn't appear to be documented.)

Additionally, it can be nice to update the client(s) as well. Ideally, all clients will forget about the old key, although implementing that may be a challenge. (Making an announcement across an organization may or may not be appropriate; it would make sense for some small IT departments. E-Mailing the entire IT staff of a large enterprise organization, especially over this type of issue, would generally be considered unacceptable. Posting a message on a private forum, which is only used by IT staff, might or might not make sense. What really makes sense will likely vary between different IT departments: what makes sense for one organization might not make sense for another organization.)

If the server is currently being accessed using SSH, then the client currently being used can likely be updated. For instance, if using OpenSSH on Unix, edit ~/.ssh/known_hosts to remove the reference to the key related to whatever system name or IP address was used to create the SSH connection. For other types of systems, see Dealing with a(n unauthorized) SSH key change and/or the section titled “When there's no saved SSH key” (which has details about where some clients store the data).

Remove specific network settings
Adjusting IP configuration

If the base image is not using automatic network configuration, then adjust the startup scripts. For instance, if the startup scripts assign a specific (“statically assigned”) IPv4 address, then take out that configuration and have the computer configured to rely on DHCP.

How to use DHCP

Any references to if0 need to be customized to reflect the actual name of the NIC on the virtual machine.

On the virtual machine:

cpytobak /etc/hostname.if0
echo ${VISUAL}
sudo ${VISUAL} /etc/hostname.if0

(Specific directions may need to be reviewed for confirmation. OpenBSD's manual page for hostname.if file. Probably the lines desired will be “dhcp” (or “dhcp NONE NONE NONE”, as mentioned by the manual page) for IPv4, and rtsol for IPv6.)

Adjusting name resolution

Similarly, have the system configured to rely on internal DNS servers. (This may be less critical if DHCP is just going to overwrite this information anyway.)

How to adjust name resolution
cpytobak /etc/resolv.conf
echo ${VISUAL}
sudo ${VISUAL} /etc/resolv.conf

Determine what internal IP addresses are most likely to be used for name servers, and use those.

These changes may cause functionality to stop working on the base system, and they might even be unpleasant for the first child image or two (e.g. until the DNS server is operational). However, if there are going to be many virtual machines, then most virtual machines will probably be best off using the automatic assignments and the names of internal machines. So, adjust the settings to what will work well for most o the child images that will be created.


If there are any other customizations that would be desirable, then doing so (before updating the file integrity checking database) may be desirable.

If the virtual machine's hard drive is expected to be used as a base image, and if the system has been restarted since the last time this was done, then: remove unique files (again). If this does get done again, though, make sure to document the removal of SSH keys. (Other than that slight hassle, there is little chance of harm by doing the process again. So, if in doubt, perform the process again. Doing that one too many times is only a slight nuisance; having a pre-existing key in a base image can be a notably bigger hassle later.)

Handling (final) file integrity checking

After making any other changes, rotate and update the file integrity checking database.

(After updating the file integrity checking database, Rotating AIDE's database files yet again may be nice, as each child image may then treat an initial rotation as being an unnecessary (but safely optional) step, rather than being a step that should be performed.)

Marking the most recent database for easy future reference

Make the latest file integrity database on the base image noticeable somehow. This may be done by making a symlink, or giving that copy a noticeable name, or documenting that database somehow. This way, people can later make a bunch of changes to a child image, and then see all of the changes made to the child image by comparing an updated database to this database. (That can be useful, for instance, if trying to copy all customized files (including data files like password databases) to a second hard drive. By having an easily accessed database of what things looked like on the base image, people can see what changes were made to the child image.) Unfortunately, the changes described here (like making a symlink) may appear to be a change in the child image. There's really no simple/easy way around that unless the filename is excluded by the file integrity checker's configuration.

e.g.: The following may work if rotation was done (after the most recent update) using the example abbreviated method, or the example preferred method, both of which name files after timestamps.

echo ${AIDEDBFL}
sudo ln -s $(ls -t ${AIDEDBFL}/aide/olddbs/aide.db.old* | head -n 1) ${AIDEDBFL}/aide/olddbs/aide-archived-basesys.db

(At the time of this writing, this method hasn't been very thoroughly tested. Creating the symlink probably works. However, Speculation: after the databases are updated, the old database may be rotated to a different loation. Perhaps that leaves a dangling symlink. A better approach might be to copy the file to the location of old data files, and then make the symlink to that longer term location.

These instructions will likely be updated after performing some more testing on child images...

(File integrity checking should probably always be the last item done before the system shutdown of a readied base image.)

Handling the disk images made so far

If there are no further changes to make on the host machine, then shut down the virtual machine.

sudo halt -p

The following may be useful in case the variable got unset at some point:

[ "X${VMAgeDir}" = "X" ] && export ${VMAgeDir}="baseimgs"
echo ${VMAgeDir}
Deleting old junk

If there was an old temporary file storing the larger version of an image, which was being held just to make sure that things were operating properly when using a compressed image, then now may be a sensible time to remove the old file. (Presumably, by now, the compressed file was confirmed to be working.) e.g.:

(The first command is just a series of variable checking. See: setting some initial variables to identify a script)

echo ${VMDirBas} ${VMGenNam} ${VMLILNAM}
ls -l ${VMDirBas}/diskimgs/${VMAgeDir}/${VMGenNam}/${VMLILNAM}/
ls -l ${VMDirBas}/diskimgs/${VMAgeDir}/${VMGenNam}/${VMLILNAM}/${VMLILNAM}1-uncompressed.qc2
rm ${VMDirBas}/diskimgs/${VMAgeDir}/${VMGenNam}/${VMLILNAM}/${VMLILNAM}1-uncompressed.qc2
ls -l ${VMDirBas}/diskimgs/${VMAgeDir}/${VMGenNam}/${VMLILNAM}/
Overview: some old notes

Shut down the virtual machine (with “ sudo halt -p ”) and compress the hard drive image (by being very careful to remember to customize the destination/output filename when following the example from compressing a disk image). If this hard drive image is then going to be used as a base system, modify the hard drive image to make it read-only (as mentioned by the “Modifying permissions” sub-section of the guide about compressing a disk image, although the permissions change would make sense to do even if disk compression is (for some reason) not being used. If later changes are to be made to this image, then either create a child image containing the desired changes, or make a copy of the entire parent image, or update the parent image with the realization that any change made may/will effectively wipe out the usability of all child images.

Backing up the progress made so far

Now may be a great time to back up the progress made so far. Make a file called ${VMDirBas}/diskimgs/${VMAgeDir}/${VMGenNam}/${VMLILNAM}/${VMLILNAM}1-post-install-hardening.qc2 (or any other name desired). The general/recommended process is to start with these steps:

  • See what files currently exist by running:
    ls -l ${VMDirBas}/diskimgs/${VMAgeDir}/${VMGenNam}/${VMLILNAM}/
  • Be careful to customize the filename that is going to be created. (Do not use the example filename if a file with that name already exists! This is probably taken care of simply by setting a value for VMMorNam. Set it to a unique value that has not been used before. Then, when following the directions to compress a drive, skip any instructions that assign a different value to VMMorNam.

    (The virtual machine should not be running at this point. So, this command is meant to be performed on the machine that runs virtual machine software.)

    echo ${VMMorNam}
    export VMMorNam=post-install-hardening
    echo ${VMMorNam}
  • See: backing up an image by creating a compressed copy

After backing up the system, make sure that VMMorNam is set as desired, and then re-perform some of data image handling tasks:

More changes to make to the hard drive image files
WARNING: UNTESTED: These directions will probably work well, but should be tested again before these instructions are fully recommended. In the mean time, carefully consider the results of each command before trusting these steps. If in doubt, copy files to a very safe location.

After creating the compressed file, modify the permissions of the newly created compressed file. (Do that to reduce the chances of easily accidentally modifying this backed up copy of the file.)

Furthermore, it may then make sense to move the larger image to a temporary filename, and make a new child image.

Check the results of any changes:

ls -l ${VMDirBas}/diskimgs/${VMAgeDir}/${VMGenNam}/${VMLILNAM}/

If all looks well, then the VMMorNam has no foreseeable need to be used soon, especially with whatever its current value is.

unset ${VMMorNam}
Modify the startup script for the virtual machine that uses the base image

Consider this to be an optional step to perform on the system that is running the virtual machine software.

If this script may be used as a template for other systems, consider making some changes. Especially, remove any requirement to an (optical disc) image file that will generally be unneeded, and which was only used for helping the operating system to be installed. This can be done at any time after the disc image is no longer needed. (The script can even be modified, to have this specific change, while the virtual machine is running.) Also, setting networking back to its initial state may be worthwhile.

(If needed, see: Set some initial variables to identify a script.)

echo bas=${VMDirBas} gen=${VMGenNam} nam=${VMLILNAM}
ls -l ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/
ls -l ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstart/
cp ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstart/exc_${VMLILNAM} ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstart/exc_${VMLILNAM}-after-sys-harden
cpytobak ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstart/exc_${VMLILNAM}
${VISUAL} ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstart/exc_${VMLILNAM}
[#mkchldvm]: Tasks for additional virtual machines that may use child images

(This section was previouisly named: “Things to do on a new system”.)

Making choices

Create documentation for the new system.

Make some choices related to the new system. Namely:

Recommended: Determine a purpose. Have some idea of what the system may do. That may be helpful for the next step.
System name

Choose a new system name.

If this will be a new network, consider what network name to use.


Choose a unique virtual machine number.

Network Identifiers

Choose IP usage. Here are some details:

Number of subnets: Based on machine type/roles

If this machine is going to be a multi-homed (meaning: multi-NICed) firewall, choose a couple of separate subnets.

Many other types of servers, such as name resolution, automatic addressing, web content, and E-Mail can get by with just one subnet (and using just one NIC).

Picking addresses

Choose an IP address for the system.

Usage of network addresses for individual hardware/software provides possible layouts for deciding on the last part of an address. (As a generalization: network infrastructure comes first (or very last with some older IPv4 standards), followed by some address space being reserved for servers for the most popular services like routing, name resolution, automatic addressing, and authentication.)

Further help on deciding on an address: The first part of the address will be the subnet: choosing subnets (section from this guide) has some tips on that. Perhaps also: planning out networking (section from the older guide on this same web page), address usage.


Preparing to make a firewall, six subnets were selected. Half of those are for IPv6 and the other half are from the aged IPv4.

I chose to start with network #8 out of what was available to me.

Following the order from choosing subnets, the firewall will use 192.168.8/30 and 192.168.136/24 and 192.168.72/30 as IPv4 subnets. (Although the subnets are listed in order of preference, the choice was selected to pick something a bit later, to be unique from what everyone else picks. It would be best for other people if they didn't instantly pick whatever they see in documentation: pick a unique or randomly selected number to start with.)

For IPv6, there is some controversy regarding whether or not to use private addresses and NAT. For the purposes of this documentation, and to try to show what actually usable address might look like (so unusually avoiding any reservation from RFC 3849: IPv6 Prefix Reserved for Documentation), the decision made for the current version of this guide is: private address and NAT are going to be used.

It makes sense to mimic the IPv4 addresses, so the IPv6 addresses will be: fd00:0:0:8::/126 and fd00:0:0:88::/64 and fd00:0:0:48::/126. (These IPv6 addresses do match the IPv4 addresses: 0x88=136, 0x48=72.)

Additional early documentation

Document these choices, and also some values for variables named VMDirBas and VMGenNam: these values can be the same as a previously-created machine.

echo ${VMDirBas} ${VMGenNam}
Making script(s)

The VMLILNAM variable might still be pointing to the values from the older machine. That is actually a good thing just becuase it slightly simplifies the next step, which is setting the value of a variable named VMParDsk.

Setting VMParDsk

In case there was any prior work, let's make sure that VMParDsk is treated like a new variable.

unset ${VMParDsk}

In order to easily copy data from a previous virtual machine, some of the following examples use a custom variable named VMParDsk (for to reference the “parent/base image”/“backing file”).

One possible appraoch

If recent work was done on another virtual machine, that variable might be able to be set by running the following:

echo ${VMLILNAM}
export VMParDsk=${VMLILNAM}

Note: these sample directions provided may often be disasterous, perhaps particularly on a non-first machine. An incorrect value may lead to using the wrong/unintended data as a parent/base image. (Most certainly, that type of problem should be avoided.) Make sure to manually review the value of VMParDsk now. If that variable has a value set, then it must be pointing to the name of a parent image. If that is not the case, clear the current value (by running the following commands).

echo ${VMParDsk}
unset VMParDsk

Actually, the value of VMParDsk needs to be pointing to the “short name” of the computer that will be the parent machine. (This is the same value that was used for ${VMLILNAM} when the parent image was created.) If VMParDsk is not set to the appropriate value, go ahead and set an appropriate value.

Otherwise, simply set VMParDsk to the name of an old machine.

[ "X${VMParDsk}" = "X" ] && export VMParDsk=LittleNameOfOldSys

Many of the following lines will assume that something like this was done. For the following examples to work, the name of the computer system for the base image should be assigned the value of VMParDsk. Make sure it is right!

echo ${VMParDsk}

The VMLILNAM variable needs to be customized for the new machine. At this point, the ${VMLILNAM} needs to be set, to be named after the name of the new virtual machine. After the documentation is updated with a name for the new machine, run the following commands on the computer that runs the virtual machine software.

export VMLILNAM=newsys

To be abundantly clear, that was meant to be customized. The newsys is a customized name for the new computer. (If that wasn't handled properly, then repeat that command with a customized name.)

Avoiding disaster by being very careful

Check the values of the variables:

echo vmdirbas=${VMDirBas} gennam=${VMGenNam} parentDisk=${VMParDsk} newSys=${VMLILNAM}

Make absolutely sure that all of them are set to values that are correct for the new machine. (Having the ${VMParDsk} and/or ${VMLILNAM} variables set to point to the wrong machine, can be a relatively easy mistake to make. Also, such a mistake is often easy to overlook when quickly checked. (An incorrect value may be the name of a machine that has been worked on recently, so it may seem sensible if sufficient thought is not being put into this check.) However, the consequences can be pretty painful, so, seriously, be careful about this check.

The good news is that some things may remain simple. Having ${VMGenNam} be the same as recent/prior work may make perfect sense. Also, the value of ${VMDirBas} may match what has been used before, and that may make perfect sense and be both good and right.

However, the values of ${VMParDsk} and/or ${VMLILNAM} may be particularly prone to being set to wrong, and very damaging, values. Be careful that those variables have values which describe what is intended. The value of ${VMParDsk} needs to refer to the (older) “parent/base image”/“backing file”. The value of ${VMLILNAM} needs to point to the name of the desired (new) child/kid/snapshot image.

Copy over some (script) files.

mkdir -p ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstart
ls -l ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstart
cp ${VMDirBas}/execbin/${VMGenNam}/${VMParDsk}/sysstart/exc_${VMParDsk} ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstart/exc_${VMLILNAM}
mkdir -p ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/nicscr/
mkdir -p ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstop/
cp ${VMDirBas}/execbin/${VMGenNam}/${VMParDsk}/sysstop/off_${VMParDsk} ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstop/off_${VMLILNAM}

Note on the first couple of virtual machines: the last line might cause an error. If you hadn't bothered to create a proper shutdown script because the only virtual machine made was a base image, don't worry about it. After creating the first child image, a proper shutdown script should have been made. A logical spot for that script would be in the base image, so copy the shutdown script to the ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstop/ directory and then re-run that last cp command.

Handling scripts related to networking

(Side note: if there is a desire to review documentation related to creating the old scripts, the check out the “Enabling communication from the host machine”, including the possibility that it may have referenced other sections such as QEMU TAP guide.)

In the documentation for creating the base image, the NIC configuration started to be a bit unusual for that machine. Most machines may want a different NIC configuration. In most cases, the following will be beneficial:

ls -l ${VMDirBas}/execbin/${VMGenNam}/${VMParDsk}/sysstart/
echo The following may, intentionally, overwrite a file if applicable.
cp ${VMDirBas}/execbin/${VMGenNam}/${VMParDsk}/sysstart/exc_${VMParDsk}-before-NIC-cfg ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstart/exc_${VMLILNAM}
NIC Scripts

(This section is probably only needed for machines that will be using “-net tap,”. However, it is relatively harmless, so if in doubt, just go ahead and perform these steps.)

Make a spot where NIC scripts can go. (This is probably optional for most virtual machines, not including virtual machines that will be firewalls.)

mkdir -p ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/nicscr

If there are NIC scripts, copy those over as well.

cp ${VMDirBas}/execbin/${VMGenNam}/${VMParDsk}/nicscr/* ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/nicscr/.
Create new disks (for a “child” virtual machine)

Create new child hard drive images. This is covered by Making a QCOW(2) snapshot/child image. The following might work well (depending on what version of qemu-img is being used).

mkdir -p ${VMDirBas}/diskimgs/kiddisks/${VMGenNam}/${VMLILNAM}
qemu-img create -f qcow2 -o backing_file=${VMDirBas}/diskimgs/baseimgs/${VMGenNam}/${VMParDsk}/${VMParDsk}1.qc2 ${VMDirBas}/diskimgs/kiddisks/${VMGenNam}/${VMLILNAM}/${VMLILNAM}1.qc2
qemu-img info ${VMDirBas}/diskimgs/kiddisks/${VMGenNam}/${VMLILNAM}/${VMLILNAM}1.qc2

Of course, if two disks are used, then make sure that images for both disks exist. In this case, the second disk is so small that it will just be copied, so that the second disk does not require the ongoing presense of a parent image. (So, if the origianl disk image is ever modified, that won't break all the images that were copied from the original.)

cp -ip ${VMDirBas}/diskimgs/baseimgs/${VMGenNam}/${VMParDsk}/${VMParDsk}2.qc2 ${VMDirBas}/diskimgs/kiddisks/${VMGenNam}/${VMLILNAM}/${VMLILNAM}2.qc2
qemu-img info ${VMDirBas}/diskimgs/kiddisks/${VMGenNam}/${VMLILNAM}/${VMLILNAM}2.qc2
Documenting Data Drive Details

It is good to note where the hard drive is at. This may be most convenient to document while the value of ${VMParDsk} is still conveniently available, so go ahead and document that now.


However, that the values of those variables must be sufficiently documented for this example documentation to even possibly be considered decent. (Some people might argue that such documentation is not decent because the documentation looks cluttered with the variables expanded. To counter that arguement, documenting the variables may be nicer for functional reasons (like convenience from a Unix prompt) and to minimize the time of documentation. Documentation is meant to serve a need for information, and some people may benefit more by having information organized one way while other people may appreciate having information organized a different way. The precise balance between functionality and cosmetics is a standard that will not have universal agreement, so this guide will not dwell further on trying to discuss which style of these styles might be considered to be more “right”. Regardless of style preferences, incomplete/missing information is rather universally considered to be inferior and generally unacceptable.)

For a child image, it is good to note what parent image is used. (This can be figured out by using qemu info but that may be less convenient.) e.g.:, the documentation for a system may have a line that states:


Of course, that documentation is only possibly decent if the value of ${VMParDsk} is documented as well.

Also, for a child image, it is good to modify the documentation for the parent image, to note the child virtual machine's name and the hard drive image's name. This way, if there is ever a problem that leads to considering a change to the parent image, the decision can be made with consideration to the child image.

Update the scripts to reflect the new machine.
Main script
echo ${VISUAL}
${VISUAL} ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstart/exc_${VMLILNAM}
Critical settings

Perhaps the most critical setting to update will be the hard drive image: the new virtual machine (or any virtual machine, for that matter) should not be writing to the wrong hard disk image. If the sample scripts are used, then this problem is likely to be effectively prevented by taking care of by updating where the VMLILNAM variable gets set in the script file.

Especially: Update:

  • the virtual machine name variable: VMLILNAM
  • the virtual machine number (VMNUM)
Networking (configuration to perform on the computer running virtual machine software)

Also, while editing the text file, review the networking options, as those might frequently be different between an initial/test system and a more common style of “child” system. Follow one of these steps of instructions:

Recommended network settings for most types of virtual machines

This is good for additional virtual machines, when another virtual machine is already actively running and performing the “listen” service. (This is generally not going to be a good option for the very first child machine.)

If this style of networking configuration is being used, then use “-net socket,” as appropriate. For those who have been using the sample script files from this guide, this may be as easy as using the following steps:

Find the text that says:

#  The below option will connect to a server, and is a fairly easy way to get
#  full network connectivity with other virtual machines connected to the same
#  server. However, it is only useful after setting up an initial server.
#  This line is only effective if no other value was set earlier.
#  If such a server IS available, then feel free to uncomment the line.
#  The value of 43000 must match the server (which defaults to 43000).

# if the previous line is uncommented then the following options will be used
# instead of using any of the earlier options
[ ${CLIOPTVMFIRSTNIC}"X" = "X" ] && \
    export CLIOPTVMFIRSTNIC=" -net socket,vlan=1,connect= "

Note: The correct block needs to be chosen here. Make sure that this is the networking configuration block that references “-net socket”.

A little bit above the reference to “-net socket” is an “unset line that needs to be uncommented.

#  The below option will connect to a server, and is a fairly easy way to get
#  full network connectivity with other virtual machines connected to the same
#  server. However, it is only useful after setting up an initial server.
#  This line is only effective if no other value was set earlier.
#  If such a server IS available, then feel free to uncomment the line.
#  The value of 43000 must match the server (which defaults to 43000).

# if the previous line is uncommented then the following options will be used
# instead of using any of the earlier options
[ ${CLIOPTVMFIRSTNIC}"X" = "X" ] && \
    export CLIOPTVMFIRSTNIC=" -net socket,vlan=1,connect= "

Also, double-check that the VLAN's match. Look later in the text file for a line that says something like:

 -net nic,vlan=1,macaddr=52:54:00:12:${VMNUM}:01 \

Make sure that the VLAN number matches what is being used by the “-net socket,”...“connect” line earlier in the file. This should be a non-issue for most machines, if the copied initial script file has the preferred default. However, having a mismatch will likely completely break networking in a way that may not be super easy to immediately figure out, so performing the check is likely worthwhile.

Make sure that the desired “unset CLIOPTVMFIRSTNIC” line is the ONLY uncommented line that says “unset CLIOPTVMFIRSTNIC”. The easiest way to do this may be to edit the text editor and run:

grep -i "unset CLIOPTVMFIRSTNIC" ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstart/exc_${VMLILNAM} | grep -v ^\#

That should show only one result. (The last part of that command excluded comments. The “^” refers to the “start of a line in a text file”.)

Recommended network settings for an initial virtual machine (not counting the base virtual machine)

One machine needs to provide some different networking options. A firewall is probably a great choice for this.

Details, on an ideal setup, are described by: Qemu kid's networking: networking configuration. The recommended steps are to complete at least the sections titled “First NIC on the virtual machine” and “Add support for more virtual machines”. If time permits, completing the entire guide may be nice in the not-very-distant future.

After making those changes:

New Network Hardware Documentation

Any newly created NIC should be documented at some point. If MAC addresses are being documented, then right now may be the most sensible time to start documenting this NIC will be at this point, not later. Especially start documenting now if any new NIC on the virtual machine needs to use a reserved “tunnel”-style network interface on the computer running the virtual machine software.

Pointing to the right hard drive image

Also, while editing the text file, make sure that the path to the disk is correct. Specifically, if using the examples from this document, each (uncommented) reference to a hard drive image in a “baseimgs/” directory may need to change to a reference to a “kiddisks/” directory. (Do not bother modifying any references that say "baseimgs/" if the line starts with a comment character. There probably will be a couple of those before the uncommented lines that do need to be changed.)

(These steps might not be strictly necessary, but probably are desirable if these servers have been set up.) Update the DHCP server(s) for any desired reservations that should exist for this machine. (Perhaps additional documentation: OpenBSD FAQ on a DHCP server.) Update the DNS server(s) for any new records that this machine should have.

Additional files to edit before running the virtual machine
-nic tap,”-related script files

This does not need to be done if the system is only using network connection types other than “-nic tap,”. If there is at least one “-nic tap,” connection, then do take care of this.

If any files are referenced by the network configuration, then those files need to exist.

Creating files

The following might save a bit of time:

echo ${OLDPWD}
pushd .
cd ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/
[ ! -f nicscr/upif2 ] && [ -f nicscr/upif0 ] && cp -i nicscr/upif0 nicscr/upif2
[ ! -f nicscr/dnif2 ] && [ -f nicscr/dnif0 ] && cp -i nicscr/dnif0 nicscr/dnif2
cd ${OLDPWD}
echo ${OLDPWD}
popd .
ls -l ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/nicscr/

If that doesn't work, the files may need to be re-created. Directions on this are available Qemu TAP NIC script files.

Customizing the script files

For instance, to edit the NIC TAP script related to the newer network card shown by this guide:

echo ${VISUAL}
${VISUAL} ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/nicscr/upif2

Precise fine-tuning of the TAP NIC script files may be worthwhile to do after the virtual machine is running, so that results of commands can be quickly tested. The main reason to tinker with the files now is to make sure that they exist, which enables easy completion of the main script file that specifies what hardware exists on the the virtual machine.

However, for any changes that do get made, it is generally nice to make them correctly. Remember that this is the configuration file for the TAP devices that Qemu will use. Therefore, the reference to DESIPv4 should refer to IPv4 address of the TAP device (not the IPv4 address of the virtual machine's NIC).

The section on Qemu TAP NIC script files has details about the customiations that needed for the TAP NIC script files. (The referenced resource also contains information about downloading/creating the files. Simply skip those details if they are not necessary.) The one thing to add, though, is to make sure to adjust the value of SCRIPTNAME (which will probably be wrong for all files except for the first NIC). (A value to set SCRIPTNAME to might be $0 although that may look less pretty, cosmetically. So, set the value to the filename of whatever file is being modified.)

Note: Don't get your hopes up that all those NICs will work perfectly quite yet, particularly if the tunnel devices won't yet have appropriate IP addresses.

Variable space

Some files may be quickest to obtain/generate by simply copying them from another machine. By now (if not some time ago), any such files have probably already been copied.

unset VMParDsk

If other variables have somehow become unset, see: setting some initial variables to identify a script.

Starting the virtual machine

(This might be nice to do at a different command prompt, so that the command prompt used for other steps can continue to be used for other tasks. If using a new command prompt to start the virtual machine, make sure to set the required variables. If using a pre-existing command prompt, especially make sure that ${VMLILNAM} is pointing to the new machine.)

echo ${VMDirBas} ${VMGenNam} ${VMLILNAM}

(While the system is successfully booting, make sure that the following is documented:

  • the startup command (and any required values of environment variables) are documented.)
  • Notes related to Qemu: If the machine is using “-net socket,”...“connect”, then make a note of which virtual machine will be using the matching “-net socket,”...“listen” command line options. That way people know what virtual machine needs to be started first.

Start the machine so that the data on the virtual machine can be easily updated.

Log into the machine. Note that the documentation of the parent/base image may be handy to help do this.

Immediate credential updates

If the virtual machine was logged into by using a password, start by changing the password to something that is not the same as what was used by the parent/base image. (The concern is that if the security parent/base image has ever been compromised, possibly even just because a child image was compromised, then perhaps the child image could be successfully attacked rather easily.)

passwd $(whoami)

(If the program complains about “Permission denied”, this does not necessarily mean that sudo is required (although that would probably effectively workaround the cause of the problem). Instead, it typically means that the old password was rejected. (A standard user is expected to provide an old password before supplying a new password.)

Commentary about documenting the password change

With larger organizations, documenting the password may be a good idea so that no other administrator needs to deal with the lost password. (One exception might be if the system has some sort of a “lock” process that would let other administrators know to wait until this system was released. Another exception may be if the virtual machine is truely sealed from easy access, due to security permissions or netork design.)

Normally, any password update should also involve updating the documentation. If the computer is not likely to be used by other administrators, this may be an exception because the plan will be to install SSH keys and then the password may be disabled. However, if there is a desire to keep using a password (to more easily handle logging in from the console), then, by all means, do update documentation so that the password can be referenced later. (If the administrator gets sidetracked and the temporary password gets lost/forgotten, the administrator can either handle the lost password like a physical machine, or revert back to the hard drive image where there was a known password. If those options sound too problematic, well, just avoid the problem by documenting the temporary password. )

Once the password is changed, some methods to check who may be logged into the system can be performed.


Update the system host name:

Setting a value for the host name is recommended to be done early on, so that people can easily know what system is being used.

Host name visibility

For some computers, hopefully the system host name will show up in command prompts (thanks to /etc/profdef described earlier in this guide). So that can be a quick way to notice that the new host name is in effect.

For computers where administrators will likely be using a graphical interface, having the name on the graphical desktop background can be similarly useful. Speculation: For X Windows, perhaps BgInfo for X has ports for multiple platforms (including Microsoft Windows). It is based on BgInfo (for Microsoft Windows, by SysInternals and now distributed by Microsoft) may be a fairly easy option to utilize: perhaps see also related material: BgInfo on startup, BgInfo custom info).

Of course, if one of those fancy background-making programs does not do the trick, a slower solution may be to use graphics editing to manually make a background image, and then using other methods to set the background, perhaps such as xsetroot or xsri or IceWM's icewmbg. (Further details are not currently provided at this time.)

Perhaps also modify the “label”/name for the filesystem volume. If a “BSD disklabel”/“bsdlabel” is being used, then that may have a name that may be adjusted. The specifics on how to do this may depend on how data is being stored on the disk. See the adjusting/tuning properties of a filesystem for details (including the “BSD disklabel”/“bsdlabel” properties, even though a “BSD disklabel”/“bsdlabel” is a disk layout and not a filesystem volume type). These labels are often left unused, but could be helpful in rare cases like trying to identify what system a drive was meant for. (There may be other data on the drive that may be useful to determine what system the drive was meant for.) For instance, if using virtual machines and if using a second hard drive for configuration, this sort of label can be a way to help identify a disk image that is found. This process may be a quick task to perform on each drive. (However, some people may consider it to be usually fruitless, and so a waste of time.)

Checking for errors

There can be quite a few steps to create a base image, and sometimes errors may be found. Sometimes, documenting the errors may seem like a much easier task than fixing them (and affecting every subsequent child machine). Check the documentation for the base image to see if there are any pecularities that should be kept in mind whenever a child is created.

Search the documentation in the base image for a section labelled “Errors” or “Problems”, etc.

On a related note: if there are any apparent problems (or desired changes) with the “parent/base image”/“backing file”, keep those noted. The topic will be visited in the section called “Consider Parent Hard Drive Image Quality”.

Networking: making it functional on the child machine

Getting the network operational may be a high priority in order to allow SSH keys to be transmitted to this system. (This does not necessarily mean full routing to the public Internet: communication with just one subnet can generally be enough to get those SSH keys installed, which is what is needed to satisfy the immediate security focus.)

IP addresses need to be set up on both the virtual machine and the “closest” piece of networking equipment (which will be virtual networking equipment):

  • If the virtual machine is communicating with a “tunnel” adapter (on the computer system that runs virtual machine software), then the “tunnel” adapter (on the computer system that runs virtual machine software) needs to have an IP address. This is the case for a Qemu virtual machine that gets its main Internet connection by using “-net tap,” command line parameters.
  • If the virtual machine is going to communicate to the Internet primarily through a Qemu “-net socket,”...“-connect” type connection, then an IP address needs to be set up in the “networking stack” (generally a part of the “operating system”) on another computer that has virtual hardware using same “-net socket,IP address and TCP port number.
Overview/obervation: Existing requirement of having IP addresses in the same subnet

Furthermore, these IP addresses need to be in the same subnet. What that basically means is that the first part of the IP addresses need to match. For IPv6 prefix length of /64 or a smaller subnet (meaning that a larger “prefix length” number is being used), the hexadecimal digits before the first three colons of the fully expanded IPv6 addresses must match. (Numbers after an optional double-colon generally do not need to match.) For IPv4 addresses with a /24 or larger “prefix length”, which corresponds to a subnet mask of at least, this ends up meaning that at least the first three octets must match. There is an exact calculatable portion of the addresses that actually need to match, and that portion depends on the size of the subnet. For further details, learn about subnets/subnetting.

The desired IP should be able to be looked up in the documentation related to this new system. If that documentation does not yet mention IP addresses, then choose which IP addresses will be used (if needed: if that choice hasn't been made yet), and then get those IP addresses documented.

Some possible resources:

Making a new administrator
  • This section involves changing user data. Backing up the user database is a standard recommendation. (In practice, there may be little need to back anything up yet if the hard drive image is a child image, since few changes will have occurred yet. However, backing up data before changing the data is just a generally good practice, so it is being mentioned here.)
  • Ideally, the base image provides an administrator account that is designed to be minimally used and then thrown away. Create a new account that will be used longer term. See: adding a user.
  • Make sure that user can successfully escalate privileges. This is often just a matter of making sure the user is in the proper group (“wheel” in Unix): see putting user in group. (Doing this should allow the user to be able to be running software as a superuser.)
  • Also make sure the user is in any required group so that the user can use remote access. (The concept of such a group is covered by Hardening and enabling a remote access program. The default group name, shown in this documentation, is “_okssh”. Once the group name has been identified, see: putting user in group.)
Controlling remote access
Customizing the TCP port number

Moving off of the IANA standard may slow down some attackers' attempts to use a program such as SSH. (This may have been done already, when configuring the base image.)

Customizing the port number for SSH
grep -i Port /etc/ssh/sshd_config
cpytobak /etc/ssh/sshd_config
echo ${VISUAL}
sudo ${VISUAL} /etc/ssh/sshd_config

Find any existing uncommented reference, if any. Then, make sure there is just one uncommented reference, and that it specifies the desired port number.

Port 22

(That entire line is unnecessary unless using a customized TCP port number, meaning any TCP port number other than 22.)

If any changes are made, send a SIGHUP to sshd (or just restart the software), so that the configuration file gets reloaded. The SIGHUP method should be faster and less disruptive: see Reloading the OpenSSH configuration file.

(This can be sensible to do before installing the SSH keys, in case an SSH connection ends up getting used to help efficiently install the SSH keys.)

SSH keys
System keys
Locating keys

The system keys may be viewed by running:

ls -l /etc/ssh/

Actually, that will probably show more files than just the system keys. That can be narrowed down a little...

Compatability note

If the files are not found there, then the path may need to be adjusted. (That should work with OpenSSH. However, users of OpenSSH-p, the “portable” version meant for use with operating systems other than OpenBSD, may find that the creator of the software distribution has moved where OpenSSH-p stores its files.) In that case, the following might help to locate the files:

sudo $SHELL -c "eval find / -iname \"ssh_host_*key*\""

or, even simpler , and which will work from most locations (although perhaps not in the are case if there are no matching files in the current directory?)...

sudo find / -iname "ssh_host_*key*"

Handle the keys as described in one one of the following sub-sections. (In the following example command lines, if the files are located in a different location, adjust the following examples appropriately.)

If this is a brand new system

While on the topic of SSH keys, update the system SSH keys if that wasn't done automatically. (This is referring to the /etc/ssh/ssh_host_* files that are essentially provided when incoming SSH connections are made.)

sudo $SHELL -c "eval ls -l /etc/ssh/ssh_host_*key*"

Make sure those files show new filetimes. (If not, OpenSSH supports an option to create those keys: “ssh-keygen -A ”. This is believed to be a newer option: generating SSH keys has details that might be helpful if using older software.)

(Really, this whole process probably does not need to be done if the base image was made ideally, but checking for problems on a first virtual machine is an especially good idea. For additional child images, checking this might be less critical except in cases where the SSH server is not operating as expected, as problems will probably be revealed when SSH does not work as expected.)

If this system is replacing an older system

Impersonating the old system may just be the most convenient approach, so that clients do not need to update their records regarding what SSH key to expect. So, copy the system-wide SSH key(s) used by the old system.

sudo $SHELL -c "eval ls -l /etc/ssh/ssh_host_*key*"

There is a section available about transferring files over a network. Beyond that, specific directions for that are not being provided here.)

Keys for logging into the new virtual machine

If additional SSH keys are needed through this process, not currently available for administrators to identify themselves with, see: generating key files.

Install key for administrator

Install the proper keys so that any authorized administrators can log in. If a new administrator account was just created, then using that account is recommended. Even more recommended is being careful that the key gets installed to the account of that administrator (not to a temporary account that is about to be deleted).

Tips for how to install the key
Communiation details: getting the key transferred
If SSH key mismatches

This does not usually occur.

If a message is shown about someone trying to do something nasty, this probably means that the SSH keys were changed but either the IP address did not change, or the DNS host name did not change. In either case, this should be handled to *correctly* make the message go away. See: dealing with a(n unauthorized) SSH key change.

This involves getting the public key onto the virtual machine. If the key is being stored in OpenSSH format, then this key is generally stored in a *.pub file. There are a couple of ways to get the key onto the virtual machine:

  • One approach may be to use remote access, and then just figure out how to paste the contents. (This is probably the method that requires the least amount of initial learning, and may often be the quickest method.)

    In theory, it might seem just as simple to paste the characters into the virtual machine software, rather than using a remote access client. There is one advantage to going through the steps of initiating a remote access connection: Using remote access has been found to successfully avoid having keystrokes being eaten (although, of course, whether or not this actually works better could vary, depending on exactly which method of remote access is being used.)

    The key will eventually need to be placed into ~/.ssh/authorized_keys file, so people looking for an easy solution may open up a text editor to just start editing a text file with that name. People seeking greater speed may use text redirection (possibly using cat, and possibly using tee). If redirecting, it is generally safer to be using a method that appends (to the end of the file), rather than overwriting.

    sudo mkdir ~/.ssh
    cat | tee -a ~/.ssh/authorized_keys

    after pasting the key, press Enter, and then the EOF character (generally Ctrl-D), and then check on the results:

    echo ${VISUAL}
    ${VISUAL} ~/.ssh/authorized_keys

    If this was done as a different user, know that permissions will need to be checked. (The topic of permissions is covered in the upcoming section about “File details”.)

  • file transferring solutions (like SFTP which is enabled by default with newer versions of OpenSSH, although Potential for term confusion does exist... A similar option that is even more likely to work, but recognized as inferior, is SCP. That is also supported by the OpenSSH server.

    Tip: file transferring may be done using a file transfer client on the machine with the file to be sent, or with the file transfer client running on the machine that will be receiving the file.)

Just make sure that the pasting doesn't somehow overflow a buffer and effectively eating up some of the characters. Overflowing the buffer has been witnessed on multiple occasions when pasting directly into the Qemu program: the problem has been known to be avoided by pasting into SSH software that connects to the virtual machine. If in doubt, and if only a single key is being used, one quick thing to check is the file size. The resulting file should probably grow by (about?) 588 bytes, or more, when successfully pasting the entire contents of a valid key. On the virtual machine:

ls -l ~/.ssh/authorized_keys
File details

The public key needs to go into the user's ~/.ssh/authorized_keys file, which might not pre-exist. Just place the contents of the public key file into a single line of that file. (To restrict what command gets run by that key, see an example in the section on “using an SSH key to run a shutdown command”)


There may also be some requirements for the Unix-style permissions that are applied to certain files.

[#sshdukyp]: Permissions related to user keys on the computer running the SSH server

On the server, the software may want to see that

The OpenBSD manual page for OpenSSH (ssh): section called “FILES” says about ~/.ssh/authorized_keys file, “This file is not highly sensitive, but the recommended permissions are read/write for the user, and not accessible by others.” However, OpenBSD's manual page for sshd: section called “FILES” seems to have stricter requirements: unless the server has an option called StrictModes set to no, then the ~/.ssh/authorized_keys file has no write access access permitted to anyone other than the user. (Both “other”, and even also “group”, must not have write access.) Similar restrictions should also exist for ~/.ssh/ and ~/.

This is also discussed by OpenSSH FAQ 3.14: “I copied my public key to authorized_keys but public-key authentication still doesn't work.” also documents the issue, and provides some solutions (which might assume that the person is logged into the computer using the account that is having troubles initiating a remote access connection).

Applying the required settings

Following are some details on how to fix this issue.

If the person performing this task is logged in as the user who will be owning the keys:

export SSHdUSRN=$(whoami)

Otherwise, just customize the username as needed:

export SSHdUSRN=username

Adjust ownerships (if necessary). (This might be needed if the .ssh/ directory or the .ssh/authorized_keys file were made by a user other than the user who needs to own the files.)

sudo chown ${SSHdUSRN}:${SSHdUSRN} $(eval echo ~${SSHdUSRN})/ $(eval echo ~${SSHdUSRN})/.ssh/
sudo $SHELL -c "chown ${SSHdUSRN}:${SSHdUSRN} $(eval echo ~${SSHdUSRN})/.ssh/authorized_keys*"

Adjust permissions: authorized key file permissions, and information from the “Follow up work” section to check details, would indicate to run something like the following:

chmod go-w $(eval echo ~${SSHdUSRN})/ $(eval echo ~${SSHdUSRN})/.ssh/
$SHELL -c "chmod go-w $(eval echo ~${SSHdUSRN})/.ssh/authorized_keys*"

(The reason for running “$SHELL -c ” is just because the wildcards might be handled a bit easier if sudo is needed, which is only likely to be the case if the steps are being performed from a user account other than the owner of the files.)

Finally, once all of the changes have been performed, run the following command that performs some insignificant clean-up:

unset SSHdUSRN
Client requirements

The OpenSSH client may have some requirements for private keys: no other users should have any permissions at all to the files. This is noted by OpenBSD manual page for OpenSSH (ssh): section called “FILES” as it describes ~/.ssh/id* files (but not the ~/.ssh/id*.pub files).

Install key for shutdown script

While mucking around with keys, update modern SSH keys for being able to shut off the system. (By “update”, this means to use file transfering, or copy-and-paste, to get the key onto this new system. By “modern”, this simply means keys that are being actively used, rather than potentially revoked keys.) To find the name of the user, perhaps see: “ ls -l /home/_* ”. The public key file (which is a single line) needs to go to that user's .ssh/authorized_keys file as described by powering down a system: allow a user to log in using a specific key.

The following example commands might be helpful: make sure to customize the username!

cat | sudo -n tee -a ~username/.ssh/authorized_keys

after pasting the key, press Enter, and then the EOF character (generally Ctrl-D), and then check on the results:

echo ${VISUAL}
sudo ${VISUAL} ~username/.ssh/authorized_keys

Ideally, the key should have gone to the end of a pre-existing line. The key is not supposed to be at the start of the line (because that would not be following the directions specified by powering down a system: allow a user to log in using a specific key).

Hardening: Further lockdown
  • Make sure that the new administrator's password is sufficiently documented.
  • Back up the user database
  • Restrict how administrators may log in.

    Overview on the process of restricting user account(s)

    Actually, the idea of fully disabling one or more of these accounts (perhaps especially the one named “root”) might give some administrators some discomfort, concerned about breaking things or making disaster recovery a larger challenge. (It seems quite likely that disabling the root account might work fine for some systems, although other operating systems might not treat that quite as nicely.) At the very least, a good practice is likely to make sure the password is different from what is stored in the base image, and that no SSH keys were inherited from the base image. (For instance, when checking the account named “root”, make sure that ~root/.ssh/authorized_keys file does not contain any keys from the base image).

    Use the desired (new) administrator account (for reasons discussed by Overview: Why the recommended approach is using a new account to disable the “superusers”) to modify any other administrator accounts that were inherited from the base image. Either:

    • Disable the account (see disable an account),
    • or Delete the account (delete an account),
    • or protect the account (by changing its password: “ passwd username ” (or even just “ passwd ”) if logged in as the user, or “ sudo passwd username ”)

    Unless the account is being deleted, make sure to handle each potential entry point. Check that each of the following has been addressed:


    There are reasons why to use vipw and an uncomfortable user interface is not a good reason to avoid the software, particularly since vipw honors ${EDITOR}. For directions on how to disable this style of login, see: Disabling Unix system user accounts by modifying login password/credential information

    SSH keys
    Check ~username/.ssh/authorized_keys (customized to include the actual username in that path), if that file exists. If that file does not exist (and perhaps the directory does not exist), that is normal for many accounts, and so there is nothing to do.
    The file named /etc/skey/username (customized for the username). That file may not exist, and even the /etc/skey/ directory might not exist. If the file does not exist, there is nothing to do.

    Make sure to leave a working administrator account (such as the new one that was just created). While doing that, disable any unnecessary administrator accounts. Here is a list that may help identify such accounts:

    • The administrator account that came from the base image
    • The account named “root”
    • Any other account that was part of the “wheel” group (from the base image)
    • Any account that is in a list of important accounts that are documented in the notes related to the base image
    • If there are a small number of accounts, perhaps review all accounts that are not restricted from logging in. The list of such accounts may be seen by using:
      grep -v ":/sbin/nologin" /etc/passwd

    Note: It is best to disable root's standard login password, and make sure that the account does not have any keys (~root/.ssh/authorized_keys or /etc/skey/root, both of which exist in subdirectories that might not exist on other systems that do not have the files). Leaving the login shell set to a valid shell can be useful if using sudo -i to use configuration files that are in root's subdirectory.


(This is some older text, likely covering much of what was just discussed in the previous section.)

It is best that running systems are not using the same passwords as the base images. This way, if any base image is compromised (perhaps due to a compromise occuring on a child image), the damage is less prone to opening up more back doors to a bunch of other running computers.

Ideally, change all credentials (keys and/or passwords) that both:

  • relies on information that is stored on the parent/base image,
  • and also permits administrators to log into the system.

This certainly needs to be done for ALL (local) administrator accounts. Check the documentation related to the base image. This probably is not necessary for network-based accounts, because presumably those accounts are based on customizations performed when creating or maintaining the network, and so those accounts are not relying on credentials that are being stored in the parent/base image.

For a temporary/throwaway account, one way to effectively handle this may even be to disable the account. For instance, if the account to log into the base system was named “baseboss”, then make a new administrator account. (Make sure the new administrator account can operate with escalated priviledges, and can perform any other essential functions like being able to log in remotely.) Then, (ideally: log in remotely, and) use the new administrator account to disable the old administrator account.

Preferred method to make changes

This section involves changing user data. Backing up the user database is a standard recommendation. (In practice, there may be little need to back anything up yet if the hard drive image is a child image, since few changes will have occurred yet. However, backing up data before changing the data is just a generally good practice, so it is being mentioned here.)

As noted by reasons to use vipw, there is one program recommended to use for any changes. Run that program:

echo ${EDITOR}
sudo vipw
SSH key for system shutdown

Since an SSH key was just recently installed to support remote shutdown, while that action was done recently (and might not be forgotten about yet), make sure that there is an easy way to shut down the system remotely. If the base image has this mostly set up already, then installing an SSH key might be the only remaining action to get that working.

Keep in mind that the key used for a system shutdown might not be the same SSH key for logging in as a system administrator. (There is not a super compelling reason to use different keys if the only people who will shut down the computer are trusted system administrators who are authorized to make other changes to the system. However, having a key that is restricted to system shutdown may allow the key to be used by someone else who could be given access to perform a clean system shutdown without needing to provide access to be able to make all kinds of other changes.)

Actually, another step that may be needed is to get networking fully functional, including routing, so that a system that has the private key can easily communicate to the computer that needs to be shut down. So, this might not be super easy to test immediately. Still, installing the key now may be a bit easier (since another key was just installed... the process may be less challenging to remember how to do. If there is a pre-existing SSH connection that will be helpful, then installing this key might even be less work to do immediately rather than later.)

Additional network improvements
Most machines on an established network

For most systems on a network, no changes should need to be made on the virtual machine because this should be handled using automatic addressing. However, if an unchanging address is desired, the automatic addressing servers may need to be adjusted to recognize the virtual machine.

For IPv4, this means noting the MAC address and then updating the DHCP/IPv4 server to create a reservation based on that MAC address.

(Information on IPv6 is still forthcoming, but likely involves obtaining the DHCPv6 unique identifier. DHCPv6 software may refer to this as a “DUID”. (There are multiple meanings of “DUID”. This is one of them.)

First machines

Some machines might not be able to use the automatic addressing service. If automatic addressing is a service that will be provided by a virtual machine, then the machine providing automatic addressing services may typically need some hard-coded IP addressing information. If other machines provide other services, the firewall may also be a good candidate of being a machine that is set up prior to automatic addressing.

Here are some resources for helping to set up networking for these machines:


Now that the system has had the most essential hardening steps done, networking may be a great next priority. If the virtual machine cannot yet communicate with the public Internet, fix that (assuming that such communication is desired).

One approach may be to follow the steps at: walkthrough for making a virtual machine: adding IP routes. That resolves some common situations.

Here are some additional troubleshooting tidbits: IP routing/troubleshooting.


Making network configuration happen on each boot.

Shutdown script

If this hasn't yet been done, then install the SSH key for shutting down the system.

Testing may have been delayed until network routing was functional, but there should be no reason for further delay.

Since the effectiveness of that action may not have been tested yet, test a script on another system (like the computer that runs the virtual machine software) to make sure that it can successfully shut down the virtual machine cleanly. (This may be sensible to do early.)

Once the key is set up, the presense of an existing script file may be seen with:

echo ${VMDirBas} ${VMGenNam} ${VMLILNAM}
ls -l ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstop/off_${VMLILNAM}
echo ${VISUAL}
[ -f ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstop/off_${VMLILNAM} ] && ${VISUAL} ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstop/off_${VMLILNAM}

If the file just doesn't exist at all yet, exit the text editor (if the computer is in the text editor) and run the commands shown in the section on Using the ability to remotely shut down. Then go into a text editor to edit the file, customizing the needed inforamtion (especially the IP address, but also the username and the TCP port number, all of which are on the line that runs ssh).

If this requires getting more networking changes to be made, then go ahead and make those changes so that this works well.

Once the script is set up, then testing it may not be a very bad idea.

Reboot, login, and check

This may not be strictly required, but running some tests at this point seems quite likely to be a worthwhile idea. Check to see how well software operates post-reboot.

sudo reboot
  • Is networking fully functional (including connecting to the public Internet?)
  • Is the system time correct? (This is checked after networking, just because networking might be helpful in fixing this.)
  • Is system documentation up to date? (Some items/topics might be particularly likely to need documentation updates at this time. Those may include: any recent changes to networking, logging in as an administrator, or how to shut down the system.)
Protecting script files

If the script files are operating as designed, make them read-only. (This might help if, for example, VMLILNAM gets improperly set when creating a new virtual machine. If an older system's script files are read-only, they may be less likely to be accidentally overwritten.)

chmod -R a-w ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}
ls -l -R ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}
Other ideas

(This is meant to be a temporary suggestion, until this gets reviewed and content between different resources are sufficiently merged.) Perhaps there are more ideas at: tutorial on setting up an installed operating system.

[#vmprntql]: Consider Parent Hard Drive Image Quality

If this the first child machine that was made from a base image, then this topic is particularly worth considering.

If so, then how has the experience been? Are there any portions of the process that did not go as smoothly as ideal? If so, there may be three possible approaches:

  • Completely scrap all child images that have been made so far, and adjust the parent image. Note that this may take a while longer than expected: the parent image's permissions may need to be altered, and SSH keys may need to deleted from the base image, and a computer running an SSH client may also need to delete cached information related to old keys. Creating copies of all related hard drive images (both for the parent image and the child image), before adjusting the parent image at all (including even booting up with it) may be worthwhile. Note that the parent image might not be able to conveniently boot with the child image, if there are IP conflicts or TCP port conflicts from “-net socket,”...“listen” or MAC address conflicts.

    This approach can be worthwhile for those who are comfortable with the process, including file handling. For those who want things simple, this approach may involve more risks than what this approach is usually worth.

  • Keep the problems, but make them easier to handle:
    • Document the problems in the documentation of the base image. Hopefully people can then see that every time a new child is made. (Near the logon credentials may be a good spot for this type of documentation.)

      If the changes to the “child”/“snapshot” images are on a system where changes tend to be in easily identified files (which describes Unix, but not Microsoft Windows which stores changes in a “registry”), then future operating system upgrades may be relatively easy. An option may be to just put up with the problems in the short term, and the long term solution may be to just build a new network using an upgraded version of the platform in the near future. That may be a very feasible idea on a small network running nothing more than DHCP/IPv4 and DNS, while the same idea would be a ridiculous proposition when being proposed for other, more complex networks where migrations may be much more challenging.

    • If the problem can be fixed by changing a file, perhaps this can be resolved by fixing the file and placing the updated file somewhere under /srv/hddcfg/extract/. (or some similar option). See “Inserting custom commands early in the process” to see the startup script and find a way to put the updated file where it should go.

      In that case, the problem may still be worth documenting, so that it may be kept in mind in case anyone wishes to re-create the hard drive image for the second drive. However, it may also be documented as a resolved issue. That way, people don't need to keep checking if they need to re-fix the problem every time a new child image gets created.

The first option may often be nicer once complete, but may not be reasonably feasible/economical in some cases. (Actually... in many cases.)

Reporting hardware

By this point, adjustments in the hardware (like the number of NICs and hard drives) is probably completed. See: Hardware reporting. (Although a child machine is likely to have identical hardware to other child machines and probably also the parent machine, a new (virtual) computer did just get assembled. So, submitting a report seems sensible for tracking.)

[#vmkidfic]: File Integrity checking (on a “child”/“snapshot” image)

This may be a great time to check what has been changed. This point of the process is really a good time to make a file integrity checker database file. Such a database file would reflects this point of the process, after performing some standard system setup tasks, but before doing lots of activity that is customized to this specific virtual machine.

Anticipated results

This may alert on SSH keys being updated. That's fine. A key reason for running this update is so that people can review the changes made already, and choose how to respond. Since new SSH keys were expected, that change may be acceptable. This also creates a new database, so that any future changes (which might not be expected) will make less sense, because people cannot just blame the issue/event (like updated SSH keys) on prior steps taken (like creating a new child image).

Also, this may alert on changes related to creating a new administrator account. Once again, if some known changes have occurred, then that is fine.

For such details, the benefit to running the file integrity check is not to generate a report showing such unneeded details. Instead, the advantage to running the file integrity check process is simply to update the database. The steps taken so far have mostly been some broadly applicable steps that make sense for most (virtual) machines. By updating and rotating these databases as a routine early step on each virtual machine, future reports will likely have more focus on just the customizations that are more unique to just the single specific virtual machine. Then, if these changes are reported again when the file integrity checks get run in the future, people can think about whether that report makes sense. If it does not, then an investigation may be performed to see if there has been some unauthorized changes.

First recommended step

As a generally useful routine, rotate the database files. (Doing this might have no effect. If it does have an effect, the most likely effect is to cause data to be effectively preserved rather than being overwritten.)

[#aidedbsv]: making a log and storing for future use

compare and update AIDE databases. This will create a report that may be viewed (although there are a couple of other steps recommended before spending time on such a report).

As usual, after comparing and updating AIDE databases, following up is recommended proceed to rotate the database files after comparing and making an updated database. So, do that.

Also, making another landmark copy of a database may be sensible to do now. The following sample command was meant to do be done *AFTER* the rotation after the the database is updated.

[ "X${AIDBNMPT}" = "X" ] && export AIDBNMPT="early-setup"
echo ${AIDBNMPT}
sudo cp -ip $AIDEDBFL/aide.db $AIDEDBFL/aide/olddbs/aide-archived-"$(hostname -s)-${AIDBNMPT}"-$(date +%F%H%M%S%Z%a).db

This uses a variable to start storing some information which just becomes part of the filename. Absolutely feel free to customize that variable: doing so is highly recommended.

(In the future, this saved log file can be used for comparisons, by rotating the databases and copying the saved database file and other steps, as shown by all of the steps of the File integrity checking child/snapshot images section (which these directions, right here, are a small part of).)

That concludes the maintenance to do to the file integrity database files. Feel free to view the latest AIDE report that was created.

Installing software

If more software needs to be installed, then install it.

Document the name of all software that gets added.

Optional: backing up progress made so far

Presuming that the software installation seemed like it worked fairly well, backing up the data right now may be a fairly good idea. Note that this idea is being mentioned as something to do right after installing the software, but even before configuring the software. Making a backup copy of the machine may even be something that is better to do before configuring the software that just got installed. That way, the backup may be less likely to contain details that might be less wanted (like additional passwords that may need to be entered and stored, or data that changes over time and which, in the future, will be unwanted, old, outdated data). This may also allow for an easier time to recover if the configuration process breaks things badly. Also, this might be useful if there is ever a desire for comparing the system right after a fresh installation to the system after more customizations have been applied.

Coming up, there will soon be another recommendation to back up the system. To re-cap: sometimes making yet another backup now, earlier, may be useful. (Sometimes it might seem to not offer any real advantages, potentially not really doing anything except for taking up time and disk space.) If in doubt, and if resources (time and disk space) are available, just go ahead and make this.

[ "X${VMMorNam}" = "X" ] && export VMMorNam=software-just-installed
echo ${VMMorNam}

After setting that variable to reflect the current state of the disk image, then proceed with the instructions to archive a child image.

(After following the instructions to archive a child image, proceed past the instructions for archiving a child image.)

[#vmkidsav]: Archiving a child image

It may be appropriate to proceed with backing up the current state, particularly if the software takes a longer time to install than having the data be part of what gets restored from a backup (if there is ever a need to restore from backup). To proceed with this, make sure the virtual machine is shut down:

Shutting down the virtual machine

(Make sure this command is being run the virtual machine.)

sudo halt -p

... and then confirm that the virtual machine software has completely stopped running this specific virtual machine. This may involve virtual machine management software saying that the machine is stopped, or noticing an inability to see anything on the local console. For Qemu machines, if the Qemu monitor was known to be working before, then an inability to connect to the Qemu monitor can be a clear indication that the virtual machine software has exited.

... and then compress all of the disk images used, and store a copy of those compressed images as archived copies of the current state of the machine when it first became ready to really be put into operation.

Perhaps See:

Compressing an image

Some earlier directions discuss how to compress an image. There are just a couple of variations to be aware of. First, it is good to customize the name of the disk image that will be created. This command may to take care of some of that customization.

echo ${VMMorNam}
[ "X${VMMorNam}" = "X" ] && export VMMorNam=some-unique-name
echo ${VMMorNam}

Another change is that many of the examples of disk handling commands were made in mind for base images. If child images are stored at another location, those examples will not work without some changes being made. The following may help deal with that issue:

echo ${VMAgeDir}
unset VMAgeDir
[ "X${VMAgeDir}" = "X" ] && export VMAgeDir="kiddisks"
echo ${VMAgeDir}


Consider whether any changes have been made to the second hard drive. If so, then backing up that hard drive, as well, may be an appropriate task to perform.

(The VMMorNam is going to keep its value, so that it may be used in the next set of directions, which is to re-child the child drive.)

Re-childing a child drive

These instructions are assuming that the following variable is already set, which helps to give a unique name for the copy.

echo ${VMMorNam}

Note: the following directinos are just for the first disk on a virtual machine. If there is a desire to do this to the second disk of a virtual machine, specify a value of “2” instead of “1” for the following variable.

export VMDskNum=1

Move the file:

ls -l ${VMDirBas}/diskimgs/${VMAgeDir}/${VMGenNam}/${VMLILNAM}/
mv ${VMDirBas}/diskimgs/${VMAgeDir}/${VMGenNam}/${VMLILNAM}/${VMLILNAM}${VMDskNum}.qc2 ${VMDirBas}/diskimgs/${VMAgeDir}/${VMGenNam}/${VMLILNAM}/${VMLILNAM}${VMDskNum}-uncompressed-archived-${VMMorNam}.qc2
ls -l ${VMDirBas}/diskimgs/${VMAgeDir}/${VMGenNam}/${VMLILNAM}/
Optional, often unneeded and undesirable steps:

However, sometimes the best results do come from following these steps.

If the uncompressed copy of the image is actually smaller than the compressed copy (because it contains a compressed copy of all of the data in the parent image), and if the parent image is likely to be reliably available, then the uncompressed copy may be the preferred copy. In that case, mark the compressed copy as being unlikely to be needed.

mv ${VMDirBas}/diskimgs/${VMAgeDir}/${VMGenNam}/${VMLILNAM}/${VMLILNAM}${VMDskNum}-${VMMorNam}.qc2 ${VMDirBas}/diskimgs/${VMAgeDir}/${VMGenNam}/${VMLILNAM}/${VMLILNAM}${VMDskNum}-large-compressed-file-containing-parent-data.qc2

(The step just performed effectively renames the file. The reason to rename the file, instead of just deleting it outright, is to make sure that things operate as intended. For the moment, it is effectively a backup copy.) The idea is to delete the file later, after confirming that the other images are working as confirmed. If there are substantial disk space constraints, and confidence that the other files will work acceptably, then there may be no super compelling reason to keep the file.)

Unnecessary step...
(Details have been commented out, and will be fully removed from here after some further verification. Please proceed with the following commands.)

The following change will cause the uncompressed copy to be treated like the preferred copy of the data. This method works by adjusting the pointer from the compressed file to the uncompressed file.

echo ${VMMorNam}
export VMMorNam="uncompressed-archived-${VMMorNam}"
echo ${VMMorNam}

Make a new child image:

chmod a-w ${VMDirBas}/diskimgs/${VMAgeDir}/${VMGenNam}/${VMLILNAM}/${VMLILNAM}${VMDskNum}-${VMMorNam}.qc2
ls -l ${VMDirBas}/diskimgs/${VMAgeDir}/${VMGenNam}/${VMLILNAM}/
qemu-img create -f qcow2 -o backing_file=${VMDirBas}/diskimgs/${VMAgeDir}/${VMGenNam}/${VMLILNAM}/${VMLILNAM}${VMDskNum}-${VMMorNam}.qc2 ${VMDirBas}/diskimgs/${VMAgeDir}/${VMGenNam}/${VMLILNAM}/${VMLILNAM}${VMDskNum}.qc2
qemu-img info ${VMDirBas}/diskimgs/${VMAgeDir}/${VMGenNam}/${VMLILNAM}/${VMLILNAM}${VMDskNum}.qc2
ls -l ${VMDirBas}/diskimgs/${VMAgeDir}/${VMGenNam}/${VMLILNAM}/

(This is conceptually similar to, but is DIFFERENT from changing disk images (“re-childing” a drive).)

unset VMDskNum
unset VMAgeDir
unset VMMorNam

Then, if the virtual machine has been stopped (which it has been, if all of the described tasks have been getting performed), log into the virtual machine (which means there is a need to start the virtual machine). (The login may be done over a remote access connection.)

Configuring software

Back up each file that gets changed, if possible.

Document the name of each file that gets changed, if possible.

Post-setup Tasks
Tasks to perform on the virtual machine
File Integrity Check again
Determining whether this is useful

It certainly seems conceivable that some people may follow this walkthrough for basic guidance, but may have skipped some of the steps such as software customization, and perhaps also software installation. If that has been done, then making another File Integrity Check update may be fairly pointless. Furthermore, it may be inappropriate to create a database called *-post-customize* yet. In such cases, this step may be sensible to put off until the software installation and configuration have actually been performed.

If there have been changes from the need to configure software, then this point of the process may again be a sensible time to run the file integrity check. (If all needed software was installed, and then a file integrity check was performed, and then there was no software configuration at all performed, then there really is not any need to run another file integrity check at this point, because nothing substantial has changed since the last time that was done.)

At this point, initial configuration has been largely completed, and so a file integrity report based on the latest database would describe the results of the early authorized configuration tasks that took place, including installing software and configuring that software. Later reports will focus more on changes that are made after the initial system configuration. Also, if a new database is made now, and is then compared to the database from the base image, then that may make a summary of what files have been changed from the base image. That can be useful with the (unrelated, upcoming) task of moving customized data to a second hard drive.

Steps to take

To make a long term copy of this database, make sure to customize the filename of any newly created database, so that it won't overwrite any pre-existing files and so that the database can be rather easily identified in the future. For example:

set AIDBNMPT="post-customize"

Additional directions are not re-provided here because they would be so redundant with the recent step, File Integrity checking (on a “child”/“snapshot” image). Just re-run the commands from the section containing those specific directions.

Comparing to a specific database/Checking what has been changed

It may be nice to review all of the changes since the creation of the base image. (More specifically, the comparison is made with the file integrity data was created very late in the process of creating the base image.)

To do that, first, rotate the database files once, to make sure nothing gets lost with the next step. (Actually, a second rotation may help to make sure that all files have been sufficiently saved, but that second rotation is about to be performed in an upcoming step.)

Then, the variables related to rotation are assumed to be already set, so proceed to run:

sudo cp -ip $AIDEDBFL/aide/olddbs/aide-archived-basesys*.db $AIDEDBFL/

(Note: this example is specifically if wanting to compare the current state of the machine to the image that was made towards the end of creating the base image. If a different database is desired to be used as the “old” data, then specify that as the first filename instead of what this example shows.)

Now, proceed to rotate the database files another time.

The remaining steps are identical to the steps in the section called “making a log and storing for future use”. (Simply follow those instructions.)

Having custom files on second hard drive

This guide doesn't yet have the full details fleshed out (at the time of this writing), but the idea is this: by storing files on the second hard drive, then is there anything on the first hard drive that is needed?

[#ysepcstm]: Why this is such an awesome thing

For instance, consider a computer that was set up just to be a DHCP/IPv4 server and a DNS server. If the DHCP/IPv4 configuration file is on a second hard drive, and the DNS server's configuration files (including zone data) is on the second hard drive, then the only data on the first hard drive are the DHCP/IPv4 leases, which many people consider to be unimportant (in that losing that file would not be any terrible tragedy). What this means is that the contents of the system's primary hard drive, which may be a child image, may be very painless to recover from. (In fact, that hard drive image could even be erased and re-created every time the virtual machine is off and then started.)

By backing up the parent image(s), and then backing up only the very small second hard drives, each system may have really no need to be backing up the primary child drive. Now, there will be exceptions, and those exceptions may be dreadfully important. (For instance, an E-Mail server's data should be retained.)

Patching could be much simpler. I once worked with an organization that would apply patches to each supported server, and reboot the server so that the patches would take effect. Now, consider this alternative: An early child image gets made out of a main parent drive. That early child image is copied, as needed, to provide the functionality for the virtual machines that use that child image. Then, operating system patches are released. A copy of the early child image is made, and that copy is used to create a new child image that contains the upgraded opreating system. Each virtual machine then gets updated by performing the following steps: make a copy of the new child image, point the virtual machine to use the new child image when it is restarted, and restart the virtual machine.

In fact, even an upgrade to an entirely new version of an operating system could be just about as simple. Create a new parent image, install the new operating system to the new image, configure the new parent image to do cool things like supporting the second hard drive. Then, create child images of the new base drive. When the virtual machines reboot and use the new base drive, the configuration files on the second hard drives will automatically configure the software on the first hard drive. What this means in a nutshell is that upgrading the operating system on multiple servers is as simple as installing and configuring the operating system on one server, plus minor amounts of work for each server (like changing the reference so that it uses the newest hard drive).

In theory, even switching the operating system used by all of the machines on the network could even go as smoothly. For instance, switching from Linux to BSD, or vice versa. Just install the new operating system onto a new parent image, prepare the parent image nicely, and run the scripts found on the second hard drive. Files like /etc/dhcpd.conf might be able to just copy right on over, functioning on the new operating system as well as the old operating system. In practice, there are probably going to be a lot of minor hang-ups because of file paths being different, but these problems would very often be fairly quick (and easy) to solve, if the problems do even exist at all.

Now, here is another idea: if the base image contains no data which is specific to a single organization, then the base image may be able to be shared with multiple organizations (and even be shared publicly, if the base image is using only freely distributable software). For an IT support company that supports multiple other companies, this means that the large bulk of data would be data that could even be safely shared between different organizations, because it would have no confidential data that is specific to the organization. Then, each client would then just have a small amount of data that is customized and stored on the second hard drives. Almost all of the data needed to entirely re-creating the DHCP and DNS servers could come from a pre-made optical disc that is not specific to just one company. Customizing the servers for the company may require using a small amount of customized data stored on the virtual machine's second hard drive image, which might be quite tiny (like perhaps 300KB or so?). The only disk space that the company would need to be backing up is that second hard drive image, so backup requirements (like the time taken to back up) could be significantly reduced compared to needing to regularly make customized backups that contain the entire operating system.

Surely things could be improved upon even further: automation could be used so that the scripts that start virtual machines could default to always using the latest hard drive images. Actually, the dream scenario is that rebooting wouldn't be needed to perform updates. Windows 9x required reboots for more things than when Windows XP was using the “Windows Installer” software, although Linux has been even more impressive by allowing even kernel updates without requiring reboots (using KSplice, or the kexec function). (This is according to StackExchange forum post. Wikipedia's article on KSplice indicates that Oracle bought out KSplice, and ended free support for RHEL.)

Wikipedia's article on “Dynamic Software Updating” (quoting Wikipedia's article on “Dynamic Software Updating”: last update from the year 2012 which then wasn't updated for at least nine months later) states, “DSU is not currently widely used in industry.” ... “Ksplice is currently the most widely known DSU system.”

Still, until such modularity and other such improvements becomes built-in functionality that is even more commonplace, the modularity of this sort of hard drive layout method offers an improvement upon earlier/past experiences.

This sort of hard drive layout might also minimize the amount of data that may need to be backed up, and minimize the time needed to restore. (By copying just one big primary hard drive image once, multiple virtual machines can be restored quickly after that.)

Directions/Some thing(s) to keep in mind
Read-Only status

The second hard drive is mounted read-only by default, when following the steps on this guide. So it will need to have its mount options changed (which may be done by entirely re-mounting it, if needed). After making changes, the safest procedure will be to re-enable the read-only status (which will happen when the computer reboots, but may be done even before that).

Tasks to perform on the computer that is running the virtual machine software
Final Archive

If the machine is quite functional, and if there has been additional work that is worth saving (like spending quite a bit of time applying customized configurations to the machine), then making a(nother) backup may be appropriate at this time. If backups (or filenames containing the backups) typically have a user-specified name, then decide what name to use, and be careful (when following directions) to make sure to use the customized name when appropriate.

Note, however, that this might not be extremely appropriate if the machine contains a bunch of customized data at this point. For instance, if there is an E-Mail server and the mailboxes of end users is already on the machine, then the server might not currently be in quite as good of a state for making a prestine permanent/long-term archive. If a user deletes a single E-Mail message the next day, and then many months later an archived copy of the server gets restored, then the user may wonder why the deleted E-Mail returned from apparent non-existence. This is just one potential example of how old data can be haunting.

If an archive is desired, which generally will be a good idea if an archive has not been made recently, then follow these steps. First, set a variable so the filename of the created archive will reflect the current state of the virtual machine:

echo ${VMMorNam}
unset VMMorNam
[ "X${VMMorNam}" = "X" ] && export VMMorNam=initial-setup-completed
[ "X${VMMorNam}" = "X" ] && export VMMorNam=post-initial-installation
echo ${VMMorNam}

Then, see: archiving a child image (which provides directions/references to compress the disk image, unset a variable, and then to re-child).

Modify the shutdown process

Whenever the computer running virtual machine software is being cleanly shut down, it should do something to safely handle the virtual machines that it is running. Make sure that the latest virtual machine will get handled by the computer that runs the virtual machine software.

For a simple setup, see: Handling the shutdown of the computer running the virtual machines

If the number of virtual machines starts to get so big that manually adjusting this becomes painful, then there may be an option to simply run all of the shutdown scripts. Shells may often have a “for” command that may be helpful. This should probably be tested before being placed in a script that runs automatically. The following command might work:

cd ${VMDirBas}/execbin/kiddisks
for x in $(find . -mindepth 1 -type d | xargs) ; do echo ${x}/sysstop/off_${x} ; done

Like the results? Remove the word echo.

Modify the system's startup process

Note that this isn't necessarily as easy as it may seem. Starting some types of programs too early may cause them to not get a normal terminal, and to quit.

A precise detailed guide on handling this is not yet available here, but problems running programs during startup discusses this problem (in the section called “Programs terminated at end of startup”).

Checking for unneeded data
ls -l ${VMDirBas}/diskimgs/${VMAgeDir}/${VMGenNam}/${VMLILNAM}/${VMLILNAM}*-large-*.qc2

If such a file exists, and the file has not been getting used, and the machine is still operating properly, then the file may be taking up disk space while not providing any real substantial benefit. If appropriate, see details on how to remove files.

Notes for the next virtual machine

If the first virtual machine using a “child”/“snapshot” image was a firewall, know that this machine required more time setting up the NIC(s) than other machines. The basic setup of other virtual machines will likely be completed even faster. (Of course, the entire process may be much slower, depending on what the machine is designed to do and factors like third party software that may need to be installed, configured, and tested.)


There, that actually wraps up this walkthrough. From here, there are some various additional guides to help show some other things:


Create additional virtual machines (if desired). To do this, choose a name for a new system, and follow the other Tasks for additional virtual machines that may use child images.

setting up an installed operating system

This guide to setting up an installed operating system contains several early steps. Many of these steps were actually copied into this guide, so there's a bit of redundancy. (In future versions of these guides, many of the steps are expected to eventually be moved back, after being sufficiently updated.)

Many of the steps that weren't copied into the guide may be considered less crucial.

Creating a firewall

This is probably a very logical next step to the process.

Unfortunately, no guide for this is being heavily recommended at this time. Some information had been written at Firewall Implementations, but that was some time ago and the information should be reviewed again before being recommended. It is possible that the guide was not very user friendly (or perhaps it is fine).

A recommended guide is likely to be getting referenced here fairly soon.

Building a network

Make new “child”/“snapshot” virtual machines as appropriate, and check out building a network. That guide was actually written with an initial stronger focus on using Microsoft Windows Server (2008), although will eventually be expanded to cover other operating systems. At this time, it might or might not yet be quite suitable for OpenBSD.

This covers setting up servers such as automatic addressing (e.g. DHCP) and name resolution (DNS).

Trouble handling

Here are some topics that, at the time of this writing, haven't been heavily covered by this guide.

  • Is Anti-malware software installed? If so, great. Does it have scheduled scans running? What happens when trouble actually occurs?
  • Is backup software running? If so, great. Does the backup software run regularly? If there is a problem with the backups, will that be noticed?
  • What happens when a hard drive dies in a RAID array? (Possibilities: a loud tone, or beeping, that annoys people. Or, perhaps worse, no alerting whatsoever, so nobody knows of the problem.)
  • If there are critical error messages, do they get ignored, reviewed on occasion, or will an alert be immediately made? (Possible resource: logs (including Microsoft Windows Event Logs), Problem Messages.
  • Is hardware testing performed? (Here are some possible resources.)

    Running these, and other tests, may be useful. However, the best setup will probably be to have them run routinely, and to have problems be integrated to a suitable reporting system that alerts people to troubles.

    Some hardware testing may involve a performance hit. On large networks, there may be a desire to schedule such performance hits so that they happen on different machines at different times, instead of bogging down the entire network all at once. For that matter, large networks may be frequently found in large organizations that frequently may have other (additional) desires, like investing a bit of effort into scheduling the performance hits during non-peak times.

Unfortunately, at the time of this writing, this guide does not have references to full documentation on how to implement these tasks.

Additional enhancements
  • Is there any sort of “check in” process that computers do regularly, so that a failure to check in will cause an alert so somebody may quickly notice the offline machine?
  • Does file integrity checking get run automatically? Can the logs be parsed automatically, to alert whenever alarming or questionable behavior is noticed?
  • Are logs sent to any sort of centralized log server? (Having logs available can be useful for dealing with unexpected downtime, such as if a hard drive fails and so a machine's logs become unavailable. Also, if there is a security incident on a computer, and the logs on that computer get trampered with, then there can be benefit to having unaltered copies of the logs on a remote system. The key to that is to make sure that the client can only add new log information, and not remove information that has previously been logged.)
    Handling logging

    There are many possible things that may be done, including sending logging to a remote server.

    For now, the following simple task(s) are provided for consideration:


    In a nutshell, this ends up causing some more detailed logs.

    (This may or may not be a great thing to do. This task is not currently being recommended, but since it does seem so simple to do, it is being provided as a step to consider.)

    Reviewing OpenBSD's manual page for the acct file and a 1994 manual page for the acct, related to Linux show that the information gets logged when a program exits. (So if there is a terribly malicious program that destroys the system, logging won't occur until after the program performs its damage and perhaps disrupts the ability for the logging to occur.)

    For systems using a configuration file, there may be an entry related to this. For instance, the following example shows how accounting may be turned on with OpenBSD:

    cpytobak /etc/rc.conf.local
    echo accounting=YES | sudo -n tee -a /etc/rc.conf.local
    sudo accton

    See: logging user activity, OpenBSD 4.0 to 4.1 upgrade guide: “Operational changes” section.

    Although the latest OpenBSD manual page for accton (as of at least OpenBSD 5.3) says the manual page is new, the same comment was made by OpenBSD 2.2 manual page for accton.

    See also: OpenBSD manual page for lastcomm

  • Is there any sort of sandboxing? Any manipulation of Internet traffic may be controversial, particularly shunned by people who generally oppose censorship. (This page is not attempting to make any hard stance on that particular topic, but does briefly note that people can definitely be annoyed by sandboxing.) For example, if a computer looks up the DNS name of and then sends traffic to port 123 of a returned IP address, redirecting such traffic to a private server may help reduce unnecessary load on the free public servers.
  • Can performance improvements be made? As one idea: do outgoing web connections get routed through a transparent local web proxy? (Doing so would make traffic less effecient, but the hope would be that repeat viewing may actually speed up connections.) This can be done for HTTP traffic. (Hopefully use of the HTTP can notice when a file was last updated, so that dynamically updated pages will get re-loaded when necessary.) The use of HTTPS proxy may require that the client has a certificate trusting the content by the HTTPS proxy, and some people may even consider the approach to be a MITM-style “attack” on generally expected privacy.

This represents the end of the less generalized “walkthrough”. (Recall that, at this time, this web page consists of multiple versions of the guide. If the first version was followed up to this point, then that version has been completed.)

The following heading represents the start of the initial public version of this “guide”.


Earlier guide: Introductory Material



See what to expect from this guide, including discussing what results should be achieved and what sort of timeframe to expect, in the Introduction to TOOGAM's “Make a Virtual Machine” tutorial.

[#mkavmreq]: Requirements

There is a somewhat lengthy “requirements” section for the guide to making a virtual machine. Much of the reading is likely non-critical. Some people may wish to invest some time, right at the start of going through the guide, in checking out how smooth or bumpy the experience is likely to be. This type of behavior is recommended whenever starting out a time consuming project, especially when creating results intended for deployment in a commercial production environment.

Those who aren't worried about determining feasibility ahead of time, or who are more interested in an entertaining thrill of quick results rather than playing things cautiously, may want to venture on forward. Those who are in any sort of a time crunch may also want to skip the requirements section (and may wish to forego reading through this tutorial, in favor of just applying knowledge from other, more focused, sections of the website.)

The “requirements” section is intentionally exhaustive. Those willing (or, in an organized environment, those who are required) to take the plunge may proceed to view the “requirements” section for the guide to making a virtual machine.

That completes this “requirements” section.

About using this tutorial
[#hopbkspd]: Getting through the material efficiently (by hopping back, for speed)

Please accept some hints about how to read this tutorial. This tutorial was designed to be followed in a specific pattern, in order to minimize the amount of time needed to get through all the needed material.

Perhaps a fault of this guide is spending too much time, early on, focusing on the expected overall time savings. There is a clear reason that was done: to simply drill home a specific point: There really is expected to be time savings compared to learning this material searching on your own. Some significant effort really was put into place to try to accomplish that goal, even though it is acknowledged that such time savings may not be quite as apparent during the first quarter or so of the guide. So, please, have faith, and start by investing a bit of time reading these recommendations. The following reading recommendations are being provided because they are expected to pay off, by saving your time.

This tutorial is part of the ][Cyber Pillar][ web site, and makes frequent references to material found elsewhere on the site. If the goal is to complete this tutorial in a streamlined fashion, then the following method is the recommended way to proceed through this tutorial: Follow the hyperlinks to the other sections on the site. With each hyperlink, complete reading just the section described by the hyperlink (including any sub-sections). Then, make sure to read no further on that page.

This may sound simple, but may be more difficult than it sounds. Taking the time to fully understand this guideline may help complete this tutorial much more quickly. After the hyperlinked section, the website may have lots of additional information that is related to what is just read. However, reading about lots of similar and related material is not going to result in completing this guide most quickly. So, after reading the referenced text assigned by this tutorial, head back to the tutorial (in order to, most quickly, complete more of the guide). Yes, there may be lots of additional details about the topic that was just covered. The reason to not keep reading further about a completed topic is just that there are also other topics to move onto.

This guide is meant to specifically cover necessary information to accomplish the specific task of creating a virtual machine, and to focus on the steps needed to accomplish this task. This differs from some of the more generalized guides, like general guide for creating a virtual machine, which is designed to be a bit more comprehensive. That simply means that the generalized guides may try to cover more details about a broader topic, while this guide is a bit more specific about the steps needed to achieve functionality. Therefore, the recommended course of action is to keep following the individual steps pointed to from this guide. Restricting the reading to what is referenced by this guide is expected to ultimately end up taking less overall time to have multiple technologies be successfully set up (configured) and implemented (functional).

It is sincerely believed that sticking to the guide will likely result in a more streamlined process, providing learning of many fundamental aspects much more quickly than the alternative method of branching off to explore lots of related material.

One strong indicator that a section has been completed is if the CSS styling shows the end of a section. For an example of how this CSS styling is rendered, see the “tutorial: time to go back” section. If there is a border surrounding the sides of text, and later on some text on the same web page is not surrounded by that border, it may be that the end of the border has been reached (as passed).

There may be other ways to know when the tutorial would suggest that the desired “section” is completed. Check out the description in the hyperlink that refers to that section. There are a few things to help identify where the “sections” start and end. One clue is the indentation levels. In the many cases where an HTML “definion list” is being used, another clue to the end of a section is the color coding (which uncoincidentally happens to correspond to the indentation levels). The third clue is that hyperlink anchors (which start with a “left square bracket” and then an anchor/number/pound/hash sign, and end with a “right square bracket”) is often found at the start of a new section. If you see one of those visible hyperlink anchors, or if you notice your eyes moving sideways because text is becoming substantially less indented, consider whether the title of the upcoming text is related to the current goal. If not, back out and make more progress on the current goal.

Some people may prefer to read in a less controlled fashion. There is nothing particularly wrong with gaining extra knowledge, but simply realize that doing so may take longer. Also, there may be the very real possibility that reading so freely may result in causing a reader to get into more advanced concepts, without having some required background knowledge. (Perhaps that is a possibility anyway, but the possibility is substantially increased in likelihood with more free-form reading.) This tutorial is meant to be a controlled guide to help cover information in a logical order so that topics may be understood as quickly as what can be expected (when considering the length of the reading).

How much this advice is followed may be dependent on the individual reader/follower.

[#adyexmpl]: A note about addresses reserved, and used, for documentation

This website may use the following for examples:

IPv6 addresses from within 2001:0db8::/32 (as documented by RFC 3849). Another address range which may be used for examples is the IPv4 addresses from 192.0.2/24 address range. (That IPv4 range is called “TEST-NET” in RFC 3330, and is called “TEST-NET-1” by RFC 5737 and RFC 5735, and is called “TEST” by RFC 1166). Additional IPv4 address ranges that may be used for examples are 198.51.100/24 (called“TEST-NET-2” in RFC 5737 and RFC 5735), and 203.0.113/24 (called“TEST-NET-3” in RFC 5737 and RFC 5735).

All of those address ranges are all meant to be used for documentation purposes (and or tests and/or research), and are not meant to be actually used when trying to get things to work. Such traffic should be blocked from working on the Internet. BCP32, also known as RFC 2606 (and not likely to have any need to be updated), reserves,, and (in section 3) as well as four TLDs (in section 2) which are .example and .test and .invalid and .localhost. Of course, the items with the word “example” may be used in documentation.

Even if these things appear in examples, do not use those in scenarios where the goal is for network traffic to operate normally. The documented examples might even be blocked by some hardware, so the documented examples may actually not work even when proper usage of the examples may result in things working just perfectly.

By making sure to always customize any examples prior to deployment, these names and address ranges can be restricted to being used only in examples. A benefit is that if any problems are encounted because example configurations are accidentally being used without the proper customizations, the problem may be quickly identified by someone who sees these uncustomized examples in deployed configurations. Therefore, in pursuit of this possible benefit, the recommended practice is to avoid any actual deployed/production use of these names and address ranges, even for private use (even if such private usage might, techmnically, function).

Dangerous stuff comes early

It is perhaps unfortunate that certain potentially harmful activities form a fundamental foundation upon which many other activities may rely. Therefore, dangerous activities may come early. Early activities may contain all of the following charcteristics:

  • It is critical that some early activities be done correctly, or else serious problems (such as security breaches and/or the loss of data integrity) may occur. Furthermore, it is very possible that the consequences of these problems may not be very easily noticeable until a later time, possibly a date far after the problems have become serious (and maybe even so late that fixing them easily is not feasible).
  • Taking care of these activities involves using software that can do things like editing a partition (using a traditional MBR partition layout). This sort of software has a high degree of access to be able to “foul up”/break quite a large amount of data (very quickly).
  • Since these activities are building foundations, they really need to be done first, before many other steps.
  • Many people don't find them to be particularly fun or entertaining, and (especially historically) the software used to perform these activities have often had some of the least user-friendly interfaces.

Examples of these activities are setting up file systems correctly (especially making sure that they don't overlap), and creating and safeguarding credentials (such as passwords and files that serve as “keys”) that may provide a high amount of access. Realize that some of the most challenging things typically come first.

(That said, some things have had interface improvements, and perhaps even automation improvements, making it easier to do some things right and less likely that some things will be done wrong. A key example is disk layout procedures that may use a graphical interface, or even provide some intelligent automation to help decide how data may be laid out. So, that problem has seen improvement compared to what was more commonplace during, say, the mid-1990's.)

Congratulations to those who have dutifully completed this section to prepare for the plunge. Now, are you brave enough for what comes next?



[#mknusevm]: Creating/using a virtual machine : Initial actions
Get IPv6 support

If this machine is going to be accessing the IPv6 Internet, but if the available Internet connection is only using IPv4, then know that there is some documentation about getting IPv6 support. Getting IPv6 working over IPv4 may be a worthwhile project on its own, and may be a project worth investigating before proceeding with creating a network of virtual machines. If that is something desirable to pursue first, see the specific section on getting IPv6 support when only IPv4 is available, and/or the more general guide about using IPv6.


Creating some initial documentation will save some time, even for tasks in the short term. Start by making some Pre-VM documentation.

[#mkvrtmch]: Creating a virtual machine
Overview of creating a virtual machine

It is recognized, and hereby acknowledged, that there may be some back-and-forth being done by this tutorial.

Many of the following steps will involve checking out information from a single referenced source. As each step is provided, please check out the referenced material, but then keep returning to this guide after completing each small set of steps. Eventually the benefit from doing so should be worth the effort. (See Time-saving navigational advice for the tutorials, hopping back for speed.)

(There is no immediate need to check out that reference right now, as the relevant pieces of that content will be getting referenced very shortly. The source is the Virtualization section's page about creating a virtual machine.)

Prepare the host environment

Restricting one's self to the documented operating systems and virtual machine software which is documented may help make sure that the experience goes smooth while following this guide.

Preparing the host environment involves installing the virtual machine software (if such software hasn't been pre-installed).

Follow the steps for making sure the host environment is sufficiently set up. Details are in Virtualization guide: Information about preparing the host environment. (That section, or material referenced in that section, should cover some initial steps such as installing an operating system and making sure the newly installed operating system is secured.)

Creating the virtual machine within the host environment
[#whnwvmds]: Overview about when to make disk images
Reading recommendation

Note: This is an overview section. Like many of the other sections entitled “overview”, this attempts to appease the thorough who want details, at the cost of containing a lot more information than what is minimally necessary. The main thing to know is that “now”, at this point in the guide, is a good time to make images. (If you are less curious, in more of a time pinch, and not following a structured class that wants all this material read, move onto the next section.)

The simple answer

Plan to make disk images before making the rest of the virtual machine.

In some cases, this specific approach might not be required, and other approaches may even be preferred by some people. That's fine. This approach, however, should generally function well with a wide variety of software. So, this approach is what this guide is recommending.

So, when an upcoming section refers to the time to make disk images, proceed at this point in the guide.

More extensive overview analysis

(The text of this overview does not have any instructions that need to be followed, and is simply being provided for those who are curious about why this guide is taking the approach that it is. Don't worry too much on dwelling on this part if anything is unclear, or if there is question about whether there is enough time to complete more necessary steps.)

The best (easiest, most recommended) time to create a disk image may vary based on the virtual machine software being used. The most popular, preferred method of creating disk images in one piece of virtualization/emulation software might be one specific approach, such as a graphical interface that is presented during creation of a virtual machine. That same approach might even be completely unavailable using other software. Some options, like creating images during or after the creation of the rest of the virtual machine, may not be supported as easily in some software (compared to other virtual machine software).

Virtual machine software will typically allow pre-existing images to be used. Therefore, the most straight-forward generalized approach for a guide to take, is to recommend creating the virtual machine disks first. This approach isn't strictly necessary in all cases, especially if another approaches, like creating hard drive images first, seems to be problematic. Some people may be familiar with, or learn, another approach that works with some software. They may consider such alternative options nicer, possibly due to being fewer steps overall.

For example, a software interface for creating a virtual machine (configuration) may, as just one of multiple steps, provide a quick and easily accessible interface (such as a clickable GUI button) that assists with creating one or more image files. For some software, that might be the easiest method. However, in the case of some other software, such a method might not work at all. A reason that method might not work could be if the software expects a hard drive image to pre-exist when the virtual machine is created.

To keep things working in many scenarios, this guide is not generally recommending approaches other than making the hard drive images first. Results of other approaches may vary based on factors like what software is being used, and what individual choices may be made. However, it is hereby acknowledged that other methods may be just as successful, and that some people may consider them nicer.

To summarize, making disk images first may be the easiest method (depending on factors like what software is being used, and what interface best suits the needs being performed). Also, in the worst likely scenario, the approach of making disk images first approach will usually work out okay, and will probably not be substantially more difficult than any other options. Therefore, this generalized guide is taking the approach of recommending that disk images get created first.

[#mkvmdsim]: Creating disk image(s) for a virtual machine

When the time to make a new disk image has arrived, proceed. (If a specific time has not yet been selected, now is probably a good time.)

One key initial step is to determine what image format will be most desirable. This guide does not provide a single strong recommendation, as there are various intelligent decisions that may be made. For some information about how well a disk image format is covered by the virtual machine software, see the documentation about the virtual machine software. (For example, if Qemu is the virtual machine software, check the documentation for the Qemu program to see if there are details about supported image formats.) Other documentation providing details that may be relevant to this decision might include: choosing a file format for a hard drive image and/or the subsection about formats for virtual disk images.

The desirable size for a virtual machine's new hard drive should already be determined (from the step of Virtualization: Initial items to decide/document when creating a virtual machine). (If that determination has not yet been made, make that determination now. And, then, document the determination.)

Create a “parent/base image”/“backing file” and images of bootable media as noted by the section on creating disk images for the emulator. (Or, for slightly more information, see making disk images for the virtual machine, which refers to the other section.)

For simple demonstrations, a dynamically sized image makes good sense to use. Also, as a space-saving measure, using child images that share a base image can allow multiple virtual machines while taking relatively miniscule amounts of space (e.g. between 20 and 45MB, rather than a few hundred per machine). For some situations, this sort of space saving can be considered very useful. In other situations, fanatical pursuits over speed may be given a higher priority over efficient minimization of disk space, and these these space-saving approaches may be scoffed at due to costs in terms of maximum throughput. This guide may likely favor the former approach, in part because speed costs can often be offset over time by using hardware that is faster, and in part because, from a purely software perspective, saving the disk space may simply the more interesting approach to work with (and may be a bit more educational). For those who would scoff at this approach: feel free to use whatever flexibility is afforded to make differing decisions.

At some time, the files should be placed in the sensible location where it was previously decided that disk images will need to be stored. Most image files will happily be usable in any location. However, disk formats that involve multiple files, including child/snapshot images that are based on a “parent/base image”/“backing file”, may have one file that refers to the location of another file. Beware of such dependencies, sufficiently testing every file if such a file is being moved. If things break when a file is moved, move the file back and/or determine what was wrong.

One thing that may help reduce such problems is to be careful, when creating an image, to make sure the image ends up being stored in the same location that the image is expected to remain when the disk image is later being actively used.

Adjust the examples from the section on creating disk images (or section on making disk images for the virtual machine) so that the created image is the desired size, or modify documentation as needed so that the documentation does match the size created by the virtual machine.

Getting other disc images
Now may be a convenient time to download any other disc images that are downloadable, and/or locating any physical media that may be needed. (Or, that may be able to be put off... slightly. But keep this requirement in mind, because it may be needed very soon.)
Making a virtual machine configuration

Then, create the “virtual machine” configuration. This might be done from within an interface (perhaps a GUI) for the “virtual machine software”, or by editing a text file outside of the virtual machine software. Third party software may also provide some options.

[#twknewvm]: Tweaking the virtual machine

It is about time to start focusing on some things like getting networking up and operational. There is more that is also worth deciding.

Networking may not have been sufficiently by this guide so far. Be patient. It is understood that networking may be needed for things like driver support and perhaps even operating system installation. So, details are coming very soon. First, though, take care of some other critical items that may be quicker to knock out.
Disk space and layout
Overview: Decisions to (re-)consider

If a virtual hard drive was recognized by the virtual machine, then presumably that means the software correctly found a hard drive image, so that means a hard drive image was successfully created. That sounds positive. However, how good was the decision about how big to make each hard drive partition? If such decisions were hurried and rushed, then now, just before the operating system is fully installed, may be the last relatively convenient time to make changes in such decisions. (So, fix those things now.)

Recommendation for temporary data

In a situation where a machine may have a plentiful amount of hard drives, such as a virtual machine where extra hard drives cost nothing, it may make sense to have swap/page the virtual memory to a hard drive that is dedicated to storing temporary data. (It is also a good idea to have a swap partition on the main hard drive, so that the system can painlessly start up without absolutely needing either another hard drive or re-partitioning. However, perhaps that swap partition may be unused (unmounted in Unix, and even just left unformatted in Microsoft Windows.) By dedicating a hard drive to just the purpose of this “swap” data, the drive dedicated to temporary data may not need to be backed up. (If the hard drive is a virtual drive, it might even be routinely destroyed without negative consequence.) The drive may be easily (intentionally, desirably) skipped during routine data backup processes (which may reduce data backup size, data backup time, usage (wear and tear) of disk storage devices, and perhaps network bandwidth).

In addition to storing swap data, other temporary data may be appropriate to put on such a drive. For instance, Unix systems may want to mount the /tmp/ directory to such a “disposable” hard drive.

Other virtual hardware decisions

Does the virtual machine have enough RAM? Are there choices, that still should be made, about what video circuitry it may use? Will it be desirable to have a working sound card? Is the virtual machine configured to use all of the desired implementations for each of these questions?

Making changes now, before the operating system, might allow the operating system to detect, and install drivers for, the hardware that will actually be used. Also, making such changes to a (virtual) machine may require rebooting the machine, which may or may not be quite so convenient down the road.

In general, for configuration options that can easily be altered after the operationg system is installed, the goal at this point isn't to fine tune the operating system's configuration. However, sizing partitions might not be done as easily(/safely?) after the operating system is installed, so take what time is needed to do that as desired.

Automatically starting the virtual machine

At some point, there may be a desire to have the virtual machine start up automatically when the host operating system is started, and cleanly shut down when the host operating system shuts down. At least in Unix, the auto-start part maybe a bit more difficult than initially expected. This topic is not really covered further by this tutorial, but it is covered by the multiple virtual machines tutorial. (The related section of the “multiple virtual machines” tutorial might currently just refer to the section about system startup.) This tutorial will not go into that in further detail. (The assumption is that the virtual machine may be manually started and stopped until after the completion of this tutorial.) So, plan to put that off until the follow-up tutorial is viewed (or, if desired, skip around that view that tutorial before completing this one).

[#brkifok]: Using the virtual machine

Generally there is a point or two during the operating system installation where installation takes some time: The first that may exist when creating/formatting a file system (which may go fast or not, depending on factors such as what kind of disk check occurs and if unused space on the new file system is left with pre-existing “garbage” data or whether it is emptied). The second potential point of waiting, likely to occur, is when the operating system installation process takes some time to copy/decompress/download files and place them on the new file system.

So, during these waiting processes, the time may be usefully spent by creating a detailed plan on how the network addressing will work long term. There are some decisions to be made, and making them may take some time.

Another possibility, which may be seriously worth consideration, is to take a break. Standing up and stretching a useful activity. Not only that, but there is wisdom in regularly determining, in light of potential time contraints, whether to continue at this time. After all, getting an operating system half-way installed, and then needing to quit because a college's computer lab closes, is just not nearly as good of a stopping point. If the machine is largely working well, this may be a good stopping point to consider taking a break.

If installing an operating system from a CD, or if networking seems to be working well enough to initiate a network installation, then go ahead and start installing the operating system since that will presumably take some time. (If networking is not working well enough to download the operating system, either delay installing the operating system (which will take longer overall), or skip ahead to the section about configuring networking in virtual machines.)

[#vmnetwk]: Implementing networking
[#plnetadr]: Planning out networking (for testing to occur very soon)

For those with quite a bit of network addressing experience, check out the “better ways of network addressing” section. Beyond that, the rest of this material is for those who would like details about how to assign network addresses, including subnets.

Appropriate scope for creating a test network

Planning that is elaborate, suitable for a whole network filled with multiple services, may eventually be desired. In the mean time, if networking hasn't yet been successfully implemented, go with the simple route.

The recommended goal for now is to set up some simple networking that fully tests the network hardware and lower parts of the network stack. There are a few benefits to doing this testing:

  • Confirming this functionality may provide some immediate satisfaction (as visible progress is seen), and re-assure that additional plans involving networking will be successful. (Having that assurance an be comforting when spending time making more elaborate network designs/plans.)
    • Getting the higher level networking to function is typically not something that has problems that are caused by the virtual machine software. The choice of virtual machine software, and NIC configuration settings of that software, generally don't cause problems with the higher level protocols.
  • If this lower level networking is not functioning, that will prevent many other popular tasks. Knowing about that problem sooner rather than later may have a number of benefits:
    • Perhaps effort can be spent early to fix the problem. This way, the problem is resolved earlier, and then working network functionality may be available earlier.
    • There may be work-arounds possible, such as changing some choices in software or, perhaps (depending on the task), figuring out a way where the task may be done without needing network access. With either of those scenarios, knowing about the problem earlier may be nicer than learning about it later.

A later section describes making choices to more cleanly design a more elaborate network of multiple machines. Meanwhile, having things tested nice and early can be... pleasant.

Choosing subnet information
Knowing some basics

Be familiar with how to determine which network route is determined (by using a network mask). If that isn't yet understood, check out the few paragraph summary from routing section: section about routing for local subnets, and/or other content in the “Basic routing” portion of the section about routing. (The referenced tutorial is admittedly brief; hopefully it is clear enough.)

[#newadrwy]: Better addressing methods

Prepare to (re-)learn regarding which subnets to choose. People who have years of experience successfully subnetting with IPv4 addresses may often use network addresses sequentially and may naturally (acting according to the nature of such experts) minimize subnet sizes. They may not employ some novel better approaches simply because of unfamiliarity. Learn why some ideas from RFC 3531 (or for IPv4, RFC 1219) have reasons provided for why that method is more beneficial than the common method of simple sequential counting. To follow that recommendation even for old hats at Internet networking, simply proceed to see Network Addressing Plans/Methods section before determining which subnets to use.

Recommended action: Choosing networks

Choose a network range that is available and which is of a sufficient/appropriate size for easily testing. For IPv4, if a new network/subnet is being created (which is recommended when implementing and testing networking for the first virtual machine on a host running virtual machine software), a general recommendation for simple temporary test networks is to use a /24. (Some people may view such a network as being unnecessarily large. Using addresses less wastefully is something that may be pursued now, or later.)

In most cases for most people/organizations, finding a subnet range with that many free addresses may most feasibly done by using a private address range. If private addresses are being used, which will be the case if more addresses are used locally then the amount of publicly-accessible addresses that are available, which is generally the case with IPv4, then anticipate using NAT before Internet access is ultimately working. For IPv6, plan to allocate a /64 for easy/test implementations. Using a set of public IPv6 addresses may work just as easily as private addresses, or even easier (since NAT may not be required), but be sure not to use addresses that are accessible by untrusted resources. For instance, do not use publicly-accessible addresses on a network that is connected to the Internet if the smaller network doesn't protect computers using traffic firewalling/routing.

Recommended actions: Plans for assigning system addresses

Make a decision about what subnets to use and what addresses are going to be provided for each machine.

Assigning addresses within a subnet

Following the advice from Network Addressing Plans/Methods, especially the alternate way of system address assignment, using RFC 1219's guidelines, decide what addresses will be assigned to systems.

Assigning an address can be done in documentation, during a planning phase, even before performing any sort of technical steps to assign the addresses.

Instead of trying to create an elaborate plan on what address to assign to each system, simply use an existing document as a guide, and mimic that guide. Deciding to do that will likely work for the short term, and reduces the amount of decisions to need to be made (which may shorten the time required to be planning). For instance, instead of creating a very elaborate plan of what addresses to assign to each system, instead, use an already-existing example of network addressing for multiple individual systems. If the provided example is at least as complex as what is likely to be used initially, at least during testing, then going that route may be a decision that ends up being simple to decide, fast to implement, successfully functional, and therefore, good.

So, let's keep planning short and simple. Some decisions will need to be made about what addresses will be assigned to each NIC. If automatic addressing is already set up, go ahead and use what's easiest. In case manual addressing is needed, keeping things simple will allow implementation to be tested sooner than if time is spent planning an attempt to do something more elaborate. The example network addressing for multiple individual systems is at least as complex as what would be needed for a simple test network, so that is an option of a model to use. Using that guide as an example, the virtual machine can use a number that ends with 200, or if IPv6 is being used, another option is to plan to have the address be automatically calculated. The host machine may be viewed like the virtual machine's WAN connection, so the host machine could be assigned an address ending with the number 1.

The recommendation for simply testing networking is to choose an address range for a subnet. Then, assign addresses (e.g. IPv6 and/or IPv4) from the address range being used for that subnet, using either manual or automatic address assignment: whichever is easier. The addresses should be assigned as needed; the requirements will depend on which method is used (out of the methods described in the section about configuring networking in virtual machines). As an example, this may involve assigning an address for the NIC on the virtual machine, and to the virtual NIC which is on the host machine and which communicates to the NIC on the virtual machine.

Setting up the networking
New/Temp Guide

Upon trying to following this guide, it was discovered that the instructions for setting up networking were quite... unpolished.

For the time being, instead of following the older guide, consider following this newer guide. Hopefully the content of this newer guide will be helpful, and useful, enough that this newer content will remain, merging with and/or replacing other older content as needed.

This guide is meant for using Qemu.

Note: It seems the Qemu monitor might be able to add a NIC to a running system. However, it remains doubtful how well an operating system may appreciate such an ability, unless the device somehow identifies itself as a removable device like a USB NIC. This guide doesn't really discuss this approach, other than this brief mention. Instead, it is assumed that any running copy of the virtual machine will be getting shut down.

Finding the file

If the content of this guide was followed, the script file may be at: $VMDir/bin/exc_base_system but a file may only be found there if $VMDir has been appropriately set. The value of $VMDir is appropriately set in the executable file, but that might not be of any help with locating the executable file. For this, consulting some documentation may be helpful. Hopefully such documentation was made when determining the location to store the image of the primary storage device, and hopefully such documentation can be successfully found fairly easily.

The first step is to back up the script file that is used to run the virtual machine. (This guide generally shouldn't cause things to terribly break, but it can be assurring to know that a backup is conveniently available.) (Details about copying files are available.)

Then edit the script file (by using a text file editor).

Adding NICs

Details for doing this may be found in the section about virtual machine network configuration (or, more likely, the resources that are referenced from that section).

Test the added NICs

Quit any currently running copies of the virtual machine. (There may be various ways to do this, including using the Qemu monitor, or using the kill command.

Then, re-run the virtual machine script.


. ${VMDir}/bin/exc_base_system

At this point, the virtual machine may be running, but without a visible display. If that is the case, make the display visible. A first step to do that may be to check the Qemu command line to to see if it notes an IPv4 address and TCP port being used by the monitor. Then, expect to use the Qemu monitor, and see virtual machine output display or, even more specifically, virtual machine output display: remote access or, even yet more specifically, Enabling Qemu's VNC server.

(This guide currently does not have a strong description, at this point, about how to test/verify working network connectivity. A guide for IPv6 has probably been made in some ancient version of notes, so it simply needs to be located and placed here. Until then, there is little incentive to want to re-make such a guide.

After testing, if results are satisfactory, move on.

Automating address assignment

Modified the ${VMDir}/bin/nic/upif0 file by uncommenting a line so that the following would run:

# dhcpd -c ${VMDir}/bin/cfg/dhcpd${PASSEDVAR} {$PASSEDVAR}

Naturally, this required I make that file:

echo VMDir is ${VMDir} and VISUAL is ${VISUAL}
mkdir ${VMDir}/bin/cfg

The contents of the ${VMDir}/bin/cfg/dhcpdtun0.cfg may be documented in the section about Information about DHCPd (specifically, information about ISC's and OpenBSD's DHCPd).

Add support in the appropriate downscript file, if the support doesn't already exist, to remove the dhcpd server. (Note: If using an older version of Qemu, the downscript may not be a supported command line parameter. There may be various ways to try to deal with that limitation; the best may be to try upgrading to a newer version of Qemu.)

Things to not do
The following was then tried, and may have caused some problems (by setting the tun interface into some sort of a rather unworkable/unusable state, until the host system was rebooted):
sudo ifconfig tun0 -link0
sudo ifconfig tun0 down
(I didn't use sudo ifconfig tun0 delete
sudo ifconfig tun0 destroy
install an operating system
Some steps to take after installing the operating system
Compressing a copy of the current virtual machine

After installing the OS, before doing any configuring, saving a copy of the operating system, still largely unconfigured, can be a good idea. Some standard “customizations” made to the configurations might always be desirable, but just in case a single one of the standard changes is ever undesirable (perhaps for some sort of testing), keeping a copy of the current state could end up being a time saver later.

Before altering the hard drive image with a program other than the virtual machine, make sure the virtual machine software is stopped.

Something like the following may be useful:

cd ${VMDir}/diskimgs/base/qcow2

The hard drive file may be compressed using information from the section about compressing hard drive images.

It may then be good to: verify that no errors were reported by the compression process, copy the compressed file, and marking the copy read-only (by modifying the file attributes so that there are not write permissions).

It may then be good to make a snapshot image, so that future changes are made in a new file instead of a file that duplicates much of the data of the file that was just saved. (However, there may not yet be a convenient guide for that, so that step has been skipped for now.)

Modify boot
I also modify the script, and tell it to stop booting from the CD-ROM. The script may continue to use the CD for now, in case it helps to install packages.
Setting up the new operating system installation

See: setting up a new operating system installation. (This step contains quite a few other steps.)

Preferred automatic addressing configuration
I make sure that the system tries to get DHCP from the first NIC, as that is how most machines will be configured.
Saving an image again
I then make an image of that configures OS. (Compress, make read-only.)
Some upcoming plans

These haven't been recently tested, but this seems like it may be a good order to proceed with:

  • I do all this before I start trying to add services like DHCP.
  • I then make two virtual machines: one as a firewall, and one for DHCP. I make sure the two machines can ping each other.
  • I then set up the DHCP so that the firewall gets its address from the DHCP.
  • Perhaps then I modify the firewall to allow Internet access from itself and from the DHCP server.
  • I should then probably focus on getting the DHCP server to serve all computers that it should serve. This may mean doing something like running dhcrelay on the host computer.
  • Then I get DNS working. Then I modify the DHCP server to start using the internal DNS server.
Older guide

Virtual machine software may support multiple implementations for networking. The first thing to do may be to decide upon one of those methods. For details, start by checking the section about “Specific implementations of virtual machine networking”, to see if there is a section about the specific virtual machine software that will be used to run the virtual machines. More specifically, if there is such a section, then see if one of the subsections provides recommendations about whether any methods of network implementation are generally preferred more than others.

(The rest of this section is older text, that may be moved or removed. Feel free to skip it for now.)

(An old note made sure to point out temp notes. So, this text may need updating, but have some useful details. Naturally, additional content (which might be useful right about now) may be in the main section about Virtual machines.)

It is time to set up networking. Here is some quick pointers:


Plan to edit the command line that is normally run to start the virtual machine. If the guide has been followed so far, then there is a Qemu command line in a script file. So, plan to edit that script file.

That command line has a set of command line parameters that start with “ -net nic”. Leave that alone: it's perfect.

However, another portion of the command line says “ -net user”. Read the following documentation as needed to convert that to “ -net tap” set of command line parameters. With the “ -net tap” command line parameters, be sure to specify a script file to configure a tun* interface. If the version of Qemu is new enough (0.9.1's documentation did not mention the parameter, 0.14.1's did), and if the tun* interface is not going to be used by any other software, go ahead and have Qemu clean up after itself by using the ,downscript=dfile command line parameter option to bring the tun* interface down.

Unless one or more quick pointers above provided all of the necessary information, the best approach to take at this point may just be to just start reading/applying the information in the section called “Specific implementations of virtual machine networking”.

(For those trying to get a virtual machine going, the generalized information that is related to a specific implementation being used may seem to be the most interesting generalized information. The section about specific implementations may make appropriate references to the more generalized section about common options for networking with virtualization. Those interested in reading all recommended material, for maximum learning, may also want to read about all the common options in the Networking with virtualization section, even if a specific implementation of virtual machine software doesn't support one of those options.)

The main point to reviewing the section of “Specific implementations of virtual machine networking” is to make sure the best option is being used. For instance, some virtual machines may default to using an option that involves “having the host machine treat the virtual machine like a standard networking application”. However, that may not be the optimum method of networking, as it may involve certain limitations which are nicer to not need to have. For the virtual machine software known as Qemu, the “Specific implementations of virtual machine networking” recommends using a different approach. (At least in theory, other virtual machine software implementations may have different recommendations.) Now may be about as good of a time as any to take the time to set up the virtual machine's networking configuration in a more preferred fashion.

(The rest of this section is older text, that may be moved or removed. Feel free to skip it for now.)

With the decisions already made about what subnet will be used, and what addresses will be assigned to machines, configure the host system to process/pass network traffic with the virtual machine. Having the host machine process network traffic with the virtual machine, similar to how the host machine would process traffic from a physical NIC, may take a while longer than some other methods to set up, although it also may provide more options. The commonly desired flexibility that is provided by that networking configuration is why that networking configuration is the one recommended to use at this time.

The goal here may be more about getting the host machine configured to provide the largest amount of options on how the network configuration is set up. (This may/will involve having/creating a TAP device.) The method to do this involves using a virtual NIC on the host machine, and setting up whatever traffic routing/firewalling is needed. The goal is not necessarily going to be to spend a lot of effort customizing the virtual machine in great detail. After all, the goal of this initial virtual machine may well be to use it as a “parent/base image”/“backing file” which can then be used to create other snapshot/child images. The individualized customizing of each child images makes sense to do when working with the child image.

Verifying the basic networking
See verifying the networking.
Handle traffic forwarding

Once a virtual machine is able to communicate with another computer on the same subnet, such as a TAP device of the host computer, often a next step that is clearly sensible would be to pursue will be to allow the system to be able to communicate with the rest of the Internet.

(Newer text)

See How the traffic (involving the NIC on the host machine) gets processed.

(Older text)

(This is some text that is probably older, predating the newer text referenced above. It may not have been fully compared to the previous text, so is remaining in case any useful details should be merged into the text that gets kept.)

A couple of approaches may be to set up forwarding/routing of network traffic, or to set to set up bridging of network traffic.

Contrasting/comparing forwarding and bridging

The difference between forwarding and briding has to do with which destination “physical address” (MAC address) is contained in the “layer two” frames.

In both cases, the machine with a physical connection, which would be the host machine, may end up passing traffic that contains a destination “logical address” (IP (IPv6 or IPv4) address) of a remote machine which is on a different subnet. In both cases, the virtual machine will presumably figure out that the remote Internet site (like is not on the same subnet. The virtual machine will then use ARP to get the MAC address that corresponds to the IP (IPv6 or IPv4) address of the “default gateway” for the virtual machine.

When using the forwarding method, the virtual machine's “default gateway” will be the NIC of the device which is forwarding the traffic. (That will be the TAP device on the host machine.) With bridging, the “default gateway” of the virtual machine will likely be the same as the “default gateway” of the host machine.

is shown in the “layer two” frames that the host machine receives will show a destination “physical address” (MAC address) which is the MAC address of the host machine. received show a destination MAC address

In this discussion/example, the virtual machine will be sending traffic to the Internet by having the traffic go through a TAP device on the host machine.

The main difference between forwarding and bridging is going to be the destination address of the frame. of the default gateway for the virtual machine. In practice, the main difference may be the Let's look at an example for both of those cases. Traffic for a machine on a different subnet, such as a remote Internet site (like, will be sent to a gateway address. The “layer three” packet (the IPv6 or IPv4) will specify the eventual desired destination address. This “layer three” packet will be stored inside a “layer two” frame. With both packet forwarding and frame bridging, the result is that the virtual machine will receive the “layer two” frame and decide that the information will need to go the default gateway of the host machine.

Example of forwarded traffic
The virtual machine realizes that is not on the same subnet. The virtual machine uses the host machine environment as a gateway. Therefore it uses ARP to determine the address of the host machine. a remote machine

This may be done by enabling forwarding/routing and setting up routing so that traffic from the TAP/tun device can reach the Internet (performing NAT as needed). (When setting up forwarding, the type of traffic set would be the unicast traffic. For example, in OpenBSD, the “mforwarding” sysctl values are related to multicasting so those can probably be zero, but other values related to forwarding might need to be adjusted.

A different option that one might have easier success with is by using bridging with the virtual NIC on the host machine and a different (physical) NIC which is also on the host machine, although that basically involves combining multiple networks and that may not be desirable (perhaps because of other computers which are on one of the networks).

END OF Older text:

Either way, any sort of software-based firewalls need to be not blocking this traffic. The goal at this point is to be able to ping a host on the Internet.

Known pingable hosts on the Internet

For IPv4, hosts that one may wish to try include:

  • Google's DNS servers: and, or if DNS is working well,
  • Other DNS, like those listed in DNS within IPv4 4.2.2/24.

Some/many/all of the options listed here may also be known publicly usable external DNS servers. (Checking out the section about DNS which lists such servers might provide some additional pingable resources.)

If commands are run on the host machine to help support the virtual machine, and those same commands aren't likely needed in cases other than when this virtual machine is being run, then one may wish to automate those commands by putting them in a script file which the virtual machine software runs. For example, the virtual machine software might run some code on the host machine whenever a specific NIC on a virtual machine is created. (The emualtor Qemu does this using code from /etc/qemu-if* or different files that are specified on the command line.)

Allowing remote access
It will be desirable to be able to remotely access machines. In many cases, it may make most sense to not spend much effort into enabling remote access until after the operating system is installed. However, for those who are interested in getting an operating system installed, see: remote access to a virtual machine.
[#vmwrapup]: Wrapping up info on creating the first virtual machine
Overview: System customizations

The configurations of an installed operating system can start being customized as early as sometime during the installation process. Generally operating systems will allow the disk to be customized. In some cases, network settings may also be set.

When customizing the system, it may be useful to consider what the role of the (virtual) machine will be.

After making a single virtual machine, the experience will generally allow subsequent machine creation to go more quickly. (This is especially true if creating the virtual machine involved setting up a command line in a text/script/batch file. The contents of such a file can be copied to a new file, which often speeds up the process of creating a machine.)

A great role for a first machine is to have its hard drive be a “parent/basing image”/“backing file”. Then, after the relatively tedious work of installing an operating system, and perhaps making other routing adjustments (like installing anti-virus software, operating system updates, and other protective software), additional machines can be added with relatively minimal effort.

Installing the operating system

Having gotten this far, the recommended next step, if this step hasn't yet been performed, is to go ahead and try to install an operating system. There are some notes about installing various operating systems in the section with details about specific operating systems.

Some hints about installing an operating system:

  • It may be best to install with options to try using DHCP, even if DHCP isn't yet working. If that isn't an option, it may be nice to get DHCP working on the host machine's virtual NIC (i.e. the “TAP/TUN” interface), even if the configuration used for automatic addressing is not finalized. By setting up the “parent/base image”/“backing file” to use automatic addressing, other virtual machines using snapshot/child images may default to be configured to rely on automatic addressing. Using automatic addressing may be a great default for the snapshot/child images, since typically most such images may complete their startup (booting) process after automatic addressing is fully set up.

    Having even a simple temporary setup that works well enough for the virtual machine to automatically get the address may be effort worth investing in, even if the configuration used temporarily doesn't match the long term configuration that will be used. If the subnets change later on, the virtual machines can work with a new configuration without needing to be changed themselves. (The “parent/base image”/“backing file” used by virtual machine software may be something that shouldn't change.) (The child/snapshot images that use IPv4 probably will want to use DHCP.)

  • If using a temporary DHCP server (which is likely what will be happening if temporarily using qemu with slirp code before eventually changing to a different networking model), keep in mind that the DHCP server being (temporarily) used may affect what DNS server is going to be used by the machine's DNS client. If that DNS server stops being available, which is likely to happen if switching qemu to another networking method, then the machine's DNS client will need to be re-configured. That may be as simple as re-running the DHCP client. In case the operating system requires additional adjustments, this may be good to keep in mind.
  • [#useezpw]: When choosing usernames and passwords, don't try to get overly complex. This may be different than most recommendations of standard practice, but the key here is that the plan is for credentials stored in the “parent/base image”/“backing file” will end up being disabled/changed in the child/snapshot images. Those child/snapshot images are the ones where more rigourous security will be desired, and until that security is set up, the only user of the machine is expected to be the administrator. If both the “parent/base image”/“backing file” and child/snapshot images are going to be able to be sufficiently protected from intrusion, there is little benefit to making the initial passwords super complex when it is known that the initial passwords will be changed very soon. (This tip may be a bit less relevant if the hard drive images are going to be left insecure before the passwords change again.)

    It may even be worthwhile to use a very well known password which is likely to be guessed in case it is forgotten.

    [#comnpwds]: Common passwords

    For more details about some commonly used passwords, see a section discussing common passwords.

  • [#swpopbas]: There are different schools/trains of thought about how much software to install on the “parent/base image”/“backing file” image if it is expected that the image will, or may, be used later to create some child/snapshot images.
    • One train of thought is: install the minimum. One benefit is that if a minimum amount of software is installed, then tasks that involve all the data on a disk will go slower (on the parent machine and also each virtual machine) when the process has to handle extra data that isn't needed for the specific machine the data is on. Examples of such operations, which would be affected by the extra data, could include performing some file system checks (fsck / CheckDisk / ScanDisk), performing file integrity checks, performing anti-malware scans, backing up file systems, searching for a file with certain characteristics, and/or optimizing a volume (e.g. defragmenting).

      Also, having fewer commands and software pre-installed might hinder an attacker. (However, as noted by OpenBSD FAQ 4: section on needed files (section 4.7)'s subsection about not wanting compilers, chances may be high that such hinderence may not affect an attacker by a whole lot).

      Consider the following specific information about which data may not be needed:

      • If compilers are neither needed nor expected to be useful, don't install them. If games aren't going to be played on this machine, don't install them. Primarily to keep the amount of used disk space low, if man pages are easily available on another machine, perhaps don't install them. (However, for convenience, they are recommended for systems where the system administrator will be fairly new to the operating system that will be getting used.) (Sometimes man pages are available online, but don't count on those if this system will be essential to online access. Otherwise the man pages may not be accessible when they are needed.)

      For some specific examples:

      Sets to install with OpenBSD

      For example, install the following sets in OpenBSD: bsd, bsd.rd,, base??.tgz, etc??.tgz, misc??.tgz, and man??.tgz. (misc??.tgz is perhaps not very useful, but there also is not a lot to it: it may be fairly small at 1.1MB uncompressed.)

      (There may also be a desire to install some pacakges: The above list is simply the operating system sets to install.)

    • Another plan is: install everything that even one child image will be using. Otherwise, the costs of installing software (such as disk space and installation time) will be used up anyway when a single child image uses the software, and such costs will be incurred again if a second child image ever uses the software. (The costs will be experienced yet again if a third child image ever ends up using the very same specific software.)
  • Some Unix systems may default to allocating a bunch of space for a location (the /home directory is a traditional location) for space used by home directories of end users. (Those more familiar with Microsoft Windows Active Directory networks may be more familiar with the term “user profiles”.) That may be all fine and dandy for a file server, and may make a lot of sense for an ISP that provides space for end users to store E-Mail, web pages, and other data. However, for a system that performs other functions (like being a traffic forwarding firewall, an automatic addressing server, and/or a name server), there may be very little need to allocate a bunch of space for end users.

    Rather than use a bunch of space for home directories, consider reducing such space down in size to a smaller amount, and have unused space on the drive. That unused space may later be easily allocated for additional space for some/all end users (perhaps replacing /home), and/or be used for other purposes (such as swap).

  • Decide how large to make each partition. Note that if this is going to be a “parent/base image”/“backing file”, this step may benefit from a bit of thought about how large the partition should be to fulfill the space needs for whatever virtual machine using a child/snapshot image. One option, which may work better for operating systems with named mount points (e.g. Unix: although this may be supported in NTFS, such named mount points have not traditionally been used as commonly in Microsoft Windows), is the option to leave a bunch of free space, so that if one machine has a specific need for a large partition then it may just make the partition as needed.
  • Along the lines of partition sizes, consider the possibility that storing some data on a different hard drive. This may particularly be a useful consideration for virtual machines: Swap space reserved on the hard drive and/or swap/paging files used within a file system and/or temporary directories (/tmp in Unix, and %TEMP% and %TMP% for each user in Windows and MS-DOS) may be able to go onto a different hard drive. This may make a lot of sense for a virtual machine which uses growable hard drive images, because then if that hard drive image ever grows too big from previous data (especially less-than-fully-compressable data), a whole hard drive image, if it has no purpose other than storing this sort of temporary data, may simply be replaced with a backed up, smaller version of the hard drive image. Defragmenting a drive that consisted of only temporary data may be a fully unnecessary maintenance task: instead, the drive could simply be replaced with a backup copy from when the drive was largely empty.

With these things in mind, read the following notes about specific implementations but then go ahead and install the first operating system.

Notes about specific implementations
Installing OpenBSD to a virtual machine

Here are some notes that were taken during an installation. (These notes are probably improvable.)

  • Using entire disk image. Editing default layout so that /home isn't all of the remaining space (about 6GB), instead using a fourth of the size (3163474 instead of 12653897)
  • There might not have been any swap space reserved. If that's the case, well, then, good thing that /home wasn't made unnecessarily large. Address that. (Update: This might not be an issue.
  • It may be nice to use disklabel -E's e (edit) command to edit the label name of the virtual hard drive. This could help distinguish this disk from other drives that may be made, particularly if the default name given to each hard drive ends up using a default label, such as “QEMU HARDDISK   ”. The reason is that if a second hard drive is added, it may also use the same default name. Having actual unique names can be useful down the road when trying to perform operations on a specific disk.
  • Ended by turning the machine off, which happened by running “ halt -p ”.

After installing the operating system, the disk image was moved. Then it was compressed and made read-only, as noted in the directions that follow.

At some point, there may be a notable amount of time to wait while the system performs disk maintanance, downloads data, and/or installs data. During that time, move onto the next step of the whole process, which simply involves making some decisions and documenting them. By proceeding with creating this documentation, the documentation may be used when carrying out the actions. That can go more quickly than making decisions along the way. Also, making the documentation during this time has another benefit: such actions will likely result in a situation where the decisions are documented in the end. That certainly can be beneficial. It is acknowledged that this text is not clearly identifying what needs to be documented. Although documenting things (ahead of time) sounds like a great idea, there should be some clarity on what to be documented. Perhaps network documentation?

After the OS is installed
Creating children before making modifications

Consider making a child image. There may be some reasons not to make a child/snapshot image, such as using a hard drive imaging format that doesn't support child/snapshot images, or wanting maximum speed without overhead caused by supporting the technology of using a child/snapshot image. (Such overhead may be less of a concern for early/test/educational installations which aren't likely to be utilized by a business “production” environment in the foreseeable future, if ever.)

People who have the option to use a child/snapshop image, check out the overview to see some reasons why it may be a good idea to make such a child/snapshot image even before performing some routine changes/customizations for a new system.

Creating another “child image” virtual machine from a “base/parent image”/“backing file”
Overview: Why make a child/snapshot image now?

When the operating system is done installing, consider the role of the computer before making a bunch of customized changes. If the system is going to be a “base/parent image”/“backing file”, it may be nice to shut down the system fairly quickly (rather than trying to make a bunch of other configurations). Even something simple like installing updates, and other favorite programs, may be a task worth performing at a later time, after the process of creating a child/snapshot image. This way, an image of the hard drive before the changes were made could still be available. Perhaps someday there will be some different goals that will benefit from the change not being made. For example, perhaps there may be a desire to compare some details about a system before the changes were made (comparing such a system to what a system is like after the changes are made). If certain customizations, like installing a specific service pack or other update, did not occur until after a child image was made, then there may be some available flexibility to easily make a new child/snapshot image from the older, less modified “base/parent image”/“backing file”.

(This section may be fairly redundant with an earlier section.)

If the virtual machine software supports child images, now may be a good time to consider making a child/snapshot image. The main objection to this idea may be that later, after the operating system is configured a bit further, may be a more sensible time for a child image. The contrary arguement is that later might be a good time for a child image as well, but there is little reason not to make one right now. After all, if a horrible mistake/misconfiguration occurs between this point and when the next child image would be made, is it really desirable to need to start over completely by re-installing the operating system? Preventing that step from needing to be taken again is one good reason to do it now. Another reason is because some future need may involve wanting to use this operating system customized in a different way. If so, having a save point before the customizations may be useful. The operating system's defaults, which were chosen by the developers of the operating system, are probably a fairly good launching point for most different configurations that may be pursued.

Once an image is made of an operating system installation, create a separate image for customizations to that installation of the operating system. This way if one wants to configure a system very differently, but still using the same operating system, then one does not need to install the operating system again just to get a hard drive with a fresh installation of the operating system. (There might still be some causes to need to start over with the operating system installation: Namely this would be in the case of wanting to install the operating system differently, perhaps to a virtual machine hard drive which is a different size, or perhaps to change partition details such as partition sizes or the type of filesystem; having given these examples, those examples might not always require a re-installation of the operating system.)

It may later be worthwhile to treat this disk image as a disk image that will be used as a “parent/base image”/“backing file” for snapshot/child images used by other virtual machines that contain even further customizations. The main point of this file is to make changes that are likely going to be desired for multiple other virtual machines, such as installing key software likely to be desired on many machines.

Note that file integrity checking software might not be getting used at this early point in the guide, so feel free to skip that specific instruction in the following generalized steps (which are also referred to at other points in the guide).

[#prpkidim]: Some final preparations for an image to be used as a “parent/base image”/“backing file”
Other changes to the parent image

Consider if there's any other changes that are desired. If there are, consider whether to make them before compressing the image, particularly if it is known that compressing the image is going to be done after changes are made. (This isn't to suggest that large changes should be made before creating a child/snapshot image. It may be better to complete the process of creating a child/snapshot image first. However, if there are no plans to create any additional child/snapshot images, and there are plans to compress data and to install additional software (perhaps including updates like service packs), it may make sense to complete such installation before running the compression. Doing so will likely cause the compression to take longer, because more data will be compressed, but then the end results will be a smaller file.)

One reason why to decide to not make changes at this time, before making a child image, is if the pre-changed image may be useful as a parent down the road. In that case, making a child image before making the changes may be the most sensible route. If further changes are to be made, perhaps a new split of a new child image may be made at that time.)

If file integrity checking software is being used, getting the data for that sort of software into an up to date status may be sensible. In some cases, though, that might not be as sensible (e.g. if the image currently consists of a basic setup that doesn't yet have file integrity checking software installed).

Once all changes have been made, if remaining tasks include compressing the data and creating a child/snapshot disk image that has those changes included, it makes sense to compress before creating the child/snapshot disk image. This way, the “parent/base image”/“backing file” parent image can be positively affected by the compression.

Keep in mind that in modern times, most disk decompression is pretty speedy (although compressing may take a while): Reading compressed data and decompressing it may be faster than reading a larger amount of data (due to the data being compressed). (Common knowledge is that one should expect a huge performance hit from using compressed data, but that may primarily be largely a result of some specific implementations, such as disk compression software build into a Microsoft Windows operating system. Such specific implementations don't invalidate the general theory, and so other implementations may show speed increases when suing comrpessed data.) elaboration on this point via hyperlink is recommended: refer to a disk compression section that might explain the theory in a bit more detail.

(If compression is desired for a virtual machine, continue reading for details to take care of before proceeding to an upcoming and/or referenced section that provides details for compressing a virtual machine's disk image.)

Required planning to avoid unpleasantness down the road
Why it is important to be careful about image placement

In addition to the need to not change the contents of the “parent/base image”/“backing file”, one may need to keep the “parent/base image”/“backing file” in a specific location. Moving the image to a new location could cause problems for a child/snapshot image which is based on a specific absolute or relative path for where the “parent/base image”/“backing file” may be. (For images supported by Qemu (perhaps with some specific old version(s), and perhaps this needn't be as true with some newer versions?), such a problem could be noticed easily with “ qemu-img info ”, being used on the child image, resulting in an error message about being an invalid file. If the “parent/base image”/“backing file” was moved back to the expected location, suddenly the child image would no longer appear to be an invalid file.)

Making a change to the path may or may not be very feasible. In theory, making a change could be as simple as changing a text file or using command line parameters to make changes or typing information into a program's GUI interface. With Qemu there has been success using “hex” (“binary file”) editing on the child/snapshot image, but only if the new location of the “parent/base image”/“backing file” is an equal or smaller number of bytes as the earlier location. (If there were fewer bytes, the end of the filename would simply be NULL characters.) If the new location required additional bytes, even overwriting the NULL characters in the qemu image would not work well. In a more recent attempt, it seemed even a shorter location did not work well. (Possibly that was due to a difference related to a relative path being stored somewhere. A re-test may be warranted?)

Redhat Bugzilla: Bug 530134 discusses an example of trying to do some fancy work involving a “parent/base image”/“backing file”... and in the end things don't work.

More considerations about placement

One possible approach may be to store all files related to one project, whether the file is a a “parent/base image”/“backing file” or a child/snapshot image, in one location (such as /diskimgs/project1) and all files related to other virtual machines in other locations. For instance, a “parent/base image”/“backing file” image related to a third project could go under /diskimgs/project3/baseimgs/.

That may be a sensible approach: another may be to have all files that are “parent/base images”/“backing files” in one location, and all child images in another location. For instance, a “parent/base image”/“backing file” image related to a third project could go under /diskimgs/baseimgs/project3/baseimgs/. Having all “parent/base images”/“backing files” in one location may allow for some easier security/permissions setup. (Details about permissions may be at file attributes/ownerships/permissions.) This would be because a whole directory (including all of its subdirectories) could, perhaps more easily, limit some file access to read-only security permissions. Also, then the images in that location end up having patterns, such as being stand-alone images that don't require access to other images, and perhaps in many cases being larger than the small child/snapshots. Such images may frequently be accessed in a read-only fashion. These similar characteristics may be a logical reason why it may make sense to organize things with parent images being kept separate from child images.

However, what happens if a child/snapshot image is created from another child/snapshot image? Does the original child/snapshot image, which is now both a child/snapshot (requiring access to the original image) as well as being a “parent/base image”/“backing file” (which should not be modified), go near the other “parent/base images”/“backing files”? The answer simply depends on one or more decisions, so there isn't necessarily just one universal answer that is expected to always, or even usually, be better/superior/more-correct than other answers.

It may be nice to have a folder named after a file format. This way, CD images may go into iso9660/ while compressed qcow2 images may go into qcow2/. Later, if there is a need to locate a CD image (to write to an actual optical disc or to mount in the host operating system), one doesn't need to intentionally try to ignore (or, worse yet, sort through) all the qcow2/ files. For raw files, it may make sense to categorize by media type, so that 1.44MB images (designed for obsoleted floppy disk technology, or images using the el-torito method of booting from a CD), and/or other images meant for removable media, may be separated from images for hard drives.

Yet more considerations about placement
At some point, it may be needed to reference what the parent image is. It may be useful to reference a full path. For example, consider a case where a child/snapshot image references a relative path (e.g. ../somedir/otherimg) for its “base/parent image”/“backing file”, and then that child image is referenced by a grandchild image which uses a path relative to a different directory. In such a case, is the software smart enough when viewing the grandchild image to realize where the relative directory for the child image is meant to be? Unless such details are tested for a specific implementation, it may be best to try to keep the implemenations simple, and absolute paths are more likely to be simple in implementation (even if they are less likely to be easy due to being short, and less likely to be as flexible).
[#vmdskcmp]: Compressing the image

In all likelihood, the disk image should not be used during the time when it is compressed. Therefore, before trying to compress a disk image, be sure to shut down any software that may be using the disk image (especially if the software may change the disk image). For hard drive images, this typically means shutting down any virtual machine that would (if the virtual machine was not shut down) be using the hard drive image.

After the system is shut down, the next step will be to compress the disk image if that is desirable. If this is going to be done, it simply makes sense to do so before making other machines based on a “child image”/snapshot that was created from this virtual machine. (Maybe it doesn't matter, if the compression is lossless and if the child images can interpret a compressed image to be identical to the uncompressed image. Whether that is true or not may vary based on different implementations. Even if this did work, perhaps the child image would still benefit from compressing the parent image before the child image is made.)

Details on this step are located in the virtualization page: section on compressing disk images.

Once the image is compressed, some formats will store additional changes in an uncompressed state. Therefore, it may be undesirable to make changes after the most recent time that the image is compressed. If desired changes are discovered, and it is decided that they should be made, then re-compressing the image after the changes may help to make sure those latest changes are compressed. However, compressing the image again may take a while again.

Once the latest compression is done, there may be little to no further desire for further changes. If so, make the disk image read-only.

[#manmkdvm]: Directions for making a child image

Some software or methods (at least one: e.g. Petri IT KB's guide to Virtual PC disks) may need to make a change to the “parent/base image”/“backing file” in order to create a child/snapshot image. If so, make a backup copy of the parent image before making changes (if feasible, unless that is undesirable for some specific reason or another), and ensure that the main file is writable. Otherwise, make sure the file is not writable: make the disk image read-only.

(Creating a hard drive image might be handled as part of the process of creating a virtual machine. If so, the most straightforward way of handling this may be to just create a new virtual machine, and then allowing that process to take care of the task of handling disk images. If the process used to create a disk image involves options being presented in a GUI, some people may find that to be easier than alternative methods that may involve using a command line. If that is not the case, though, it may make sense to modularize the steps taken. Specifically what that is referring to is focusing on disk images first, before taking on a more elaborate task such as making a new virtual machine. The main benefit to doing this in separate steps is to reduce the amount of details that one needs to focused on at any one time. If it is more straightforward to do this seamlessly as part of the virtual machine's creation process, then by all means, do what is easiest.)

After deciding what “parent/base image”/“backing file” to use and where that file is going to remain and where the child image is going to go, create a child/snapshot image (using the implementation-specific details as needed).

Some directions for creating child images is in the Virtualization page's about creating disk images. The directions are likely to be specific to the virtual machine software and there may be some differences based on which type of image file is being used.

[#dskimgro]: Modifying file attributes/permissions of the disk image file
The usefulness of making disk images read-only
Overview: Why to make parents read-only

(This section has a fair amount of warning.)

After significant changes to a virtual machine's disk image (such as installing an operating system), it may make sense to keep a copy of that original image.

Making an image read-only before making any child/snapshot image makes a lot of sense, since the child/snapshot images may require that the parent image is always available and never changed (at least not in a way that would affect the child image). In probably all cases, once a child/snapshot image exists, one should expect to never again update the “parent/base image”/“backing file”. The data in a “parent/base image”/“backing file” will commonly be interacted with by software that is designed to write to that data file, so it may be an easy mistake to make to accidentally start writing to that file (and possibly to not even realize the error until changes have already been written, especially since most modern popular operating systems will routinely write to hard drives when they are starting up). Once that has already happened, substantial data may effectively have been lost, because child images may no longer work properly, if at all.

If a virtual machine uses this “parent/base image”/“backing file” (which might be done as simply by being mentioned on a command line that starts a virtual machine), and if writing to the disk is allowed, then changes will likely be successfully written to the parent image. This unsurprising truth is not only true when there are intentional efforts to change data (like saving a file in a text editor), but also when data is written through one or more of the many automated processes that routinely write data, such as having a log file being written to, swap information being maintained, or a disk being checked for errors. Any such changes that are made to the “parent/base image”/“backing file” could be a problem for any child/snapshot image that may exist. This sort of event can, naturally, be even more painful in cases where multiple child/snapshot images are lost because they use a single “parent/base image”/“backing file” file.

The way to safely implement a change to an existing parent image is to make a new snapshot/child image (and then have that new snapshot/child image be modified, as desired). With at least some of the image formats that support snapshot/child image technology, the newly created snapshot/child image (which has the desired data modifications) may then serve as a parent for new child images, if desired. In some cases, it may be possible to somehow merge a child/snapshot image's changes into a “parent/base image”/“backing file” file, and the end result may not be a problem for a single child/snapshot image that was used as part of the merging process. However, this sort of change, which results in a modified “parent/base image”/“backing file” file, will likely invalidate that modified file, so that file won't be useful for other child/snapshot images.

So, since (in many cases) the parent image cannot be modified without causing data loss, let's deny permissions so that the parent image isn't accidentally modified (perhaps by being loaded up in a virtual machine and booting an operating system which modifies swap/page space on the disk).

Warning: starting a virtual machine with a read-only hard drive image may not result in the sort of clear error messages that one might expect when there are errors writing data. For example, trying to save changes made to a text file that is “read-only” will generally result in a text editor complaining that the file can be written to. In contrast, using a read-only disk image may not be quite as clear, so soon, that there are problems.

With at least one (version of at least one) virtual machine software product, the software was not reporting problems with writing data. Trying to write changes, like saving a modified text file, would not successfully result in changes being written, because the virtual hard drive was using a file that wasn't allowed to be written to. However, the software within the virtual machine made inaccurate statements (like “File saved successfully” or “1 file(s) copied.”) that indicated that data was written. Perhaps this is because the virtual hard drive being used reported success to the operating system, even though the data was written. If that is the case, then there's no surprise that the operating system, and software running in that operating system (like a text editor saving a file), reported that data was successfully written. However, when re-opening the file in the text editor, it was found that the earlier version of the text file is what got successfully read from the disk.

Such an error (where software ends up reporting no errors) may be a little difficult to be noticed quickly, and, once noticed, may still take a bit of investigation to discover the actual cause of the problem. Meanwhile, there is effectively data loss occurring: data that people think is being safely written is, in fact, not available to be used at a later time. Such recent changes to the disk are effectively lost. Of course, this sort of data loss is generally a bad thing.

Consider, though, the alternative. If a “parent/base image”/“backing file” file is allowed to be accidentally written to, then the software in the virtual machine may not report a problem saving data. Furthermore, the data that was recently being written to the single virtual machine being used may be data that will be available in a short or long time in the future. This all sounds like good things. However, in that case, writing to the “parent/base image”/“backing file” causes data loss for other virtual machines (which may not be actively running). Multiple hard drives of multiple other virtual machines may become invalid. Those hard drives may include many changes that are not recent. That could be far more substantial data loss, and because the changes that are lost may be less recent, they may be changes that are more difficult to re-create as needed.

The analogy to physical hardware: Having this happen to offline virtual machines would be like using a physical computer that is turned on, and by writing to the hard drive, also writing to the disk sectors of hard drives of several other computers which may (and, perhaps, probably are) not even powered up. Such a ridiculous concept may not be reasonable to happen with physical hardware, but when this sort of thing happens with virtual machines, the data loss may be chaos.


If a hard drive does get compressed, revoking the permissions to write to the disk is an action that may be best to perform immediately after compressing the disk. The act of revoking such permissions may help to discourage cavalier, non-chalant changes. This is because writing to the disk image would require a bit more effort, because first the write permissions would need to be altered. Since additional data being written might be stored using less optimum compression (very possibly by using no compression) until a full (and time-consuming) compression procedure is performed, it may be preferable not to allow simple little writes to be made to the hard drive image that will serve as a “parent/base image”/“backing file” file. A potential change of substantial size might be worth the efforts to write to the disk, and re-perform the data compression (and then revoking the ability to write the data again). Less substantial changes might be better off being placed into the child/snapshot images instead of the “parent/base image”/“backing file” file. (The changes can then be compressed by compressing the child/snapshot file).

Supporting file integrity data

Keeping an image unchanged will mean that data used with file integrity checks will continue to have the same amount of accuracy, which is great if the data is accurate and up to date. Making changes causes the information to become less accurate, and more out of date. This usually isn't so big of a problem that it ends up being a compelling reason to not make changes, primarily since the file integrity checker's data can simply be updated, but it is a benefit that exists when an image's contents is not changed.

An old, trusted, and read-only file (which might be trusted in part because it is old and read-only) that was once used to verify that files on a “parent/base image”/“backing file” were valid, should still be usable to re-verify the exact same “parent/base image”/“backing file”. This means that large databases of old file verification data may be stored using read-only methods, if desired.

Revoking the write permissions is particularly recommended if there will be any virtual machine that is based on a “child image”/snapshot that was based off of this hard drive image, because the “child image” may require that this “parent/base image”/“backing file” never changes after the “child image”/snapshot is created. So, make file read-only (through file system attributes and/or (security) permissions) to reflect the desire that the image should not be (accidentally) written to.


Directions for this may be specific to the operating system and/or filesystem combination. Some additional information may be available at: File attributes/ownerships/permissions. Any specific directions here may move to another area that discusses handling permissions. For now, however, here is a guide for the command to run when in Unix:

chmod ugo-w just_created_xxGB.hdd

(Naturally, the hard drive image's filename should probably be customized to be better than what was just shown. If the only thing that was done was installing the operating system, then an appropriate filename might be one that includes the name of the just-installed operating system, and also the hard drive's size.)

Use of chown may also be a bit effective, although chown's effects may be more likely to be worked around (accidentally) when a user changes groups for one reason or another.

For Windows, solutions may involve file attributes and/or security permissions.

Any other wrap-up steps
[#avmthen]: After the first virtual machine is made
Moving on

Once the first virtual machine is created, one may wish to move onto another task such as creating another virtual machine, or designing a network of multiple machines (which may or may not involve other virtual machines).

Improving the newly created virtual machine

Another possible task, which may also make a lot of sense to focus on right after taking care of many necessities involved in creating the first virtual machine, would be to consider whether there are other changes to make to the first virtual machine (before moving onto other task(s)). A similar task is to consider whether changes should be made to the host machine.

Perhaps none of these speed features are required to be addressed immediately (although, if some of these features were required by the virtual machine software, then they were already addressed when running the software), although it may make sense to do so now rather than later.

Following simple directions, which are just designed to allow the machine to functionally operate, may not result in a machine which is optimized for speed. It would be unfortunate if a lot of time is spent waiting on a machine which is unnecessarily running three times slower because of a simple configuration issue that could dramatically increase the speed. Checking into the speed is especially recommended after making the first virtual machine, because some changes might result in improvements for not only the original virtual machine, but all virtual machines.

Here are some things to check.


Did the system seem wretchedly slow? If so, or when some spare time is available, consider checking into one or more of the following.

  • Does the processor support hardware-assisted virtualization settings? Can hardware-based “data execution prevention” (specifically AMD's “no execute” (“NX”) bit, or Intel's equivilent “execute disable” (“XD”) bit)? If so, are the benefits of such features unavailable just because of a BIOS setting (on the host machine which runs the virtualization software)?
  • Was the virtual machine (guest operating system) given a low amount of memory while the virtual machine software is running on a system with tons of free memory?
  • Are there some fundamental changes that may be made in the software? This may be discussed in the section about available options of virtual machine software. For example, Qemu speed options discusses changes that can be made with Qemu. Some changes may be more involved, while others may be as simple as changing an option (such as by adding a command line switch). (The reason for such an option may be some potential disadvantages to running the faster version of the code, such as the code being less compatable in certain situations. The expectation may be that end users read about the options on how to speed things up, so that end users are then aware of any potential documented pitfalls from attempting to do things the fast way.)
  • Might there be some other virtual machine software that runs more efficiently? To consider this, check out the available options of virtual machine software. Note that switching to different virtual machine software may be painless or multi-step. If the another piece of virtual machine software requires that disk images are in a different format, then conversion of the disk images may be required. Additionally, the other virtual machine software may be emulating a different set of hardware, which may cause some pain if an installed operating system only included some fairly specific drivers.
Other items to decide for a network of virtual machines

After a single virtual machine has been created, the process can basically be repeated for other virtual machines. Note that much of the process can be streamlined. An existing hard drive image can become a “parent/base image”/“backing file” of snapshot/child images, which can negate the need to install an operating system again. Some steps that were needed when creating the first virtual machine, like configuring a virtual network interface on the host machine that is running the virtual macines, may already be done. The process might be as streamlinable as making sure these major steps are taken:

  • Create the configuration of a new virtual machine. (With at least some software, this could just mean copying a script file that will then be edited.
  • Make sure that a different hard drive image is used.
  • Make sure that a unique MAC address is assigned.
  • Give the system a new name, so that it isn't quite so confused with an already-existing system.
    • Places to consider checking for names for names: DNS; Is there a PID file being used?
Deciding on, and documenting, ranges of network addresses

To do things in a structured, ordered approach, see Multiple Virtual Machine tutorial: Deciding on, and documenting, ranges of network addresses.

The alternative may be to assign some addresses more haphazardly, but then there may be a need to later renumber the IP network addresses. For any serious effort (like making something reliable for a business), or if there are going to be more than just a few virtual machines, do take the time to consider what network addresses to use.

Next actions

If there were recommended actions related to the first image that haven't yet been taken, go ahead and take those. This is referring to shutting down the newly installed operating system, compressing the disk image if desired, and adjusting permissions. (See compressing a virtual machine's disk image if applicable.)

Right after an operating system was installed, before starting the virtual machine, consider whether all the settings are still the desired and correct settings. Typically a virtual machine's configuration will match the last accepted/used configuration. One configuration which is likely not set to the desired configuration is the boot process. When installing an operating system, the virtual machine may be configured to boot off of media other than the hard drive. After the operating system is installed, the usual media to boot off of is often the hard drive, or perhaps by using some other method which may differ from the method used when installing the operating system.

Also, while the machine is off, it may make sense to check other settings. For instance, giving the system a slightly small amount of memory might be tolerable when installing the operating system. However, on an ongoing basis, it will likely be desirable for the system to run decently fast. Also, some additional software might be installed that increases the system's requirements for a pleasant experience. Checking those settings one last time, before starting the system, may be worthwhile since the change might be more convenient/feasible to make while the system isn't actively running.

One thing in particular when running a virtual machine right after an operating system was installed is that the order (or even existance) of boot devices will probably need to be changed. (It may be good to keep the operating system CD in the CD drive, at least for the first mount, in case other items need to be installed to the hard drive. Also, if the install files are going to be copied on the local hard drive, it will be desirable to have the CD in the drive.) If the script for the new machine was created by copying the script used for another machine, and then changing a lot of details in order to customize things for the new machine, then don't forget to check the boot order of devices. (The harm in failing to do so is likely a minimal but existant waste of time since most operating system installation boot media will prompt the user before performing destructive activities. Even if the boot media is destructive automatically, the harm may be minimal if the image being used is a new child image. But either way, it is a waste of time that is best avoided.)

Create a new virtual machine
(This information has been moved to the “Creating a new virtual machine (after one already exists)” section of multiple virtual machines.)
Before running the new virtual machine

(Information from this section has been moved to the “Before running the new virtual machine” section of the multiple virtual machine guide.)

Make some decisions

After making the first virtual machine, there are some decisions that will be nice to have made for a network. (Information from this section has been moved to the “Make some decisions” section of the multiple virtual machine guide.)

Knowing the environment
It may be helpful to know a bit about the operating system's startup procedure. e.g.: In OpenBSD, commands may be added to “/etc/rc.local”. further details should be added to the section about operating systems/startup section(s): see OS info, System startup procedures.
[#cfgnwsys]: Configuring the remote machine

This machine will probably require a fair amount of steps to be taken. For example, the desired automatic addressing won't be available if that service is meant to be provided by this machine or by a snapshot/child image that is based off of this machine.

There are some desired first steps other than enabling remote access. For example, some are related to security purposes. Making sure the virtual machine is protected (through firewalling or other methods) is a top priority. The very next step is quite likely going to be to make sure an instance of the virtual machine is running. Go ahead and run the virtual machine.

Once the machine is running, one may wish to check that the virtual machine is running and review the sections, if needed, on interacting with the output displayed by the virtual machine (including Creating a port forwarding rule using SSH).

Quite a bit of information was here but has started to be moved to setting up a new operating system.

Supporting shutdown options

There are multiple options provided by the section on shutting down a computer.

Other user interface customizations
Command line experience improvements

Become familiar with the command line history features (see Human interface details: section on “Command line history”). If changes need to be made, make them. (Also, become familiar with tab completion features.) See also: Human interface details: section on “Copying files (with progress indicators)” and Human interface details: section on “Displaying files (using color to do so)”

Preparing the machine's files for use by child/snapshot images

(Information from this section has been moved to the “Preparing the machine's files for use by child/snapshot images” section of the multiple virtual machine guide.) There are steps that may be taken, and may be sensible to take even after creating just a single virtual machine. However, since the benefits tend to be when using multiple virtual machines, the information is in that guide.

[#evmcfghd]: Wrapping up the initial setup of the hard drive image (a.k.a.: end virtual machine configuration of the hard drive image)

It may now be wise to follow the general steps of handling some final preparations for an image to be used as a “parent/base image”/“backing file”. (Those steps may also have been performed right after installing the operating system. One difference between checking and performing those preparations at this time, compared to doing that task right after installing the operating system (if a child image as done at that time) is that file integrity checking may be more likely to be a task that is sensible to be performed, rather than skipped. The file integrity checking doesn't need to be done again, though, if it was just done after any other changes were made.)

Compress image

If compression is desired for a virtual machine, compressing a virtual machine's disk image has further details.

Reviewing the whole setup so far
  • Does any program (such as a Qemu virtual machine, for example) write to PID files in a directory under /var/run/ which gets removed when the system reboots?
    • If so, does the operating system re-create such a directory when it starts up, and does it do so before running a program that should be putting a PID file in that location?
    • If the directory is re-made, are permissions sufficient for the virtual machine to be created?
  • If any of these checks reveals problems, those problems should be handled before any virtual machines are started. There may be a good desire to have that be handled automatically when the system is started up. Having these issues being addressed/fixed in the system's startup process is a fine idea. However, if a virtual machine is started automatically as part of the host machine's startup process, these problems will need to be handled even earlier in the sequence of events that get performed automatically when the host machine starts up.
Moving onto the next machine

A lot of the process is going to be similar to preparing the “parent/base image”/“backing file”. For example, document the machine, create a child image, and once the image is started, customize credentials and things like the machine name. Several of the steps will be able to go faster: installing software typically used on machines is a step that will be largely done because the software will already be installed on the virtual machine.

This guide will be using an example of having one machine which is used for an automatic network addressing server, one machine which is used for a name server, and another machine which is used for firewalling/routing traffic. All of these services could operate on a single virtual machine. However, for very large organizations, even just one of those services may require such resources that just one machine is, individually by itself, not enough to sufficiently handle the resource. Showing how to get all of this working on separate machines is the more complex scenario, because having traffic being allowed (well enough for processes to work) is more likely to require special setup compared to storing everything on one machine.

Further details on performing multiple tasks may be covered by the guide to making a network consisting of multiple virtual machines.