Wednesday, November 9, 2016

Nano Server on AWS: Step by Step

Windows server 2016 comes in many flavors. Nano server is the new addition that is optimized to be lightweight and with smaller attack surface. It has much less memory and disk footprint and much faster boot time than Windows Core and the full windows server. These characteristics make Nano a perfect OS for the cloud and similar scenarios.
However, being a headless (no GUI) OS means that no RDP connection can be made to administer the server. Also since only the very core bits are included by default means that configuring the server features is a different story than what we have in the full windows server.
In this post I'll explain how to launch and connect to a Nano instance on AWS. And then use the package management features to install IIS.

Launching an EC2 Nano server instance:

  • In the AWS console under the EC2 section, click "Launch Instance"
  • Select the "Microsoft Windows Server 2016 Base Nano" AMI.

  • In the "Choose an Instance Type" page, select "t2.nano" instance type. This instance type has 0.5GB of RAM. Yes! this will be more than enough for this experiment.
  • Use the default VPC and use the default 8GB storage.
  • In the "Configure Security Group" page things will start to be a bit different from the usual full windows server. Create a new security group and select these two inbound rules: 
    • WinRM-HTTP: Port 5985. This will be used for the remote administration.
    • HTTP: Port 80. To test IIS from our local browser.

  • Note that AWS console gives a warning regarding port 3389 which is used for RDP. We can safely ignore this rule as we'll use WinRM. RDP is not an option with Nano server.
  • Continue as usual and use an existing key pair or let AWS generate a new key pair to be used for windows password retrieval.


Connecting to the Nano server instance:

After the instance status becomes "running" and all status checks pass, observe the public IP of the instance. To manage this server, we'll use WinRM (Windows Remote Management) over HTTP. To be able to connect the machine, we need to add it to the trusted hosts as follows:
  • Open PowerShell in administrator mode
  • Enter the following commands to add the server : (assuming the public IP is
$ip = ""
Set-Item WSMan:\localhost\Client\TrustedHosts "$ip" -Concatenate -Force

Now we're ready to connect to the Nano server:
-ComputerName $ip -Credential "~\Administrator"

PowerShell will ask for the password which you can retrieve from AWS console using the "Get Windows Password" menu option and uploading your key pair you saved on your local machine.

If everything goes well, all PowerShell commands you'll enter from now on will be executed on the remote server. So now let's reset the administrator password for the Nano instance:
$pass = ConvertTo-SecureString -String "MyNewPass" -AsPlainText -Force
Set-LocalUser -Name Administrator -Password $pass

This will change the password and disconnect. To connect again, we can use the following commands and use the new password:
$session = New-PSSession -ComputerName $ip -Credential "~\Administrator"
Enter-PSSession $session

Installing IIS:

As Nano is a "Just Enough" OS. Feature binaries are not included by default. We'll use external package repositories to install other features like IIS, Containers, Clustering, etc. This is very similar to apt-get and yum tools in the Linux world and the windows alternative is OneGet. The NanoServerPackage repository has instructions regarding adding the Nano server package source which depends on the Nano server version. We know that the AWS AMI is based on the released version, but it doesn't harm to do a quick check:
Get-CimInstance win32_operatingsystem | Select-Object Version

The version in my case is 10.0.14393. So to install the provider, we'll run the following:
Save-Module -Path "$env:programfiles\WindowsPowerShell\Modules\" -Name NanoServerPackage -minimumVersion
Import-PackageProvider NanoServerPackage

Now let's explore the available packages using:
or the more generic command:
Find-Package -ProviderName NanoServerPackage

We'll find the highlighted IIS package. So let's install it and start the required services:
Install-Package -ProviderName NanoServerPackage -Name Microsoft-NanoServer-IIS-Package
Start-Service WAS
Start-Service W3SVC

Now let's point our browser to the IP address of the server. And here is our beloved IIS default page:

Uploading a basic HTML page:

Just for fun, create a basic HTML page on your local machine using your favorite tool and let's upload it and try accessing it. First enter the exit command to exit the remote management session and get back to the local computer. Note that in a previous step, we had the result of the New-PSSession in the $session variable so we'll use it to copy the HTML page to the remote server over the management session:
Copy-Item "C:\start.html"  -ToSession $session -Destination C:\inetpub\wwwroot\

Navigate to http://nanoserverip/start.html to verify the successful copy of the file.


Nano server is a huge step forward to enable higher density of infrastructure and applications especially on the cloud. However it requires adopting a new mindset and a set of tools to get the best of it.
In this post I just scratched the surface of using Nano Server on AWS. In future posts we'll explore deploying applications on it to get real benefits.


Fletcher Bush said...

Thanks for your post. I tried to replicate unsucessfully. I did exactly as specified but still I could not connect to the server using WinRM.

The differences I noted were that I could not find the AMI with that id (ami-e4e61f8b) and could not find a 'Datacenter Edition' of Nano.

Hesham A. Amin said...

The AMI id differs from a region to another. The region I used is Frankfurt. and the image name was "Microsoft Windows Server 2016 Base Nano" with description: "Microsoft Windows 2016 Datacenter Edition Nano. [English]".

Anonymous said...

I followed your instructions but when attempting to connect to the Nano Server instance, I get the following error:

PS C:\> Enter-PSSession -ComputerName $ip -Credential "~\Administrator"
Enter-PSSession : Connecting to remote server failed with the following error message : WinRM
cannot complete the operation. Verify that the specified computer name is valid, that the computer is
accessible over the network, and that a firewall exception for the WinRM service is enabled and allows access
from this computer. By default, the WinRM firewall exception for public profiles limits access to remote
computers within the same local subnet. For more information, see the about_Remote_Troubleshooting Help topic.
At line:1 char:1
+ Enter-PSSession -ComputerName $ip -Credential "~\Administrator"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: ( [Enter-PSSession], PSRemotingTransportExc
+ FullyQualifiedErrorId : CreateRemoteRunspaceFailed

I've checked it is in the trustedhosts.

PS C:\> Get-Item WSMan:\localhost\Client\TrustedHosts

WSManConfig: Microsoft.WSMan.Management\WSMan::localhost\Client

Type Name SourceOfValue Value
---- ---- ------------- -----
System.String TrustedHosts

And PINGing the server results in timeout:

PS C:\> ping $ip

Pinging with 32 bytes of data:
Request timed out.
Request timed out.
Request timed out.
Request timed out.

Ping statistics for
Packets: Sent = 4, Received = 0, Lost = 4 (100% loss),

NOTE: I have masked my IP address in the statements above.

Hesham A. Amin said...

These are some troubleshooting steps:
-Make sure you're using the public IP not the internal IP?
-try "telnet 5985" and observe the result
-Double check your security group setting.
-Make sure the problem is not with your corporate firewall.