BSD

How To Create, Configure And Connect To A FreeBSD Instance In Amazon EC2

(20180108 – The steps in this post were amended to address changes in the Amazon AWS service — iceflatline)

FreeBSD is an free and open source advanced computer operating system used to power modern servers, desktops and embedded platforms.

Amazon Elastic Compute Cloud (“EC2”) provides resizable computing capacity in the Amazon Web Services (“AWS”) cloud. Amazon EC2 can be used to launch as many or as few virtual servers as you need, configure security and networking, and manage storage. An Amazon Machine Image (AMI) is a template that contains a software configuration (for example, an operating system, an application server, and applications). From an AMI, you launch an instance; virtual servers that can run applications. Instances feature varying combinations of CPU, memory, storage, and networking capacity, and give you the flexibility to choose the appropriate mix of resources for your applications.

This post describes how to create and configure a FreeBSD instance in Amazon EC2. Then goes on to explain how to connect to the new instance using SSH from a machine running a BSD, Linux or Windows operating system.

The steps discussed in this post assume you have an active AWS account. If you do not, you can sign up for one at Amazon Web Services.

Let’s get started…

Create and Configure the FreeBSD Instance

Fire up your web browser and navigate to Amazon Web Services. Login to the AWS Management Console by selecting “AWS Managment Console” from among the options in the drop down list under “My Account” (See Figure 1).

Screenshot showing how to find the Amazon AWS Management Console

Figure 1

Once you’ve successfully logged in, select “EC2″ from among the options listed under the “Services” section (See Figure 2).

Screenshot showing the EC2 option in the Amazon AWS Management Console

Figure 2

Next you’ll choose the Amazon EC2 “region” under which the FreeBSD instance will be created. In this example we’ll select the US West (Oregon) region (See Figure 3).

Screenshot showing the selection of an Amazon region where the FreeBSD instance will be created

Figure 3

Now select “Instances” from among the options under the “Instances” category on the left side of the page. If this is the first time you’ve created an instance in this Amazon EC2 region you’ll be greeted with a message indicating “you do not have any running instances in this region” and a button to launch one (See Figure 4).

Screenshot showing the Amazon AWS EC2 launch instance screen

Figure 4

Select “Launch Instance” and you’ll be greeted with Amazon’s quick start guide for creating a new AMI. Select “AWS Marketplace” from among the choices on the left side of the web page where you will be offered the ability to search for and select an AMI. Simply search for “freebsd” and you will presented with several FreeBSD image options (See Figure 5).

Screenshot showing search results for a FreeBSD AMI

Figure 5

In this example we’ll select the “FreeBSD 11” AMI, where we’ll be presented with some product details, including instance pricing. Select “Continue” where you’ll be asked to choose an instance type. Amazon EC2 provides several instance types optimized to fit different use cases. In this example we’ll use the recommended m4.large instance. (See Figure 6).

Screenshot showing the selection of a Amazon m4.large instance

Figure 6

Select “Next: Configure Instance Details” where you will be presented with a list of default options that can be modified, if desired, to better suite your needs. Hovering your mouse over the “i” icon near an option will describe its purpose in greater detail. One option that may prove helpful is the termination protection. Enabling this option will prevent the instance from being accidentally “terminated” (i.e., deleted). If enabled, you will not be able to delete the instance through the AWS Management Console until this option is once again disabled. For our example, however, we’ll simply retain the default options (See Figure 7).

Screenshot showing the configuration of the default Amazon EC2 instance options

Figure 7

Now select “Next: Add Storage” where you can adjust the size of the default or “root” Elastic Block Store (“EBS”) volume. You can also attach additional EBS volumes to your instance, or edit the settings of the root volume. You can also choose to delete the volume should you decide to terminate the instance. For our example, we’ll retain the 10GB root EBS volume and all default settings (See Figure 8).

Screenshot showing the Amazon EC2 EBS storage volume configuration options

Figure 8

After configuring storage, select “Next: Add Tags” where you be given the option of creating a “Tag” for your instance (See Figure 9). Tags enable you to categorize your AWS resources in different ways, for example, by purpose, owner, or environment. Each tag consists of a key and a value, both of which you can define. Uniquely tagging instances can be beneficial, particularly if you plan on creating many of them. Again, this is an optional step, and since we’re creating a single instance, we’ll forgo tagging and move on to the next step: Configure Security Group.

Screenshot showing the Amazon EC2 instance tagging option

Figure 9

A security group is a set of firewall rules that control the traffic for your instance. For example, if you want to set up a web server and allow traffic to reach your instance, you would add rules that permit unrestricted access to HTTP and HTTPS ports. You can create a new security group or select from an existing one. In this example, we would simply like to connect to the new FreeBSD instance using a secure shell (SSH) so there is no need to create a new rule as one already exists for SSH by default. However, you may wish to filter incoming SSH connections to your FreeBSD instance. If you’d like to connect from any network, then simply retain the select “custom” from among the options in the drop down list under “Source”, else you can limit incoming connections to the IP your currently using or to a custom IP address or IP subnet. For this example, we’ll allow incoming SSH connections on port 22 from anywhere (See Figure 10).

Screenshot showing the configuration of security group rules in Amazon EC2

Figure 10

When complete, select “Review and Launch” where you’ll be given one last opportunity to modify your settings. If everything checks out select “Launch” where a pop up screen will provide the opportunity to select an existing key pair or create a new key pair. A key pair consists of a OpenSSL public key, which Amazon AWS retains and copies to your instance, and a private key that you download and retain. Together, they allow you to connect to your FreeBSD instance securely using SSH. If this this is first time you’ve created an instance you’ll likely not have an existing key pair from which to chose. If this is the case, select “Create a new key pair” from among the options in the drop down list and enter a name for your new key pair. In this example we’ll use the name “ec2-or-freebsd.” Now select “Download Key Pair” and save the file in a secure and accessible location (See Figure 11).

Screenshot showing the creation of a new key pair in Amazon EC2

Figure 11

Next, select “Launch Instances”, followed by “View Instances” and you’ll be taken to a page showing your FreeBSD instance launching. After a minute or two, the “Instance State” will change from “pending” to “running” (See Figure 12). You can stop your instance by selecting “Stop” from among the options in the drop down list under “Actions” located at the top of the page.

Screenshot showing a running FreeBSD instance in Amazon EC2

Figure 12

Finally, let’s get the public IP address of our FreeBSD instance. Select “Connect” at the top of the instance page and make a note of the public IP address assigned to your instance (See Figure 13). Note that the instance will be assigned a new public IP address if you stop it and restart it. If you want to avoid this situation then consider using an Elastic IP address. If you simply reboot the instance from within the operating system it will retain the same public IP addresses.

Screenshot showing the public IP address assigned to this FreeBSD instance n Amazon EC2

Figure 13

Connect to the instance from Windows

Now that we have our new FreeBSD instance up and running under Amazon EC2 let’s turn our attention to connecting to it using SSH under Windows. Since Windows doesn’t typically support SSH, we’ll need an SSH client. There are many out there to choose from, but the one we’ll use in this example is PuTTY, a free implementation of Telnet and SSH for Windows and Linux/BSD platforms.

PuTTY does not natively support the private key format *.pem generated by Amazon EC2, so we’ll also need a way to convert this key file to a key format that the PuTTY application can use. For this we’ll use PuTTYgen, a free key generation utility, which can convert keys to *.ppk, the file format required by PuTTY. You can download standalone versions of PuTTY and PuTTYgen, or simply download the Windows installer version of PuTTY, which will also install PuTTYgen, as well as Pageant, an SSH authentication agent for PuTTY.

Fire up PuTTYgen and select “Load”. Navigate to where you downloaded the ec2-or-freebsd.pem file and select “Open” (Note: you may have to change the search filter from “PuTTY Private Key Files (*.PPK)” to “All Files (*.*)” in order to readily locate the file). Once ec2-or-freebsd.pem has been successfully loaded into PuTTYgen, you can modify the “Key comment” field if desired, as well as add a passphrase to protect your private key. Electing not to means that anyone gaining access to your private key will also quite easily be able to access your FreeBSD instance. Once complete select “Save private key” and select a name (for this example, we’ll use the same name: ec2-or-freebsd) and a location to save the new key file (See Figure 14).

Screenshot showing the creation of a ppk file in PuTTYgen

Figure 14

Exit out of PuTTYgen and fire up PuTTY. Navigate to Connection->SSH->Auth. Under Authentication parameters select the Browse button and select the ec2-or-freebsd.ppk file you saved in the previous step. Navigate back up to Session. You’ll connect as “ec2-user” so prepend this user name to the public IP address assigned to your instance so that the entire field looks like this: “ec2-user@”. If you chose a different SSH port number other than the default 22 when setting up your instance’s security group, ensure that number is reflected in the “Port” field.

Now select “Open” and the PuTTY client will connect to your FreeBSD instance. If this is the first time you’ve connected to it, you’ll receive a warning concerning the authenticity of the host you’re trying to reach. If you’re sure this is the correct instance and you want to continue connecting, select “Yes” to add the key to PuTTY’s cache and carry on connecting. If you want to carry on connecting just once, without adding the key to the cache, select “No”. You’ll be asked to provide the passphrase (if you created one) for your private key and you’ll be connected to the instance.

Connect from FreeBSD or Linux

Connecting to your FreeBSD EC2 instance via SSH is significantly easier in FreeBSD or Linux. Start by checking to see if the .ssh directory exists in your home directory. If it does not, create it and set it’s permissions appropriately:

Now move the ec2-or-freebsd.pem file you downloaded to ~/.ssh and modify its permissions appropriately:

As an optional security step you can add a passphrase to your key:

Now let’s connect to our FreeBSD instance:

If you chose a different port number than the default when setting up the instance’s security group, then you’ll need to specify that on the command line as well:

If this is the first time you’ve connected to it, you’ll receive a warning concerning the authenticity of the host you’re trying to reach. If you’re sure this is the correct instance and you want to continue connecting type “yes” at the prompt. The public key of your FreeBSD EC2 instance will be added to ~/.ssh/known_hosts and you will be connected.

Conclusion

Well, that’s it. With a little effort you can easily create, configure and connect to your own FreeBSD instance in Amazon EC2. Now that you know that your *.ppk and/or *.pem private key works, you should back it up to offline media such as a flash drive or CD and keep it someplace secure. I also strongly recommend that you create a password for the user root in your FreeBSD instance(s).

Issues to note

Amazon does not provide a easy way to verify the key fingerprint – the one listed in the EC2 Management Console. I did manage to find this rather obscure command that will work from FreeBSD and Linux, but I have yet to find an easy way to perform this task under Windows, outside of installing and setting up the the Amazon EC2 command line interface tools.

References

http://aws.amazon.com/documentation/ec2/

http://www.daemonology.net/blog/2017-10-21-FreeBSD-EC2-community-vs-marketplace-AMIs.html

Networking

How To Create And Configure VLANs In pfSense

(20171231 — The steps in this post were amended to address changes in recent versions of software. Minor editorial corrections were also made — iceflatline)

pfSense is a customized version of FreeBSD tailored specifically for use as a perimeter firewall and router, managed entirely from a web browser or command line interface. pfSense includes a long list of other features, as well as a package system allowing its capabilities to be expanded even further. pfSense is free, open source software distributed under the BSD license.

A VLAN (“Virtual Local Area Network”) is a logical grouping of network hosts (and other resources) connected to administratively defined ports on a switch. This enables hosts to communicate as if the attached to the same physical medium, when in fact they may actually be located on different LAN segments. A VLAN is treated like its own subnet or broadcast domain, which means that Ethernet frames broadcast onto the network are only switched between the ports logically grouped within the same VLAN.

In this post I will describe how to create and configure a VLAN in pfSense. Once configured, you’ll be able to route (or prevent routing) traffic between this VLAN and other VLANs, and each VLAN will be able to share the same Internet connection. To help explain the steps involved, we’ll create a static VLAN on a 24-port switch and trunk that VLAN from the switch to the LAN interface on pfSense, where we will assign the VLAN a unique /24 private IP subnet.

All steps involved assume that: 1) pfSense is installed correctly and providing basic Internet connectivity to an existing LAN interface; 2) the NIC (“Network Interface Controller”) assigned to the LAN interface supports IEEE 802.1Q VLAN tagging; and, 3) the switch connected to the LAN interface is capable of supporting the creation, configuration and trunking of port-based VLANs.

The software versions used in this post were as follows:

  • 2.4.2-RELEASE-p1 (amd64)

The switch used in this post was a Cisco model SG200-26; a so-called “smart switch,” featuring, among other things, Gigabit Ethernet, a web-based management interface, and simultaneous support for up to 256 port-based and IEEE 802.1Q tag-based VLANs.

Each switch, and its associated management interface is different; therefore, you’ll need to make the appropriate adjustments when following the instructions in this post in order to successfully configure your particular switch.

Let’s get started…

Configuring the Switch

As you may recall, static VLANs, often referred to as “port-based” VLANs, are created by assigning switch ports to a preconfigured VLAN identifier. In this example, we’ll configure a static VLAN on our switch and assign it VLAN ID 50. Note that you can use any positive integer between 2 and 4094 you’d like for your VLAN ID, however, VLAN IDs 1 and 4095 should be avoided because, as a general rule, most switches by default assign all ports to VLAN ID 1, the “administrative” VLAN ID, and VLAN ID 4095 as the “discard” VLAN.

Begin by navigating to VLAN Management->Create VLAN and select “Add.” Enter a value of 50 in the “VLAN ID” field and enter a name to denote this particular VLAN in the “VLAN Name” field. In this example, we’ve used the name “vlan50.” When complete, select “Apply”. (See Figure 1)

Screenshot showing the creation of a new VLAN ID 50 in the Cisco SG200-26 switch

Figure 1

Before assigning membership of a particular port to our new VLAN, we must first configure that port to be either an “Access” port or a “Trunk” port. Access ports are ports that are members of only one VLAN. This type of port is normally used for attaching end devices which are generally unaware of a VLAN membership, either because their NIC is incapable of tagging Ethernet frames a VLAN ID, or they are not configured to do so. Switch ports configured as Access ports remove any VLAN information from the Ethernet frame before it is sent to the device. Trunk ports on the other hand can carry multiple VLAN traffic, and are normally used to connect switches to other switches or to routers. It is very often the case that small-business grade switches, such as the Cisco SG200, designate each port as a Trunk port by default.

To keep our example simple, we’ll assume that the device(s) connected to the switch are not configured, or are unable to be configured, to tag Ethernet frames with a VLAN ID. Consequently, in this example, we’ll configure port 19 as an Access port, and assign it membership in our newly created VLAN. Furthermore, we’ll also assume that port 25 is currently being used to connect the switch to the pfSense LAN interface, and configure it as a Trunk port, assigning it membership in our newly created VLAN.

Navigate to VLAN Management->Interference Settings, select port 19 and then select “Edit”. Change the Interface VLAN Mode from Trunk to Access, then select “Apply” (See Figure 2). Now follow similar steps to configure port 2 as an Access port.

Screenshot showing port 19 being configured as an Access port in the Cisco SG200-26 switch

Figure 2

Next, navigate to VLAN Management->Port VLAN Membership, select port 19 and then select “Join VLAN”. Since Access ports can be added as untagged to only a single VLAN, we’ll need to first remove the default VLAN the switch automatically assigns to each port (usually VLAN 1). Highlight VLAN 1 by left-clicking on it, then select the arrow icon to remove it from the interface. Now highlight VLAN 50 by left-clicking on it, then select the arrow icon to add it to the interface, ensuring that “Untagged” is selected from among the options under “Tagging”. Select “Apply” when completed (See Figure 3).

Screenshot showing port 19 being joined to VLAN 50 in the Cisco SG200-26 switch

Figure 3

With switch port 19 configured as an Access port and joined to VLAN 50 any Ethernet frames that enter that port will be tagged with the appropriate VLAN ID. Now let’s configure the port 25, the port that is connected to the LAN NIC in pfSense. This port will be configured as a Trunk port and joined to VLAN 50 so that, in addition to passing the Ethernet frames from from devices attached to the other ports on the switch to pfSense, it will also pass Ethernet frames tagged with VLAN ID 50 entering switch port 19.

Ensure that port 25 is configure as a Trunk port, then navigate to VLAN Management->Port VLAN Membership, select port 25 and then select “Join VLAN”. Highlight VLAN 50 by left-clicking on it, then select the arrow icon to add it to the interface, ensuring that “Tagged” is selected from among the options under “Tagging”. Select “Apply” when completed (See Figure 4).

Screenshot showing port 25 being joined to VLAN 50 in the Cisco SG200-26 switch

Figure 4

That’s it for configuring the switch. If your switch supports both a running configuration and a startup configuration, make sure to save the changes you’ve made to the startup configuration so that they are not lost should the switch reboot for any reason.

Configuring pfSense

Now we need to create and configure VLAN 50 in pfSense. Navigate to Interfaces->Assignments and make note of the device driver name assigned to the LAN NIC. For this example we’ll assume the device driver name is “em1” (See Figure 5). The LAN interface will serve as the “parent interface” for the VLAN interfaces we will create in the next step.

Screenshot showing the device driver name assigned to the LAN NIC in pfSense

Figure 5

Next, navigate to Inerfaces->Assignments->VLANs and select the “+ Add” icon. In the subsequent screen, select “em1”, the LAN NIC interface, from among the options in the drop down list under “Parent interface”, and enter the value of 50 under “VLAN tag”. Add an optional description for this VLAN under “Description”, then select “Save” (See Figure 6).

Screenshot showing the configuration of a VLAN interface in pfSense

Figure 6

After creating the VLAN interface, return to Interfaces->Assignments and select the “+ Add” icon to add the “VLAN 50 on em1-lan (VLAN 50)”, then select “Save” (See Figure 7). At this point you’ll notice that under the “Interface” column pfSense has likely denoted VLAN 50 as an optional or “OPT” interface. Don’t worry, we’ll address that next.

Screenshot showing the addition of a VLAN interface in pfSense

Figure 7

For this example we’ll assume that pfSense has assigned VLAN 50 as OPT4. Navigate to Interfaces->OPT4 and select “Enable Interface”. Under “Description” replace “OPT4” with “VLAN 50”, then select “Static IPv4” from among the options in the drop down list under “IPv4 Configuration Type”. We’ll use network 192.168.50.0/24 for VLAN 50 by assigning the static IP address 192.168.50.1 on this interface, and selecting the network mask of “24” under the “Static IP Configuration” section. The other parameters can remain at their default values. Select “Save” and “Apply changes” when complete (See Figure 8). Now if you navigating back to Interfaces->Assigments you will see VLAN 50 listed and labeled with the description you added when enabling the interface in the previous steps.

Screenshot showing the VLAN 50 interface being enabled in pfSense

Figure 8

Next, we need to build a firewall rule for our two new VLANs so that traffic can pass to / from the WAN interface, and by extension, to the Internet. Navigate to Firewall->Rules and select the VLAN 50. Select the “Add” icon (there are currently no rules so either Add icon will work) to create a new rule. For our example, we’ll build a simple outbound pass rule for any protocol in VLAN 50, similar to the way a typical LAN outbound pass rule would be configured. Select “any” from among the options in the drop down list Under “Protocol”, and under “Source” select “VLAN50 net” from among the options in the drop list. If desired, you may enter a description of this newly created rule for your reference under “Extra Options”. The other parameters can remain at their default values. Select “Save” and “Apply changes” when complete (See Figure 9).

Screenshot showing the creation of a firewall rule for VLAN 50 in pfSense

Figure 9

Unless you plan to assign static IP addresses to host devices, you’ll want to configure a DHCP server for the new VLAN 50. Navigate to Services->DHCP server and select VLAN 50. Select “Enable DHCP server on VLAN50 interface”, then enter the range of IP addresses within the network 192.168.50.0/24 you’d like the DHCP server to use under “Range”. Finally, pfSense will use the IP address assigned to this interface as the gateway address by default. For our example this address will be 192.168.50.1. If your requirements call for something different, enter an IP address for the network gateway under “Gateway”. The other parameters can remain at their default values. Select “Save” when complete (See Figure 10).

Screenshot showing the creation and configuration of a DHCP server for VLAN 50 in pfSense

Figure 10

You’ll also want to navigate to Services->DNS Forwarder->Interfaces and ensure that interfaces used by the DNS Forwarder for responding to queries from clients includes VLAN50, then select “Save” and “Apply changes” when complete (See Figure 11).

Screenshot showing the inclusion of the VLAN 50 interface in the DNS Forwarder in pfSense

Figure 11

Wrapping up

At this point the LAN switch and pfSense should be configured to support VLAN 50. To test, connect a host device such as a desktop or laptop computer to port 19 on the switch. If you’ve configured everything as described, you should receive an IP address within the DHCP address range you’ve specified for VLAN 50 network 192.168.50.0/24. The default gateway, DHCP server and DNS server addresses should be 192.168.50.1. You should also have Internet connectivity.

Be aware that as currently configured, each VLAN is routed to all other VLANs. If you would like to disallow some or all traffic to/from a particular VLAN you must create firewall rules explicitly stating what traffic should not be routed. Keep in mind that pfSense evaluates firewall rules on a first-match basis (i.e. the action of the first rule to match a packet will be executed). So, for example, if you wanted to block all VLAN 50 traffic from reaching the LAN you might create a rule to that effect before the one we created previously to route all VLAN 50 traffic to any destination (See Figure 12).

Screenshot showing the placement of a firewall rule blocking all traffic in VLAN 50 from reaching the LAN in pfSense

Figure 12

Conclusion

VLAN support in pfSense is not hard to configure nor complicated to manage, assuming your switch and NICs support this capability. To help explain the steps involved, we created a static VLAN on a commodity 24-port small-business switch and trunked that VLAN to the LAN interface on pfSense. We then created and added the VLAN interface, created the requisite firewall rules, and assigned the VLAN a unique /24 private IP subnet with host addressing handled using DHCP. The VLAN is able to share the pfSense’s Internet connection and we are able further configure pfSense to prevent routing traffic between each VLAN, if desired.

Networking

How To Access Your VirtualBox Guest VM From The Host Using SSH

(20180430 — The steps in this post were amended to address changes in recent versions of software — iceflatline)

Recently I had the occasion to spin up a Ubuntu server Virtual Machine (“VM”) in VirtualBox on a Windows-based host machine. Those of you who have performed a similar excercise know that the default window size that VirtualBox provides to command-line-based VMs, like *BSD and Ubuntu server, etc., is rather small, somewhere in neighborhood of the standard VGA resolution of 640 x 480 pixels. Normally the fix for this, of course, would be to install what VirtualBox calls “Guest Additions,” which consists of device drivers and other applications that optimize the guest operating system for, among other things, the ability to enlarge the window size. However, getting Guest Additions to install and run properly on command-line-based guest VMs is a monumental pain in the ass. One work-around that seems to work fairly well is to switch the VM window to “scale mode” (View->Switch to Scale Mode or Host+C), resulting in what is essentially a magnified version of the window and its contents. An even better solution, in my opinion, is to configure the VM so that you can connect to it directly from the host machine using Secure Shell (“SSH”), giving you full control over the window and text size of the guest VM.

This post explains how to access a VirtualBox Ubuntu server guest VM from the VirtualBox host machine using SSH. It then goes on to explain how to accomplish the same task when using a FreeBSD guest VM. The software versions used in this post were as follows:

  • FreeBSD 11.0-RELEASE
  • Ubuntu Server 18.04 LTS
  • VirtualBox 5.2.6

Let’s get started…

First, let’s add a new “VirtualBox Host-Only Ethernet Adapter” in VirtualBox. This new adaptor will allow us to enable a private network consisting of our host machine and our guest VM. The host can connect to any guest VMs configured to use this adaptor, and they can connect to each other, but nothing outside of this virtual network will be permitted access.

Navigate to Files->Preferences->Network and click on the “+” icon to add new adaptor. You’ll see that VirtualBox creates a new adaptor called “VirtualBox Host-Only Ethernet Adapter #2” (See Figure 1).

Screenshot showing the creation of a VirtualBox Host-Only Ethernet Adapter in VirtualBox

Figure 1

Right now you might be thinking “but couldn’t I just use the existing default VirtualBox Host-Only Ethernet Adaptor?” You absolutely could; however, setting up a second one allows you to customize it to your liking, leaving the default adaptor in its default configuration as a fallback.

Now, double-click the new adaptor (or highlight it and select the edit icon) and note the IP address and subnet mask (e.g., 192.168.135.1 and 255.255.255.0) that VirtualBox has arbitrarily assigned under the “Adapter” tab. You may change these network parameters if desired, however, it is preferable to retain “1” as the value of the last octet in the IP address (See Figure 2).

Screenshot showing the IP address and subnet mask assignment in the VirtualBox Host-Only Ethernet Adapter #2

Figure 2

Optionally, you may configure a DHCP server on the VirtualBox Host-Only Ethernet Adapter #2 so that the guest VM obtains an IP address automatically at boot time. This can be accomplished by navigating to Files->Preferences->Network, double-clicking the new adaptor (or highlighting it and selecting the edit icon), selecting the “DHCP Server” tab and the selecting “Enable Server”. You’ll then need to modify the various DHCP server parameters (e.g., Server Address, Server Mask, etc.), keeping in mind that they should encompass the IP address configured for the adaptor, else the IP address should be modified so that it lies within the DHCP server parameters you’ve configured. When finished, select “OK” (See Figure 3). Note: I typically forgo using the DHCP server, electing instead to use a static IP address. That way, I can consistently use the same address each time I want use SSH to connect to the guest VM.

Screenshot showing the DHCP server configuration tab in the VirtualBox Host-Only Ethernet Adapter #2

Figure 3

Let’s configure our Ubuntu server VM so that it will use the new VirtualBox Host-Only Ethernet Adapter #2. Shutdown the Ubuntu server VM if it’s running. Right-click on the VM and select Settings->Network. Select the “Adapter 2” tab, then select “Enable Network Adapter”. From among the options under “Attach to:”, select “Host-Only Adapter”, then select “VirtualBox Host-Only Ethernet Adapter #2” from among the options under “name:”. Now select “OK” (See Figure 4).

Screenshot showing the selection of VirtualBox Host-Only Ethernet Adapter #2 for use by the Ubuntu server virtual machine

Figure 4

Now start the Ubuntu server VM. After the system has fully booted, login to the VM at the VirtualBox console window and execute the command ifconfig -a to list all network devices. In addition to your primary network device, enp0s3 (in this example), you should now see a second network device listed, enp0s8 (in this example). If you chose to setup a DHCP server when creating VirtualBox Host-Only Ethernet Adapter #2, then enp0s8 should already have an IP address assigned to it from among the pool of addresses you chose to use with setting up the DHCP server, in which case you should make a note of this address and use it to connect to the Ubuntu server VM using SSH.

If you elected not to setup a DHCP server when creating VirtualBox Host-Only Ethernet Adapter #2, then you’ll need to assign a static IP address to network device enp0s8. First, install the package ifupdown:

Then open /etc/network/interfaces as the root user and add the following lines, making sure to change the values shown in this example so that they fall within the IP subnet parameters chosen when creating the new VirtualBox Host-Only Ethernet Adapter #2:

Now start the interface so that it obtains the new network parameters:

At this point you should be able to connect to the Ubuntu server VM via SSH using this static IP address.

FreeBSD Guest VM

A similar approach can be taken for a FreeBSD guest VM. The setup and configuration of the VirtualBox Host-Only Ethernet Adapter in VirtualBox is identical to what has been described thus far for the Ubuntu server VM. However, in order to assign a static IP address to the new network interface, em1 in the case of FreeBSD, you’ll need to open /etc/rc.conf as the root user and add the following line, making sure to change the values shown in this example so that they fall within the IP subnet parameters chosen when creating the new VirtualBox Host-Only Ethernet Adapter #2:

Then restart the interface so that it obtains the new network parameters:

Conclusion

The default window size that VirtualBox provides to command-line-based guest VMs like BSD and Ubuntu servers is typically very small, resulting in a poor user experience for those administrators trying to perform work beyond just a few quick simple commands. Fortunately, VirtualBox can be configured so that the user can connect directly to a guest VM from the host machine using SSH, giving the user full control over window and text sizing.

BSD

How to Create and Maintain a ZFS Mirror in NAS4Free

NAS4free is an open source NAS (“Network Attached Storage”) platform based on FreeBSD that supports file sharing across Windows, Apple, and UNIX-like systems. Support for ZFS, Software RAID (0,1,5), disk encryption, S.M.A.R.T, email reports, CIFS FTP, NFS, TFTP, AFP, RSYNC, Unison, iSCSI, HAST, CARP, Bridge, UPnP, and Bittorent, are among its many features – all configurable through its GUI interface. NAS4Free can be installed on Compact Flash or USB flash drive, hard disk or booted into a “LiveCD” environment. NAS4Free code and documentation are released under the Simplified BSD License.

The ZFS (“Zetabyte File System”) is a combined file system and logical volume manager designed by Sun Microsystems. The features of ZFS include protection against data corruption, support for high storage capacities, snapshots and clones, continuous integrity checking and automatic repair. ZFS is implemented as open-source software, licensed under the Common Development and Distribution License (CDDL).

This post will describe how to setup a simple, yet resilient, ZFS-based RAID 1 (ZFS mirror) in NAS4Free. In RAID 1, data is written identically to two disk drives, thereby producing a “mirrored” set. If one disk becomes defective, the remaining disk still contains all the data. To help explain the steps involved, we’ll use two new 2TB (Terabyte) SATA 3.0 hard disks, along with the ZFS utilities available within NAS4Free, to create and configure our ZFS mirror. We’ll also discuss a few post-install activities to help maintain your ZFS mirror. All steps involved assume that the two hard drives have been installed correctly and are recognized by the BIOS, and that NAS4Free is installed and operational. The software versions used in this post were as follows:

  • NAS4Free v9.1.0.1 – Sandstorm (revision 636)

So, let’s get started.

Adding the Disks

The first thing we need to do is logically add the two new disks to NAS4Free so the system acknowledges their existence, permitting further configuration on them. Log in to the NAS4Free GUI (“Graphical User Interface”), navigate to Disks->Management, and select the “+” icon. (See Figure 1).

Screenshot showing the Disk Management page in NAS4Free

Figure 1

In the subsequent page you are presented with the configuration screen for adding new disks. Select the first 2TB disk from the drop-down menu under the “Disk” field, and select “unformatted” from among the options in the drop-down menu under the “Preformatted file system” field. The remaining options on this page can retain their default settings. Now select “Add” (See Figure 2).

Screenshot showing the Disk Management - Add Disk page in NAS4Free

Figure 2

Repeat these steps for the second 2TB disk. When complete, select “Apply changes” (See Figure 3).

Screenshot showing the Disk Management page in NAS4Free indicating that two new disks have been added

Figure 3

Note: If you’re adding disks that have previously been formatted using ZFS, NAS4Free will likely not allow you to add these disks as unformatted. You can, however, add them by selecting “zfs storage pool device” under the “Preformatted file system” field and skip the following formatting step.

Format the Disks

Now that the disks have been added, we need to format them. Navigate to Disks->Format, and select one of the newly added disks from the drop-down menu under the “Disk” field. Select “ZFS storage pool device” from the drop-down menu under the “File system” field, then select “Format disk” (See Figure 4).

Screenshot showing a newly added disk being formatted as a ZFS storage pool device in NAS4Free

Figure 4

Repeat these steps for the second disk, then navigate back to Disks->Management and ensure that both disks are present and formatted as ZFS storage pool devices (See Figure 5).

Screenshot showing two newly added disks formatted as a ZFS storage pool device in NAS4Free

Figure 5

Create a ZFS Virtual Device

We’ve added our two 2TB hard disks and formatted them. Now its time to create a ZFS “vdev” or virtual device.

Unlike traditional file systems, which reside on single devices and require a volume manager to use more than one device, ZFS filesystems are built on top of virtual storage pools called “zpools.” A zpool is constructed of virtual devices, or “vdevs,” which are themselves constructed of block devices: files, hard disk partitions, or entire disks, with the latter being the recommended usage. Block devices within a vdev may be configured in different ways, depending on needs and space available: non-redundantly (similar to RAID 0), as a mirror (RAID 1) of two or more devices, which is the focus of this post, or as a RAID-Z (similar to RAID-5) group of three or more devices.

In summary then, a vdev represents the disk drives that are used to create a zpool. A zpool can have any number of vdevs at the top of the configuration, known as a “root vdev.” If the top-level virtual devices contain two or more physical devices, the configuration provides data redundancy as mirror or RAID-Z virtual devices.

To create a virtual device consisting of our newly added hard disks, navigate to Disks->ZFS->Pools->Virtual device, and select the “+” icon. In the subsequent page, enter a name for the new virtual device under the “Name” field (e.g., “vd_1”), and select “Mirror” from among the options under the “Type” field. Now select both hard disks in the “Devices” field by holding the CTRL key and left-clicking each disk. You can also enter a description for the virtual device under the “Description” field, if desired. Select “Save” when complete (See Figure 6).

Screenshot showing the creation of a ZFS virtual device in NAS4Free

Figure 6

Create a ZFS Pool

Having created our vdev, let’s move on and create a zpool. Navigate to Disks->ZFS->Pools->Management, and select the “+” icon. In the subsequent page, enter a name for the new zpool under the “Name” field (e.g., pool_1). You should see the vdev created previously listed under the “Virtual devices” field. Select the vdev by left-clicking on it. Add a description for the virtual device under the “Description” field if desired. The remaining options can retain their default settings, resulting in the mount point for the zpool becoming /mnt/[your-zpool-name]. Select “Save” when complete (See Figure 7).

Screenshot showing the creation of a ZFS zpool in NAS4Free

Figure 7

Create a ZFS Dataset

At this point you could start using your entire zpool as storage if desired. However, a significant feature of ZFS is the concept of “datasets.” A dataset is essentially a child filesystem of the parent zpool. Imagine that the zpool is a single hard disk. In a typical hard disk you would create a single, disk-sized partition, and then format that partition with a filesystem. But if later you’d like to add additional filesystems to the disk, you have to erase and redo your partition to create more partitions to contain the new filesystems, or use a tool to actively resize existing partition, and then create the new partitions and filesystems.

With datasets, all of these partitioning efforts are unnecessary. A ZFS dataset acts like another mounted partition with no locked-in size. The quantity of disk space it takes up is only as much space as you use in populating it, or children datasets of it (of course, it can never be larger than the size of its parent zpool). You don’t have to worry about resizing partitions as ZFS inherently handles all that for you. Additionally, each dataset can have its own special configuration by modifying different behavioral variables. For example, you can determine quota and permissions independently for each dataset. Finally, datasets provide more flexibility if you need to snapshot or clone your filesystems.

To add a dataset to the zpool, navigate to Disks->ZFS->Datasets->Dataset, and select the “+” icon. Enter a name (e.g., “files”) in the “Name” field (resulting in the mount point for the dataset becoming /mnt/[your-zpool-name]/[your-dataset-name]). Ensure that the zpool created previously is selected from the drop-down list under the “Pool” field. If you’re interested in performing periodic snapshots of the dataset (discussed below), I recommend enabling the “Snapshot Visibilty” option so that the snapshots are added automatically to /mnt/[your-zpool-name]/[your-dataset-name])/.zfs/snapshots. The remaining options can be configured according to your requirements. Select “Add” when complete (See Figure 8).

Screenshot showing the creation of a ZFS dataset in NAS4Free

Figure 8

Wrapping up

We’ve successfully added two new 2TB hard disks to NAS4Free and formatted them, created a vdev and a zpool, and finally, created a dataset within our zpool. At this point you can start enabling services such as CIFS, NFS, UPnP, etc., to take advantage of your new ZFS mirror storage. Remember, when configuring some of these services to select the correct mount point for your dataset (e.g., /mnt/pool_1/files).

With the creation and configuration of our ZFS mirror out of the way, let’s move on talk about a few maintenance activities that should prove useful.

    Replacing a defective hard disk

Occasionally you may have to replace a hard disk in your zpool that has become defective. To perform the replacement, navigate to Disks->ZFS->Pools->Information and note which disk is defective or missing (e.g. ada2). Next, navigate to Disks->ZFS->Pools->Tools and offline the disk if possible by selecting “offline” from the drop-down list under the “Command” field. Ensure that “Device” is selected under the “Option” field and that the correct pool is selected under the “Pool” field. Use the checkbox to select the defective disk under the “Devices” field, then select “Send Command!” (See Figure 9).

Screenshot showing a defective disk being offlined in NAS4Free

Figure 9

Power down NAS4Free, then identify and replace the defective disk with one of equal storage capacity using, if possible, the same SATA port [Pro-tip: Take the time to label your disks correctly (e.g. ada2) when you install them. It will make physically identifying the defective disk much easier!]. Restart NAS4Free and navigate to Disks->ZFS->Pools->Information to verify the device name for the new disk. If you were able to reuse the same SATA port, the device name should be same as the defective disk (e.g. ada2). Navigate to Disks->ZFS->Pools->Tools and replace the disk by selecting “replace” from the drop-down list under the “Command” field. Ensure that “Device” is selected under the “Option” field and that the correct pool is selected under the “Pool” field. Use the checkbox to select the defective disk under the “Devices” field and the new disk from the drop-down list under the “New Device” field, then select the “Send Command!” The replacement disk should resilver fairly quickly. Verify by navigating to Disks->ZFS->Pools->Information

    Creating and managing snapshots

One of the many great features about using ZFS is its snapshot capability. A snapshot is a read-only reference to the state of a dataset at the moment the snapshot was taken. It is a reference, and not copy, because at the moment it is taken, it takes up no additional space. However, as data within the dataset changes, either because files are modified or deleted, the snapshot consumes disk space by continuing to reference the old data. This behavior allows you to easily recover files if necessary, but in doing so prevents disk space from being freed until the snapshot is deleted.

To take a snapshot manually, navigate to Disks->ZFS->Snapshots->Snapshot, and select the dataset you want to snapshot (e.g., pool_1/files) from under the “Path” field. Enter a name for the snapshot (e.g., snapshot_1), enable “Recursive” option, then select “Add” (See Figure 10).

Screenshot showing a ZFS snapshot being manually created in NAS4Free

Figure 10

NAS4Free also provides the ability to configure reoccurring snapshots under Disks->ZFS->Snapshots->Auto Snapshot. Here you can schedule a time the system should perform the snapshot and how long it should retain them, resulting in the oldest snapshot being deleted when the deadline is reached.

You have a couple of options when it comes to “rolling back” to a particular snapshot. In fact, though , rolling back is a slight misnomer, because what you’re really doing is locating the snapshot you’re interested in and copying over the files you’d like to recover. If you selected the option “Snapshot Visibility” when setting up your dataset in NAS4Free (See Disks->ZFS->Datasets->Dataset->Edit), then all snapshots for that dataset will be located in that filesystem under the directory /.zfs/snapshot (e.g., /mnt/pool_1/files/.zfs/snapshot). This allows you to simply navigate to the snapshot directory your interested in and copy files from that directory to the current filesystem.

Another way you can recover files from snapshots is to clone one to another directory. This approach has the advantage of allowing you to share out the cloned snapshot directory, say using CIFS or NFS, for some period of time until files are recovered. To clone a snapshot, navigate to Disks->ZFS->Snapshots->Snapshot and edit the snapshot you’re interested in cloning by selecting the small wrench icon. Ensure that “Clone” is selected under the “Action” field, then enter a path to the directory where the clone is to reside. Note that this path must be expressed as a relative path. So, for example, pool_1/files/oldfiles would work, but /mnt/pool_1/files/oldfiles would not, nor would /pool_1/files/oldfiles. Also note that the directory where the snapshot will be cloned does not have to be created in advance, rather it will be created automatically for you when you clone the snapshot. Now, select “Execute” when finished and your cloned snapshot will be available for use at the path you specified (e.g. /mnt/pool_1/files/oldfiles) (See Figure 11). Cloned snapshots can be destroyed at anytime by navigating to Disks->ZFS->Snapshots->Clone.

Screenshot showing a snapshot clone being manually created in NAS4Free

Figure 11
    Data scrubbing

Performing a ZFS “scrub” on a regular basis helps to identify data integrity problems, detect silent data corruptions caused by transient hardware issues, and to provide early alerts to disk failures. This operation traverses all the data in the zpool once and verifies that all blocks can be read. Scrubbing proceeds as fast as the vdevs will allow, though the priority of any disk I/O generally remains below that of normal operations. So, while the scrub operation might negatively impact performance slightly, the zpool’s data should remain usable and nearly as responsive while the scrubbing occurs.

To schedule and manage scrubs on a ZFS zpool in NAS4Free, we’ll set up a cron job to run the zpool scrub command. Navigate to System->Advanced, and select the Cron tab. Ensure that the “Enable” checkbox is selected, then enter the command zpool scrub [your-pool-name] in the “Command” field. Ensure that the command is run as the root user and enter a description for the cron job if desired. Now select when you’d like the command to run in the “Scheduled time” field. If you have consumer-quality drives, consider a weekly scrubbing schedule. If you have data center-quality drives, consider a monthly scrubbing schedule. Also note that depending upon the amount of data in the zpool, a scrub can take a long time. Consequently, you may want to consider scheduling them for evenings or weekends to minimize the impact on performance. When complete, select “Add”, then “Apply changes”. The example shown in Figure 12 shows the command zpool scrub pool_1 will run every Sunday at 1300 local time.

Screenshot showing ZFS scrubbing being configured as a cron job in NAS4Free

Figure 12

Conclusion

This post described how to create and maintain a simple, yet resilient, ZFS mirror in NAS4Free, an open source NAS implementation based on FreeBSD.

Code

Check if a Device or File System is Mounted

Occasionally I find myself needing to mount a remote file system on a local *BSD or Linux machine. On one such occasion recently I had mounted an NFS file system from a Network Attached Storage (NAS) server to a local machine running FreeBSD, for the purpose of backing up some of the files to yet another machine offsite using the rsync utility. I had created a little script to run rsync periodically through cron. This script worked well until I noticed a few days later that the backups on the remote machine no longer existed. After some investigation I quickly determined that NAS file system was no longer mounted on the FreeBSD machine (I can neither confirm or deny that I may have configured something incorrectly). The rsync script, upon noticing that files no longer existed in the source, deleted said files at the target. It was at that point that I decided to include a small test in the rsync script to check on the existence of the mounted file system; then, if it still existed, the script would proceed with the rsync command, else it would write an error message to a log. Here is the code snippet I used in the script, which you can easily adapt for other situations:

The df command simply displays statistics about the amount of free disk space on the specified file system. If a file system argument is not specified, statistics for all mounted file systems are displayed. The output of the df command is then piped through the venerable grep utility using its -q option, which instructs grep not to write anything to standard output, but rather exit immediately with a zero status if a match is found. Finally, the file system we’re interested in matching to, parsed from the output of the df command, is provided to grep. If the output of this df command is zero, the script runs a command (in this case my rsync command), else if it exits with anything other than zero, the script runs another command instead (in this case an error message).