AWS AppStream – Secure, High Performance Remote Work

Now that we’ve become remote workers by default, it’s no surprise that many teams are turning to Virtual Desktop Infrastructure (VDI) solutions to provide centralised, managed desktop experiences for day to day applications. But what if you don’t need a full desktop experience and, instead, just need to provide access to a single application (or a few pre-defined applications)?

AWS AppStream 2.0 allows you to define, configure and manage individual applications and catalogues of applications, then make them available via a web browser, on any platform, with an optimised streaming experience. There’s no need to install custom software on the user’s desktop, and access to the streamed application can be managed either via your existing company directory, through creating a custom directory specifically for AppStream, or by using the built-in “User Pools” feature.

This is extremely beneficial in scenarios where you need to have applications that run inside a secure network boundary, but don’t have (or want) the complications that come from provisioning VPN or other remote network connectivity solutions to workers.

In addition, AppStream has built-in support for its “fleets” to become active on-demand, and shut down automatically after a certain period of idle time. This automates cost minimisation, since idle resources are stopped and incur a much lower cost (for example, nights and weekends).

In this post, I’m going to explore setting up AppStream to provide access to a high-performance graphics application on the desktop. For this example, I’ll be using the free and open-source 3D modelling/rendering/animation tool, Blender. You can download it from if you like.

Blender works best on a system with an in-built graphics card, or GPU, since it’s doing high-end graphics rendering. I’ll need an application instance with that capability to give me the best performance.

Getting Started - Creating a VPC

I’m going to use a dedicated VPC for this example, in order to keep the AppStream builder and runtime fleet separate from other network resources. If your organisation already has a VPC with connectivity to on-premises resources, or to other environments, you could use that (and therefore provide access to existing shared drives, databases, or other services).

I use the AWS Console VPC Wizard to create a VPC with just Public subnets. I’m using mostly defaults here, and once the VPC is created, I’ll add more subnets to fill the Availability Zones for maximum redundancy.Once the VPC has been created, (taking about 10 seconds) I manually add two more public subnets (for availability); one in ap-southeast-2b and one in ap-southeast-2c.

This takes about 2 minutes all up.

Create the AppStream Image Builder

Now that my VPC is in place, I can create my AppStream image. I start by working out which base image builder I’ll need. Blender works well with many kinds of graphics cards, but I’m looking for a balance between performance and cost so I want the G4dn instance type; and because I want a recent operating system, I choose the Windows Server 2019 base image.

 I don’t need boatloads of CPU, since most of the work will be done by the GPU, so I can choose the lowest-level G4dn instance with 4 vCPUs and 16GB of RAM. I don’t need to specify VPC endpoints, or an IAM Role — yet.

In the network configuration, I’m using the VPC I created above, and I’m not configuring an Active Directory for domain-joined users in this example.

Once I’m done with the configuration, I click Review and then Launch. This will take about 15 minutes, so I have a cup of tea.


The image builder is ready when it’s in the Running state. If for some reason it goes straight from Pending to Stopped, you should check in the Notifications tab for the image builder to see what’s gone wrong.

Create your AppStream Image

Once the image builder is running, I select it from the list of builders and click Connect. Initially, I need to log in as the Administrator user, in order to install applications.

 The image comes with Firefox pre-installed so I can just download the Blender installer from — this goes pretty fast, since the EC2 instance has a very quick connection to the internet.

Once Blender is installed, I run the Image Assistant (there’s an icon on the desktop of the image builder session)

 I click the “Add app” button, browse to the location of the Blender program, and choose the Blender executable; then Save, and click Next in the Image Assistant.

Now I switch to the Template User, to set up Blender with the defaults I want.

Connected as the Template User, I run the Image Assistant again; from there, I start Blender and configure the Preferences. Most important for this use case is to set the System preferences for Cycles rendering to use CUDA devices — the NVidia Tesla T4 appears immediately.

I pin Blender to the taskbar (to be nice), and then I can quit Blender and switch back to the Administrator user via the Image Assistant.

Back at the Administrator, I now have a Template User configuration that I can use to Save Settings, which I do. Once the settings are saved (this takes a few seconds), I switch to the Test User to validate that Blender is available.

Once I’ve launched Blender, and checked that it’s working normally, I switch back to the Administrator user, and I optimize the launch experience for the application by following the prompts.

Then I configure the final image name, set the description and tags, and click “Disconnect and Create Image”.

Back in the AWS AppStream console, I can see that the Image Builder instance is in the state “Snapshotting” which means it’s creating an AppStream Image that I’ll be able to launch later. This stage can take 20 minutes or so, and it’s time for another cup of tea!

Once the image has been created, the Image Builder will be in a Stopped state. If you click across to the Image Registry tab and change “All Images” to “Private and shared with others”, you’ll see your new AppStream image, in the “Available” state. If you go there before the Image Builder snapshot has finished, you’ll see the Image in a “Pending” state.

Create an AppStream fleet

Once I’ve created the image, I need to create a fleet of AppStream instances to serve the streaming applications. I choose the Blender image that I created.

On the next screen, I select the smallest G4 instance type, and define the Fleet Type to be On Demand. This is key for cost control, as it means that when an instance stops being used, it will be scaled-down automatically. I tune the idle and timeout parameters accordingly.

In order to allow the AppStream instances to write user files to S3 when they’re shut down, I add an IAM Role to the fleet definition.

 Then I define the VPC to launch the fleet instances in, using the one I created at the beginning, and create the fleet.

It’ll take about 10 minutes to start the fleet up, so it’s time for tea again!

Create an AppStream Stack

Once the fleet has transitioned from Starting to Running, I create a Stack to provide access and policies around the streaming sessions.

In the next screen, I enable Home Folders. This will make use of the IAM Role I added to the Fleet above, and write user files to S3.

In the last screen, I configure options for clipboard copy and paste, file transfer, local printing, and application settings persistence — so that when a user changes settings, they are persisted to S3 between streaming sessions.


The stack will be active almost instantly (no need for tea here!)

Creating User Pools

The last step is to create and define users who can use the Stack. I click the User Pools entry in the left-hand menu, and then Create User. I fill in the user’s email address, first and last names, and click Create User

Creating the User Pool takes about 10 seconds. Once a user has been created, you can assign them to a Stack.

The welcome email includes a link to the AppStream launch page, and a temporary password. Once the user signs in, they’re required to choose a new password.

You should ensure that you assign applications to users before they get to the login screen, otherwise they’ll see this message.

You can assign a stack (application) to a user in the User Pool screen:

Once my user has been assigned to a stack, logging in shows you a screen like this, which is encouraging.

Clicking the Blender icon shows me that it’s preparing my session, with a nice progress meter and countdown.

Using AppStream

It’s fast. I’m on a good Internet connection at home (100Mbps down/50 up — well, good for Australia) and I was able to use Blender, which is a very interactive and graphics-intensive application just as comfortably as I do on my local machine, with the advantage that the AppStream instance has a much better GPU than my laptop.

The responsiveness is fantastic, to be honest. Not good enough for twitch gaming, but I am in Melbourne, and the instance is in Sydney, which is 10+ milliseconds away on a good day. I can resize my browser window, and the session resizes with it. I can go full-screen, invoke multiple monitors (which is represented as multiple windows), transfer files to and from the instance … it’s really quite good.

Using the S3 option for saving files was initially a little confusing — you have to specifically save in D:\PhotonUser\My Files\Home Folder\ — which works just fine, but you need to know that. It’s also not lighting fast, presumably because it’s actually saving the file to S3 every time. This might interact badly with applications which auto-save a lot, depending on how the application manages file saves. A performance improvement could probably be achieved by deploying an FSx filesystem for Windows, which is beyond the scope of this post.

I did manage to wedge Blender though, by asking it to render a truly silly number of hairs on a monkey, and the application stopped responding. Clicking the Windows “X” button in the top-right brought up the familiar “close this application or wait” dialog box. Closing the application gave me … a black screen. I logged out, and back in again, and got an error:

I’m pretty sure this is a temporary state of affairs, but I did appear to be able to completely wedge a “slot” in the AppStream fleet. I had to manually scale the fleet out in order to get an additional instance to finish this post, by editing the Desired Capacity in the AppStream Fleet console.

This took a few minutes to have an effect — because of course it’s starting up a new Windows instance in the back-end — but it was frustrating that I couldn’t manage the instances themselves in any way, or terminate sessions that were in-progress.

I discovered, afterwards, that the “black screen” for a crashed application isn’t a game-ender — you can just go to the application menu and re-launch the application in the current session, and it comes right back up.

Copy/paste is a bit … odd. You have to go through this “top-level” menu for copy/paste to make the copied text available to the other clipboard to be pasted, but unless you need to do a lot of it, it’s not too bad.

On the whole, though, it’s a good experience. I can see really valid use cases for this service, above and beyond my trivial example.

Oh, and in case you’re curious how the render came out, here it is: a brown monkey with a reflective sphere on a checkerboard. You can’t get much more cheesy than that!


It often comes down to price, and in this case, the comparison would be against a Workspaces desktop.

Let’s look at an equivalent configuration, a single user running Blender on a GPU-enabled Windows workspace as their primary desktop. They’re full-time work from home, so monthly pricing makes sense. If we assume that this user is in the Sydney region, and works 8 hours/day for 23 days in a month (in that they have the application running for 8 hours), then the comparison looks like:

So for an equivalent application experience for a user who only needs that single application, the cost is nearly half for AppStream compared to Workspaces. Of course, the experience is different — if you have users who need a full remote desktop, then Workspaces is the right choice; but for a sensible cost, fully-managed, application-centric experience that provides high performance on any end-user’s desktop, you can’t go past AppStream.

Additional Options

The option I chose for persisting user files in  S3 is great, but doesn’t allow for easy sharing of files between users.  To solve this, I could have created an AWS FSx Filesystem for Windows, mapped that into a shared drive on the AppStream Image, and had users log in as domain users; but for the scope of this blog post, there are a lot of moving parts that have to come together (create a Directory Service, configure SAML authentication, create and configure an FSx Filesystem, adjust the AppStream Builder, and so on). For a larger deployment, or an organisation that already has an Active Directory implementation that’s available in AWS, this would be a relatively straightforward set of tasks. There would be an additional cost to provision those resources, of course.

You can also integrate Google Drive, or OneDrive to a Stack when you create it, to allow other options for file sharing (although there are additional configuration requirements for these options)

If tea isn’t your (ahem) cup of tea, you can opt for coffee, juice or water throughout this process. I advise against anything stronger, as you end up consuming quite a lot of it.