Gaming On A Budget With AWS And CloudFormation

Run A Gaming Machine As-A-Service In AWS, And Only Pay As Much As You Play

Posted by Daniel Eyer on Fri, May 6, 2016
In Guest Post
Tags: cloudformation, gaming, aws

If you’re a gamer on a budget or you can’t justify the cost of a new rig due to limited gameplay time, there’s a great writeup here on how to build a cloud-based gaming machine for Steam games. I went through the process and got it up and running without much difficulty, but I owe part of that success to working with AWS and IT for a living.

After going through the process of building my initial gaming instance, I considered how much easier the process might be if you could automate some of the steps with CloudFormation (CF). This CF template will create a Windows server to use as your baseline for a cloud-run Steam engine (see what I did there?). The full template is available here

Parameter Inputs

Let’s start with the Parameters. The description for each should provide some explanation about what’s needed, but we’ll go over some of them.

"AWSAMI" : {
    "Description" : "Choose the AMI ID for your Steam machine...

This is the flat Windows image upon which your instance will be built. You can get this list by trying to launch and instance and looking at the list of AMIs in the Quick Start tab.

"PublicIPAddress" : {
    "Description" : "What is your public IP address?  Go to to find out, then type the numbers in here and type /32 at the end.",
    "Type" : "String",
    "Default" : "",
    "AllowedPattern": "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})"

Here, we create a value for your WAN/Public IP address to populate into a Security Group later that will only allow RDP connections from your location. The caveat here is that if your public IP address changes, you’ll need to update the Security Group with the new value. We give a sample format in the value of Default and we use the AllowedPattern field to create a regex constraint that will only allow an IP address to be given in the right format.


The security group is pretty straight-forward. We just have two ingress rules…

        "SecurityGroupIngress" : [
            {"IpProtocol" : "udp", "FromPort" : "1194", "ToPort" : "1194", "CidrIp" : ""},
            {"IpProtocol" : "tcp", "FromPort" : "3389", "ToPort" : "3389", "CidrIp" : { "Ref" : "PublicIPAddress" }}

The first rule allows us to connect to OpenVPN (over port 1194 UDP) from anywhere. So, when you’re stuck at your Great Uncle Earl’s for the holidays, you can squeeze in some game time that doesn’t involve Boardwalk or Park Place. The second rule allows RDP connections to your server and we use the Ref function to reference the Parameter PublicIPAddress we went over earlier.

Now, the bulk of the template: the EC2 instance. Much of the work being done here takes place in the CloudFormation::Init section and is built/downloaded as the server is launched. Doing the work at this stage leaves you with less to do once the server has been started and performs the work a lot faster than we can. The CloudFormation::Init parameter can contain several different components, but the main two we’re concerned with here are “files” and “commands.”

Files can be built during this phase by creating them in-line or by downloading them. We’ll look at creating them in-line first with the OpenVPN.bat file - the files that will install and configure OpenVPN server for us once the server has finished launching. First, we specify the location and name of the file. Note that we have to escape the \ character with an extra \ character.

            "C:\\Users\\Public\\Desktop\\OpenVPN.bat" : {

Now that we have a filename and location, we can start building our file. We use “content” to specify that we’ll be creating this file via in-line entry. We use Fn::Join with " as our delimiter.

                "content": { "Fn::Join" : ["", [

Then, we start building our file, line by line with a line feed (\n) at the end.

                    "cd C:\\Program Files\\OpenVPN\\easy-rsa\n",
                    "build-key-server server\n",
                    "build-key client\n",
                    "robocopy keys ../config ca.crt dh1024.pem server.crt server.key"

On to the next file…

                "C:\\Steam.exe" : {

We have a filename and location, so let’s use “source” to specify that this file will be downloaded…

                "source" : ""

And, just like that, we’ve told CloudFormation to go download that file for us and name it Steam.exe and put it on the root of the C drive. This will make it easier for us to call the file later in the “commands” section.

Welcome to the “commands” section! We have a number of cool commands being run here, so I’ll touch on a few and what they do. Note that commands are executed in alphabetical order, so we name each of them sequentially.

            "1-Install Steam" : {
                "command" : "C:\\SteamSetup.exe \/S"

We install Steam first (note the number 1) using escape characters in all the right places.

            "5-Add New User" : {
                "command" : { "Fn::Join" : [ "", ["net user ",{"Ref" : "NewUsername"}," ",{"Ref" : "NewUsername"}," \/add"]]}
            "6-Add New User to Administrators" : {
                "command" : { "Fn::Join" : [ "", ["net localgroup Administrators ",{"Ref" : "NewUsername"}," \/add"]]}

We create a new user (as specified in the Parameters section) and then add it to the local Administrators group.

The rest of the template are boiler plate nuts and bolts, so we won’t go into the details, but through a little CloudFormation magic, we’ve taken some of the legwork out of creating a complex image. After you’ve finished installing and configuring OpenVPN and any other steps necessary, you can capture your image as an AMI and terminate your instance.

To launch a gaming box to try out, hit this button Launch stack SteamEngineStack and Happy Steaming!

Tweet this, send to Hackernews, or post on Reddit