Home > Blogs > VMware Hands-On Lab (HOL) Blog > Tag Archives: NSX

Tag Archives: NSX

HOL Three-Tier Application, Part 4 – Web Server

This is the fourth post in the series about building a three-tier application for demonstration, lab, and education purposes. If you have been following along, you have created the base Photon template as well as simple database and application servers.

This post covers the final layer of our stack, the web presentation tier. I have said it before, but the configuration of the web server here is really simple, and if you have made it this far, you’re golden.

The Web Server (web-01a)

All of the hosts in this application run “web server” software, but this one has the web server designation because it is the one that the user directly accesses. The entire back end could be replaced with real application middleware and an RDBMs, but the user expects this one to present an SSL-encrypted web page on port 443. This time, I have chosen not to use Apache, and there is no need for Python. There is no CGI, and minimal configuration is required aside from issuing another certificate for the SSL. This tier is mostly interesting because it will support the virtual name of the application in addition to the real name(s) of your web server(s).

The red box in the following diagram highlights the component that we are building in this post.


Again, the first steps look quite a bit like the steps we performed for the application and database servers as we assign the personality to the template. I will again outline the steps here as a reminder. Details can be found in my post about the database server.

Let’s get started!

  1. Deploy a copy of the base Photon template you created by following the steps in my first post.
  2. Name it something that makes sense to you for your web server. I called mine web-01a
  3. Power it up and log in as the root user
  4. Change the hostname in /etc/hostname and in /etc/hosts
  5. Change the IP address in /etc/systemd/network/10-static-eth0.network
  6. Use a SSH client to access the machine as root (makes pasting possible)

Instead of installing Apache again, we are going to use nginx. You can do the same thing with Apache, but I wanted to try something a little more lightweight and the nginx configuration for this use case is really simple.

Install nginx to be used as a reverse proxy

The web server machine will function as a reverse proxy, sending user requests bound for port 443 on this server to the application server at https://app-01a.corp.local:8443

# tdnf install nginx

The nginx install is less than 6 MB and takes a few seconds:


Configure the reverse proxy

Edit the configuration file, /etc/nginx/nginx.conf

# vi +116 /etc/nginx/nginx.conf

by adding the following at the bottom of the file, at line 116, just before the closing “}” in the file.

   # HTTPS server
   server {
      listen 443;
      server_name webapp.corp.local;

      ssl on;
      ssl_certificate     /etc/nginx/ssl/webapp.pem;
      ssl_certificate_key /etc/nginx/ssl/webapp.key;

      ssl_session_cache shared:SSL:1m;
      ssl_session_timeout 2m;

      location / {
         proxy_pass https://app-01a.corp.local:8443/;
         proxy_set_header Host $host;
         proxy_redirect http:// https://;

Notice that we need an SSL certificate and a key to make this work. We have done this before, so let’s create those now.

Make the ssl directory and switch into it

Let’s just create the certificates in the place that the server expects them to be.

# mkdir -p /etc/nginx/ssl
# cd /etc/nginx/ssl

Build the configuration file

It is common for multiple web servers to be configured in a pool, behind a load balancer. I create the certificate here using a name, webapp.corp.local. This name can be assigned to the load balancer’s VIP. If there is only one web server, as in my example here, this name can also be an alias that resolves to the one web server. For simplicity, and possibly for other use cases, the certificate configuration we build here includes the names of three web servers: web-01a, web-02a and web-03a.

Create the file webapp.conf

# vi webapp.conf

with the following contents, modified as needed for your environment:

distinguished_name = req_distinguished_name
x509_extensions = v3_req
default_md = sha256
prompt = no
C = US
ST = California
L = Palo Alto
O = VMware
OU = Hands-on Labs
CN = webapp.corp.local
keyUsage = keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
DNS.1 = webapp.corp.local
DNS.2 = web-01a.corp.local
DNS.3 = web-02a.corp.local
DNS.4 = web-03a.corp.local

Save and close the file.

Generate the key and certificate

Note that this is a long command and you may need to scroll to the right to get all of it. Ensure it ends with “webapp.conf”

# openssl req -x509 -nodes -days 1825 -newkey rsa:2048 -keyout webapp.key -out webapp.pem -config webapp.conf

(optional) Validate that the PEM file “looks right”

I put this command here for those who want to look at the certificate. It is a good command to know in case you have a certificate file and want to know what information it contains. That can help you match the certificate to the proper host without needing to install it and then find out it is not the right one.

# openssl x509 -in webapp.pem -noout -text

Start the nginx server and configure it to startup when the VM boots

# systemctl start nginx
# systemctl enable nginx


With the other components (db-01a, app-01a) online, reachable and tested, you can test the whole solution with curl from the console of the web server

# curl -k https://web-01a/cgi-bin/app.py

This should return the data from the database in HTML format by executing the script on the application server.

You can filter the results by appending a querystring. Try this one:

# curl -k https://web-01a/cgi-bin/app.py?querystring=science

That query should return a single entry with a name containing the word science. It may be difficult to read on the command line since it is HTML. These look nicer via a GUI web browser anyway, and you can modify the filter using the form at the top of the table:


That’s it!

You now have the components of a rudimentary three-tier web application that you can use in your lab. I hope this build has provided some useful tools for you. In the final post, I will use this set of VMs and cover an example of how to implement a pool of webservers in front of the application and database tier.

Thank you for reading!

Oh, just one more thing…

Notice the pretty green lock next to the URL in my web browser in the previous screen shot?

SSL Certificate Trust

In this application, we have a self-signed SSL certificate. It should be created with the name webapp.corp.local, or whatever you selected for your environment. To get rid of the web browser security warnings and have the shiny green lock show up, you need to do two things:

Configure DNS Records

The only record you need from the client side is one that points to webapp.corp.local.

If you have a Windows-based DNS server, you can create the records using PowerShell. The following 2 lines create a DNS host (A) record for web-01a.corp.local and then a DNS alias (CNAME) record for webapp.corp.local that points to it.

PS> Add-DnsServerResourceRecordA -ComputerName 'dns.corp.local' -ZoneName 'corp.local' -name 'db-01a' -IPv4Address '' -CreatePtr

PS> Add-DnsServerResourceRecordCName -ComputerName 'dns.corp.local' -ZoneName 'corp.local' -Name 'webapp' -HostNameAlias 'web-01a.corp.local.'

This configuration allows the virtual name webapp to be separate from the web-01a name and enables the addition of other web servers to a pool, followed by the reassignment of the webapp name to a load balancer IP.

If you don’t have Windows-based DNS, you can edit your /etc/hosts file on the client or add the DNS records to your nameserver using the procedures required for your environment.

Trust the Self-Signed Certificate

Once you have name resolution knocked out, you need to trust the certificate on your client. You can really trust the certificate, or you can sometimes create an exception in the web browser. Do whichever works for you and makes you happy. Without trust, this is what the connection looks like in Chrome:


In our labs, we download the web server’s certificate to the client machine and add it to the Windows Trusted Root Certification Authorities store or one of the subtrees within Keychain Access on MacOS. That will handle IE on Windows, and Chrome browsers on Windows and MacOS.

If you save the certificate file to your desktop in Windows and double-click it, the bold text pretty much sums up what you need to do.


There are a variety of ways to get this done, and there are some shortcuts, but the process has not changed in many years and this Microsoft Windows Blog article covers a process that works.

Firefox manages its own trust store, so you need to import it separately if you want to use that browser. Check the Mozilla Wiki for detailed instructions about how to do this. Note that newer versions of Firefox have implemented more strict checking. Basically, they refuse to accept a “leaf” certificate that is specified as a Certificate Authority certificate (why is your web server using the CA certificate??) and will not allow a non-CA certificate to be added to its trusted root CA certificate store. Getting this to look nice requires additional hoops that are beyond the scope of this article. We have a Microsoft CA implemented in our labs and generally issue certificates from there. Since that CA is trusted by all clients within the environment, there is no issue.

Thank you again for reading!

You can finish the series with the last post: Use Cases.

HOL Three-Tier Application, Part 3 – App Server

This is the third post in the series about building a three-tier application for demonstration, lab, and education purposes. At this point, you have downloaded Photon OS and prepared the base template according to the specifications and have built and tested the database server, db-01a.

Working from the bottom-up, we move to the application server, which sits between the database and the web tier. As with the database, this is nothing fancy, but it gets the job done.

The Application Server (app-01a)

The application server sits in the middle of our stack and handles the formatting of data that is returned from the database. We will again use Apache and Python because we know how to use those tools from the database server build. This time, the CGI script presents an HTML form and table containing data pulled from the database via HTTP.

To add a bit of realism and fun to the process, we will configure SSL on the application server. The basic configuration is pretty simple once you have the certificate and key, and it is good to know how to do. Sure, we will be using our own self-signed certificate, but this is a lab!

The red box in the following diagram highlights the component that we are building in this post.


Note that the first steps look quite a bit like the steps we performed for the database server. I’ll outline them here. Details can be found in my previous post. Let’s get started!

  1. Deploy a copy of the base Photon template you created by following the steps in my first post. Name it something that makes sense to you for your app server. I called mine app-01a
  2. Power it up and log in as the root user
  3. Change the hostname in /etc/hostname and in /etc/hosts
  4. Change the IP address in /etc/systemd/network/10-static-eth0.network
  5. Use a SSH client to access the machine as root (this makes pasting commands easier)
  6. Install the Apache web server

Install the Apache server here, just like on the database server

# tdnf install httpd

Due to the SSL requirement on this machine, there are more files to edit than in the database server build, so get your editor ready!

Prepare to create the certificate and key

Creating the certificate is easiest if we pass it a file containing all of the answers needed by openssl. Navigate to /tmp and create the file app-01a.conf

# cd /tmp 
# vi app-01a.conf

Put the following contents into the file. Substitute values appropriate for your environment. The CN and the values under the [alt_names] section are the most important for our purposes here.

distinguished_name = req_distinguished_name
x509_extensions = v3_req
prompt = no
C = US
ST = California
L = Palo Alto
O = VMware
OU = Hands-on Labs
CN = app-01a.corp.local
keyUsage = keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
DNS.1 = app-01a.corp.local
DNS.2 = app-01a
IP.1 =

Save and close the file.

Generate the key and certificate from the configuration file

Note that this is a long command. You may need to scroll all the way to the right to get all of it.

# openssl req -x509 -nodes -days 1825 -newkey rsa:2048 -keyout app.key -out app.pem -config app-01a.conf

(optional) Validate that the PEM file “looks right”

# openssl x509 -in app.pem -noout -text

Read through the text output and make sure the certificate looks as you expect. If you filled out the configuration file properly, it should be fine.

Leave those files where they are for now. We’ll need them in a few minutes.

Configure the web server to run SSL on port 8443

SSL over the default port is so yesterday. Besides, we want something that differentiates this traffic from the port 443 SSL traffic that comes from the client to the web server. Changing the port makes the firewall rules more interesting and easier to distinguish. Besides, this is not normally user-facing, so there is no complexity with requiring normal users to append “:8443” to the end of the host portion of the URL.

Open the configuration file

Use the “+52” to jump to the line we want.

# vi +52 /etc/httpd/httpd.conf

Disable listening on port 80

We don’t need this server listening on the default HTTP port, so put a # in front of the “Listen 80” on line 52)

#Listen 80

Load the SSL module

Is this thing on? We need to turn on the SSL functionality, which is disabled in the default configuration. Uncomment (remove the # from the beginning of) line 143:

LoadModule ssl_module /usr/lib/httpd/modules/mod_ssl.so

Load the CGI module

Just like on the database server, we have to enable the CGI module. Add the following text on its own line at the end of the module loading, above the <IfModule unixd_module> text. I use line 176.

LoadModule cgi_module /usr/lib/httpd/modules/mod_cgi.so

Include the SSL configuration file

Near the bottom of the file (around line 508), un-comment the line

Include conf/extra/httpd-ssl.conf

Save the file and exit.

Configure SSL Settings

Open the SSL “extra settings” file.

# vi +36 /etc/httpd/conf/extra/httpd-ssl.conf

On line 36, locate the Listen line and change the port number from 443 to 8443

Listen 8443

To make things work, I also had to comment out line 92:

#SSLSessionCache "shmcb:/etc/httpd/logs/ssl_scache(512000)"

Change the virtual host’s port number from 443 to 8443 on line 121

<VirtualHost _default_:8443>

On lines 144 and 154, ensure that the following are set (these should be the defaults) and note the paths:

SSLCertificateFile "/etc/httpd/conf/server.crt"
SSLCertificateKeyFile "/etc/httpd/conf/server.key"

Put the certificates in the right place

Remember the files you created at the beginning? Now is the time to move them to where they are expected. Just overwrite anything is already there.

# mv /tmp/app.key /etc/httpd/conf/server.key
# mv /tmp/app.pem /etc/httpd/conf/server.crt

Start the web server and set it to startup when the VM boots

# systemctl start httpd
# systemctl enable httpd

Everything should start up cleanly. If not, you may have a typo somewhere. The following command provides some good information to help locate the issue:

# systemctl status -l httpd.service

Once you have the web server started properly, take a little break. Now is just the configuration part.

Create the Python script that is our “application”

As I have written previously, Python is not my native language, but it is already there and I can convince it to do what I need. This CGI script takes the text data off the HTTP connection from the database server and formats it. It also has a simple filter field and button to change the data view a bit. Each button click submits a new request to the database and shows that the connection is still possible.

I have added some complexity here because it can provide useful information in some demonstration cases. If the IP address of the source webserver is in the webservers table, its name will be displayed. Otherwise, the IP address is used when the Accessed via: line is printed. In certain situations, this can be useful for demonstrating that load balancing is working.

Create the script

# vi /etc/httpd/cgi-bin/app.py

Add the following contents to app.py, remembering that spacing is important:

#!/usr/bin/env python
import os, sys, cgi
import requests

webservers = {

print "Content-type:text/html\n\n";
print "<head><title>Customer Database</title></head>\n"
print "<body>\n"
print "<h1>Customer Database Access</h1>\n"

remote = os.getenv("REMOTE_ADDR")
form = cgi.FieldStorage()
querystring = form.getvalue("querystring")

if remote in webservers :
   accessName = webservers[remote]
else :
   accessName = remote

print "Accessed via:",accessName,"\n<p>"

if querystring != None:
   url = 'http://db-01a.corp.local/cgi-bin/data.py?querystring=' + querystring
   url = 'http://db-01a.corp.local/cgi-bin/data.py'
   querystring = ""

r = requests.get(url)

print '<form action="/cgi-bin/app.py">'
print ' Name Filter (blank for all records):'
print ' <input type="text" name="querystring" value="'+querystring+'">'
print ' <input type="submit" value="Apply">'
print '</form>'

print "\n<table border=1 bordercolor=black cellpadding=5 cellspacing=0>"

print "\n<th>Rank</th><th>Name</th><th>Universe</th><th>Revenue</th>"

#deal with the data coming across the wire
a = r.text.split("|\n#")
for row in a:
   if len(row) != 1:
      print "<tr>"
      splitrow = row.split("|")
      for item in splitrow:
         if item != None:
            print "<td>",item,"</td>"
      print "</tr>\n"
   print "</body></html>\n"

Save and close the file.

Set execute permissions

# chmod 755 /etc/httpd/cgi-bin/app.py


Now, as long as your database server is online and reachable, accessing the script via https on port 8443, will produce the data formatted as HTML:

# curl -k https://app-01a:8443/cgi-bin/app.py

If you access it via a graphical browser like Chrome or Firefox, you can and witness the fruits of your labors thus far. Note that you will have to accept the self-signed certificate, at least temporarily. The -k switch to curl tells it to ignore the untrusted SSL certificate and continue in “insecure” mode.

Here is what it looks like from Chrome. I used the IP address in the URL here because I have not created a DNS entry for app-01a. My plan is to provide access to this application only via the web front-end and I am only accessing the app server directly as part of the build.


The good news is that we are almost finished with the application. As you can see, you can use this as it stands as a “two-tier application” by creating a DNS record for the app-01a server, but I promised you three tiers. Stick with me. We cover that in the next post.

Thanks for reading!

HOL Three-Tier Application, Part 2 – DB server

This is the second post in the series about building a three-tier application for demonstration, lab, and education purposes. At this point, you have downloaded Photon OS and prepared the base template according to the specifications. If not, please go to the first post in the series to prepare your environment.

I am trying to release these posts on Wednesdays, but yesterday was a holiday in the US, so I had some time to get this one out the door early.

For the build, I will work bottom-up so it is possible to test the components as we go along and address any issues before we get to the end and have to worry about the whole stack.

The Database (db-01a)

There are many choices that could have been made here, but I wanted to minimize the steps required and use the tools I had available by default, wherever possible. So, the database server for this application uses a SQLite database. This may seem like an odd choice since it has no native remote access. But, the sqlite3 is already present on the Photon image. So is Python. Don’t expect elegance here since I do not normally use Python. I hacked together a simple CGI script to query the database and send the results over HTTP. It is not fancy, but it is small and does just enough for my needs.

Fear not! SQLite is simple enough that you don’t need any kind of DBA skills to use it. The minimal SQL that I know was enough to get this done.

The red box in the following diagram highlights the component that we are building in this post.

Application - Database

Let’s get started!

Deploy a copy of the base template

Deploy a copy of the base Photon template you created by following the steps in my first post. Name it something that makes sense to you. I called mine db-01a.


Power it up and log in as the root user.

Set the IP address

You need to configure the IP address for this machine. Here are the contents of my /etc/systemd/network/10-static-eth0.network file.



Set the name

Update the name in the /etc/hosts and /etc/hostname files with the proper name for this VM. Replace every occurrence of the name you used in the template with the name of this VM. Note that the hostname within the prompt string will change when you log out.

Restart the network to apply the settings

# systemctl restart systemd-networkd

Once you have finished with these steps, make sure you can access the network before moving on. You need Internet access in order to proceed.

SSH in

At this point, I strongly suggest you SSH to the machine so that you can paste text. Doing all of the work from the console is possible, but pasting is easier. So, fire up puTTY or whatever else you use as your preferred SSH client.

Install the web server

I am using Apache here since I can get the base install to do what I need in pretty short order. Unfortunately, it is not already present, so we need to install it. Fortunately, it only takes a few minutes:

# tdnf install httpd


Make a directory to store the database file and make apache the owner

So you don’t absolutely need to do this, but I sometimes like to separate my data from the executables.

# mkdir /etc/httpd/db
# chown apache:apache /etc/httpd/db

Start the web server and set it to startup when the VM boots

# systemctl start httpd
# systemctl enable httpd

Create the database’s front-end CGI script

There is not much to this one. It performs a simple query of the database and dumps the result. You can type in the code, but if you have connected via SSH, you can paste it in. I recommend the latter. Keep in mind that Python uses whitespace to give the program structure, so indenting is important. More precisely, the exact amount of indentation does not matter, but the relative indentation of nested blocks to one another matters a lot. If that sounds confusing, just make sure the spacing looks like mine.

This script takes an optional parameter named querystring that allows the data to be filtered on the name property of the records. It is a step above the “dump everything” approach we used in previous versions and provides the possibility for some user interaction.

Open a new file, /etc/httpd/cgi-bin/data.py

#!/usr/bin/env python
import cgi
import sqlite3


print "Content-type:text/plain\n\n";

form = cgi.FieldStorage()
querystring = form.getvalue("querystring")
if querystring != None:
   queryval = "%" + querystring + "%"
   select = "SELECT * FROM clients WHERE name LIKE '" + queryval + "'"
   select = "SELECT * FROM clients"

for row in curs.execute(select):
   if len(row) == 4:
      for item in row:
        print item,'|'
      print "#"


Save and close the file, then mark it executable

# chmod 755 /etc/httpd/cgi-bin/data.py

Create the database file and load it with data

SQLite will create the file if it is not already present. Bonus!

# sqlite3 /etc/httpd/db/clients.db

At the sqlite> prompt, create the table:

CREATE TABLE 'clients' (
 "Rank" integer,
 "Name" varchar(30),
 "Universe" varchar(25),
 "Revenue" varchar(20)

Then, load in some data. Feel free to use whatever you like:

 (1,'CHOAM','Dune','$1.7 trillion'),
 (2,'Acme Corp.','Looney Tunes','$348.7 billion'),
 (3,'Sirius Cybernetics Corp.',"Hitchhiker's Guide",'$327.2 billion'),
 (4,'Buy n Large','Wall-E','$291.8 billion'),
 (5,'Aperture Science, Inc.','Valve','$163.4 billion'),
 (6,'SPECTRE','007','$157.1 billion'),
 (7,'Very Big Corp. of America','Monty Python','$146.6 billion'),
 (8,'Frobozz Magic Co.','Zork','$112.9 billion'),
 (9,'Warbucks Industries',"Lil' Orphan Annie",'$61.5 billion'),
 (10,'Tyrell Corp.','Bladerunner','$59.4 billion'),
 (11,'Wayne Enterprises','Batman','$31.3 billion'),
 (12,'Virtucon','Austin Powers','$24.9 billion'),
 (13,'Globex','The Simpsons','$23.7 billion'),
 (14,'Umbrella Corp.','Resident Evil','$22.6 billion'),
 (15,'Wonka Industries','Charlie and the Chocolate Factory','$21.0 billion'),
 (16,'Stark Industries','Iron Man','$20.3 billion'),
 (17,'Clampett Oil','Beverly Hillbillies','$18.1 billion'),
 (18,'Oceanic Airlines','Lost','$7.8 billion'),
 (19,'Brawndo','Idiocracy','$5.8 billion'),
 (20,'Cyberdyne Systems Corp.','Terminator','$5.5 billion'),
 (21,'Paper Street Soap Company','Fight Club','$5.0 billion'),
 (22,'Gringotts','Harry Potter','$4.4 billion'),
 (23,'Oscorp','Spider-Man','$3.1 billion'),
 (24,'Nakatomi Trading Corp.','Die-Hard','$2.5 billion'),
 (25,'Los Pollos Hermanos','Breaking Bad','$1.3 billion');

Once you are happy with the data you have entered — ensure that you finish with a semi-colon and a newline — press Control-D to close the SQLite session.

Set the database file’s owner

The apache user running the web server needs access to this file in order for the CGI script to read the data.

# chown apache:apache /etc/httpd/db/clients.db

Enable CGI on the webserver

The default Apache install on Photon does not have the CGI module loaded. It is simple enough to turn it on:

Open the web server’s configuration file. The +176 before the file name opens the file at line 176, which is where we want to start:

# vi +176 /etc/httpd/httpd.conf

At line 176, add the following line to load the CGI module:

LoadModule cgi_module /usr/lib/httpd/modules/mod_cgi.so

At line 379, add the following to enable access to the database directory. It goes right before a line that starts with <IfModule mime_module>

#database directory
<Directory "/etc/httpd/db">
    AllowOverride None
    Options None
    Require all granted

Save and close the file.

Restart the web server to read the updated configuration

# systemctl restart httpd


Now, you can access the script via http and you should see the data.

# curl http://db-01a/cgi-bin/data.py

It won’t look too pretty, but the user never sees this back end data. That’s where the application server comes in. At this point, the result should look something like this:

root@db-01a [ ~ ]# curl http://db-01a/cgi-bin/data.py
1 |
Dune |
$1.7 trillion |
... (truncated) ...
24 |
Nakatomi Trading Corp. |
Die-Hard |
$2.5 billion |
25 |
Los Pollos Hermanos |
Breaking Bad |
$1.3 billion |
root@db-01a [ ~ ]#

The next piece of the puzzle is the application server, which consumes the data provided by this component. If you had no problems with this setup, the rest should be a breeze. This may be the most complicated part of the whole application.

Thank you for reading!

The next post detailing the build of the App server is available here.

HOL Three-Tier Application, Part 1

This is the first post in my series about the multi-tier application we use in some of the VMware Hands-on Labs to demonstrate, among other things, network connectivity, microsegmentation and load balancing. This post will cover downloading the base operating system and performing the configuration tasks common to all of the VMs in the solution. As with anything, there are multiple ways to do this. This represents the way that worked for me.

The Need

Whether you live in a cutting-edge, microservices-oriented world, or have a traditional application spread across multiple machines, the components (machines, containers, services, processes, etc.) need to communicate with one another over the network. Understanding what that looks like is important to securing the connection end-to-end. This simple application is intended to provide a starting point for learning or testing firewall and load balancing configurations to see how they affect a distributed environment.

For instruction purposes, we wanted three simple, independent parts that could be deployed, rearranged, and otherwise manipulated to illustrate many different situations that may occur in an environment. For HOL and other labs, small is usually good. Oh, and fast. It should be fast.

The Application

This application consists of three operating system instances, independent VMs, each of which handles a specific task. When all of them can communicate over the network over the required ports, the client receives the requested information and can interact with that information. If there is a breakdown, not so much.

This demonstration application has been created so that each component VM is independent from the others: IP addresses can be changed and multiple instances of the web and application tier VMs can be created by cloning, renaming, and re-addressing. The basic build with one of each type and all resources on the same subnet will be described in this series. The following is a simple diagram of what I will be covering. I put SSL in here because it is always a good idea to secure your web traffic, and it provides the opportunity to configure a load balancer in front of the web tier in a more realistic scenario.


So, let’s get to it!

Build The Base

This application is built using VMware’s Photon OS. If you are not familiar with the Photon project, you can read more on the VMware Photon OS page. Basically, as the page indicates, Photon OS is a Minimal Linux Container Host. Because we have very basic needs, we are going to focus on the first half (Minimal Linux) and ignore the second half (Container Host) for now. One really cool thing about Photon OS is that it boots incredibly quickly.

Before we do anything, I’d like to give you an idea of the time involved in building this application. Once I have the software downloaded and have staged the base Photon template, I can get the basic application up, running, and captured in under an hour. If you are comfortable using the vi editor and an SSH connection, I think you can as well. Even if you are a bit rusty, it should not take too much longer than that. My time is skewed a bit since I was documenting the build.

Download the Software

This application is going to run as a set of virtual machines on my VMware ESXi hosts. I selected the Photon OS, Version 1.0 — OVA with virtual hardware v10 as my starting point. If you like, you can install Photon on your own from the ISO, but this has nearly everything we need in a simple package: A pre-installed and vSphere-optimized Photon OS minimal instance configured with virtual hardware version 10. At the time of this writing, that file was available using the link at the bottom of the VMware Photon OS page. The file I downloaded was called photon-custom-hw10-1.0-13c08b6.ova and is less than 300 MB.

Import the OVA

Once you have downloaded the software, import the OVA to your environment and power it up.

Create a Baseline

You can handle this however you like, but I have some tasks that are common across all of the VMs and don’t like to duplicate work if I can avoid it. Note that you will need Internet access from the VM in order to install software. You will also need three IP addresses that you can statically assign to the VMs.

Set the root password

The default password on the OVA is changeme — use this to log in with the user name root. The system will prompt you again for the changeme password and then require you to set a complex password. It didn’t like our standard (simple) HOL preferred password, so I had to set it to VMware123! and then I used passwd to change it to VMware1! that we use in all of the Hands-on Labs. Note that passwd will complain about a weak password, but will still let you change it here as long as you are persistent:


Ensure that root’s password does not expire

It is always a drag when you finally get back to working on your lab, only to have to reset passwords… or, worse, figure out how to break in because the password is no longer valid. In production, I probably would not do this, but this is a lab tool.

Note that my convention is to prefix the examples with a “#” because they are executed as the root user. You don’t type the “#”

# chage -M -1 root

Note that is a NEGATIVE ONE after the -M

Set the hostname

Change the hostname from the default generated name to what you want to use. For the template, I usually set it to something besides the default  photon-<some random characters> so that I know I have done this work. Note, if you’re not familiar with the vi editor, look here for a “cheat sheet” from MIT.

# vi /etc/hostname

Replace the current name with the new name and save, close the file.

Set a static IP (change from default DHCP)

In this OVA, the default network configuration is stored in /etc/systemd/network/10-dhcp-en.network. To configure a static IP address on the eth0 interface, rename the file and replace the contents:

# mv /etc/systemd/network/10-dhcp-en.network /etc/systemd/network/10-static-eth0.network

Renaming it instead of copying it retains the permissions so that it will work. The contents are pretty straightforward. The following example is for the web-01a machine in my environment. Substitute with addresses that make sense for you. Don’t count on DNS to work once these VMs are deployed in DMZs or microsegments, but I configure it because I need to be able to resolve repository hostnames to install software:



Restart the network to apply the settings

# systemctl restart systemd-networkd

Edit the hosts file

Because this application is intended to be self-contained, we use local hosts files for name resolution. Configuring this template with all of the names and IPs that you want to use is easier than doing it later for each VM. Specifying names allows the other tools’ configurations to be built using names instead of IP addresses. This and makes changing addresses later much easier.

Remember to also change the hostname on the loopback ( from the default to your host’s name, too. This is an example of the edited file from our web-01a machine:

# Begin /etc/hosts (network card version)

::1 localhost ipv6-localhost ipv6-loopback localhost.localdomain localhost web-01a
# End /etc/hosts (network card version) db-01a.corp.local  db-01a app-01a.corp.local app-01a web-01a.corp.local web-01a

Modify the firewall to allow the desired ports

The iptables config script run at startup of the Photon OS is /etc/systemd/scripts/iptables and only allows SSH by default. Add the following lines to the bottom of the file:

#Enable ping by anyone
iptables -A INPUT -p icmp -j ACCEPT

#Enable web and app traffic 
iptables -A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp -m tcp --dport 443 -j ACCEPT
iptables -A INPUT -p tcp -m tcp --dport 8443 -j ACCEPT

The last three open the ports we need for all of the app layers. You can comment out the ones you don’t need for each VM after you deploy each one… or not.

Restart iptables to apply the new rules

# systemctl restart iptables

(optional) Verify the new rules

# iptables -L

(optional) Enable key-based SSH

If you have an SSH key that you use, now is a good time to copy your SSH key to the /root/.ssh/authorized_keys file, replacing the <ssh-key-here> text that is there by default.

(optional) Install software used by all

The OVA contains a minimal installation of Photon OS, but I created this application with the default packages in mind. We use the tdnf tool to perform installations on Photon. While adding lsof is optional, I find it excellent for troubleshooting.

# tdnf install lsof

Once installed, try this to see which services are listening and connected on which ports:

# lsof -i -P -n

Cool, right?

If you have anything else that you want to install — say you prefer nano to vim as a text editor — go ahead and install that now using the same tdnf syntax:

# tdnf install nano

Finish Up

I usually reboot here just to make sure everything comes up as expected before moving on. With Photon, that reboot only takes a few seconds.

If everything looks good, shut this machine down and clone it to a template for use when creating the web, app, and database server machines. For this example, I called mine photon:


Next time, I will cover the build of the database VM using this template as a starting point.

Thank you for reading!

Happy New Year

Happy 2017 from the VMware Hands-on Labs team! I have three quick updates for you in this post.


We are currently working on our Spring Release, which is when we refresh some of the labs from the prior year’s VMworld. Look for some updated content around April of this year.


We have started planning the labs for VMworld 2017, which is always an exciting time. If you have a great idea that you would like considered for our 2017 cycle, we have the Hands-on Labs Idea Registry. We accept submissions on this site for the current year until around mid-February. Once your idea is submitted, it will be reviewed and presented to the appropriate VMware Business Unit for consideration.


We have create a few tools to deal with the specialness of running our lab content in a nested environment. Some of these have proven useful to others in the community who run their own labs. We talk about these tools a bit during our VIP Tours at the VMworld events and are happy to share what we can. A few are currently available on GitHub:

  • LabStartup – a framework that we use for checking the status of components within our labs, both at startup time and, now, on a periodic basis. The LabStartupFunctons.ps1 contains some useful functions for checking status and, in some cases, performing remediation.
  • HOL-ModuleSwitcher – a framework for executing PowerShell scripts via a simple “button panel” UI. Supports Start and Stop scripts for each module.


Disclaimer: These scripts are provided “as-is” and may not be appropriate for your environment. They are not officially supported by VMware. If you decide to use them, you do so at your own risk.

Most recently, I have been overhauling the three-tier “application” that we use inside our labs. The basic version is made up of 3 VMs, runs entirely on Photon OS, and boots in under 30 seconds!


With all of the interest on networking in general, and NSX in particular, we have received some requests for access to this application because it can be really helpful in a lab setting.

Rather than providing a link to a multi-GB download with VMs that someone else (me) has hacked together, I think it would be more interesting to explain how this application is put together. My goal for this project is to have something small, simple, and understandable. Using as many default components and settings as possible helps get there. It is not currently implemented using something sexy like containers, although it can be reworked that way if you are so inclined.

In some upcoming posts, I will describe this application and how it is constructed using the base Photon OS v1.0 OVA as a starting point. If you want to see what the current ConeOS-based version looks like, you can check out one of the NSX labs like HOL-1703 or HOL-1725. The new version is slightly different, but the idea is the same.

Thanks for reading and enjoy your labs!

UPDATE: The first post in the series is now online: HOL Three-Tier Application, Part 1

A look back… and forward

As 2013 draws to a close, there are a lot of people posting predictions for 2014. As for me, I think that 2014 is going to be the year that VDI really takes off…

But seriously, I’m not big into making predictions. If I’m right, there is just more pressure to do it again next year, and if I’m wrong… humiliations galore. Instead, I’d like to look at where we have been as leading indicators to what may be interesting going forward. To that end, while I am migrating labs between clouds in preparation for VMware Partner Exchange in February, I’m looking back at 2013 and some things that piqued my interest. I’ve tried to keep the list short because you’re probably like me and have a short attention span. There are so many to choose from, but three is about all I can manage.

For me, 2013 was a pretty big year: I joined VMware in March, attended my 9th and 10th VMworlds (including my first one in Europe), drafted my first white paper, and learned quite a bit about NSX, VSAN and OpenStack along the way. That’s not to say that I’m an expert in any of those areas yet, but I think each of them is going to be important in the not-too-distant future. You may think that I’m just drinking the company Kool-Aid, but the engineer in me who likes to look at the components of a solution thinks these technologies are actually very interesting.

We officially announced NSX at VMworld San Francisco in August of 2013 and its GA in October in Barcelona. Those of us on the Hands-on Labs team witnessed the excitement around these announcements at both conferences: the NSX for vSphere lab was taken more than double the number of times as the second-most popular lab (our usual winner, the vSphere Performance lab.) I think this is the first time that we have had such a dramatic difference between our top labs.

Over the past few months, the interest in NSX has not waned. Within the public Hands-on Labs, we have delivered nearly 2,500 NSX labs since October. People want to understand this new paradigm and how they can leverage it to make their lives easier. Don’t get me wrong, the transition is not something that can be done overnight or without planning, but I think the potential value of this abstraction for the right customers is incredible. If you would like to experience NSX for yourself, we have two Hands-on Labs for that: HOL-SDC-1303 (NSX for vSphere) and HOL-SDC-1319 (NSX for Multi-Hypervisor). In HOL-SDC-1319, you create each of the components and connect them by hand using the web interface. In a later module, you have the option of performing all of that same work by executing one simple script. There is a lot of untapped power in that kind of automation.

I have not focused in the networking space for many years and I am looking forward to reacquainting myself. I know it has been said by many others before me, but NSX seems to be positioned to do for networking what ESX did for servers in the early 2000’s. Watch this space.

I’ve worked a lot with enterprise storage, so I think this is a no-brainer. That I’m talking about VSAN may surprise you since it involves decentralizing the storage. However, I’m also a big fan of choosing the right tool for the job, and I think there are jobs at which VSAN will excel. Even though VSAN is only in beta, there is a great deal of excitement about this product. I have been in standing-room-only VSAN sessions at VMUG meetings, and nearly 10,000 people have expressed interest by signing up for the VSAN beta program — you can go to http://vsanbeta.com and join the party.

Even if you have a “proper” storage area network with a fancy array, I humbly suggest you take a look at what VSAN can do and, more importantly, how it ties storage and virtual machines together. Beyond its underlying host-centric storage configuration, which may give traditional SAN people that funny feeling in the pits of their stomachs, the per-VM storage policy based management (SPBM) is absolutely worth understanding. SPBM has applications beyond VSAN. Say you are interested in VSAN but lack the gear to get it installed. You can head over and take the VSAN lab in the Hands-on Labs. While you will not experience the performance of running a real VSAN, you can have a look at the interface, enjoy its configuration simplicity, and explore those storage policies I mentioned earlier.

OpenStack is another thing that caught my eye this year. There has been all kinds of buzz around this one, and I admit that I initially looked at it because I wanted to know what all of the fuss was about. If you are looking for a way to deploy certain types of applications or workloads, this framework is absolutely worth a look. However, I suggest a nontrivial amount of Linux knowledge as the prerequisite to any production deployment.

We have been doing a lot of work with OpenStack at VMware — in fact, VMware is one of the top 10 contributors to OpenStack, and no small effort has been expended to ensure that OpenStack integrates not only with VMware vSphere but also NSX and VSAN. Some people believe that OpenStack and vSphere are mutually exclusive. That is entirely untrue. You can learn more about all of this on our VMware OpenStack community page.

I noticed a lot of confusion in the industry regarding OpenStack: what it is and how it can or should be used. As someone who comes from a traditional datacenter background (you know, 1:1:1 application:server:OS, or application:VM:OS), I think I am of the same mind as many of you. I have done my fair share of research and I see OpenStack as an interesting technology that has its place in the toolkit.

Unfortunately, I believe there are some in the industry trying to position OpenStack as the “one ring to rule them all.” It isn’t, at least not out of the box or without accepting a significant amount of risk. If you have heard the pets/cattle or kittens/chickens analogies before, you have an idea of what I mean. At this point, OpenStack is most definitely suited for “cattle” and “chickens,” and it does a great job with those. Users with the right workloads seem to love their OpenStack. However, I have not seen it used to provision Microsoft SQL or Exchange servers, Oracle application or database environments, or most traditional (i.e. not cloud-aware) enterprise applications.

When I first read about OpenStack, I thought, “Oh, great, is this the the ‘single pane of glass’ panacea all over again: manage multiple different stacks of gear using just one API!” After closer inspection, I think there is more to it than that and it is worth watching to see how deep the rabbit hole goes. As long as it somehow manages to keep things simple and doesn’t contract “creeping feature-itis,” I see OpenStack and its offspring going a long way. Interested in some Hands-on? Yeah, we have a lab for that, too: HOL-SDC-1320 (OpenStack and vSphere) NEW Openstack HOL available -> https://my.vmware.com/web/vmware/evalcenter?p=openstack-hol

In my experience, it is good to know what the available tools can do, even if you do not yet know all of the details about how they work. Sure, I could have easily mentioned the cool stuff that the PernixData guys are doing, EMC’s ViPR, our own vCloud Automation Center, or a multitude of other intriguing solutions out there. Those other things are all very interesting to me, but there just is not enough time in the year to research everything and get my day job done. So, I chose two of our products and an open source project because I invested enough of my time in 2013 to understand what they mean and how I see them being applied in the future.

Cheers and a happy 2014 to everyone. Take a look, take a lab!

The VMware NSX Labs are now Available in the HOL Online Portal

The wait is over. The VMware NSX for vSphere Lab (HOL-SDC-1303) has arrived. You consumed over 2,000 sessions of this lab, totaling 124,000 lab minutes during the four days of VMworld. That is roughly equivalent to locking yourself in a room with your laptop and doing nothing but take this lab 24 hours a day, seven days a week, for three months straight. Creepy . . . 🙂

We are bringing additional NSX content to the online portal as well as the remaining labs in the Mobility catalog. This is a big day of HOL goodness! Enjoy.

Remember to participate in the HOL Community page at http://hol.vmware.com/, take labs at http://labs.hol.vmware.com/ and tweet us @VMwareHOL.

VMware NSX Labs

HOL-SDC-1303 – VMware NSX Network Virtualization Platform

A Tech Preview of the exciting new VMware NSX for vSphere product announced at VMworld. Learn how VMware NSX virtualizes your network and simplifies your datacenter. This lab is currently based on a beta version of code and you may encounter some user interface issues during the lab exercises. The lab will be improved with newer code as the product moves closer to release. For now, brave the rapids, jump in with both feet and have a go at at VMware NSX, the premier solution for Network Virtualization.

Enroll in HOL-SDC-1303

HOL-SDC-1319 – VMware NSX for Multi-Hypervisor Environments

Also a Tech Preview, this lab focuses on the multi-hypervisor version of VMware NSX. This is a great opportunity to see how NSX can help, even with the non-vSphere portions of your datacenter.

Enroll in HOL-SDC-1319


HOL-MBL-1301-UC – Horizon View Use Cases

VMware Horizon View is changing the way desktop computing is delivered. These use cases, drawn from real-world experience, clearly demonstrate the inherent value within the Horizon View solution. If you are curious as to what ways Horizon View is actually used today, this lab provides excellent examples.

Enroll in HOL-MBL-1301-UC

HOL-MBL-1304 – Horizon Workspace – Explore and Deploy

Hours of new content have been added to this refresh of the successful 2012 Horizon Workspace lab. This is a phenomenal opportunity to experience Horizon Workspace for the first time. Log in and try it out!

Enroll in HOL-MBL-1304

HOL-MBL-1309 – HORIZON MIRAGE – Manage Physical Desktops

Layers and image management are at the heart of the VMware Horizon Mirage desktop management software. This lab will get you acquainted with this powerful solution in just a few minutes.

Enroll in HOL-MBL-1309

HOL-MBL-1311 – Applied ThinApp with the Horizon Suite

Also a Tech Preview, this lab focuses on the multi-hypervisor version of VMware NSX. This is a great opportunity to see how NSX can help, even with the non-vSphere portions of your datacenter.

Enroll in HOL-MBL-1311