Better Living Through Narratology

Automating a Steam Gaming instance in AWS

A while ago, I went through the setup here ( http://lg.io/2015/07/05/revised-and-much-faster-run-your-own-highend-cloud-gaming-service-on-ec2.html ) to build a gaming machine in AWS and loved the result.  A lot cheaper to run one in the cloud than to shell out loads of cash for a new one and a great write-up.

The downside, although it was a one-time downside, was going through many of the settings to create the AMI that I needed and to tighten security a bit the way I needed.  Also, the article was written with a Mac client in mind and I run Windows.

So, with my Windows experience and with all the AWS work I’ve been doing lately, I put together a CloudFormation template to automate many of the steps.  If you’re looking to create your own AMI, you can start with the template (posted at the end), but here’s what you need to first:

Before Template

You’ll need to create a Key Pair in the EC2 section of AWS.  Make sure you download this .pem file.

Make sure you know the AMI id of the Server 2012 R2 image.  If you go to the EC2 section of AWS and click on Launch Instance, you’ll see Server 2012 R2 right there on the front page.  The AMI id will look like ami-12345678.  The last 8 digits will be different, but they all start with the ami- prefix.

Make sure you know your public IP address.  You can get this from http://www.whatismyip.com.  IMPORTANT NOTE:  Your IP address can change, eventually.  When it does, you will need to update it in the SteamSecurityGroup or you won’t be able to use Remote Desktop to get to your machine.

After Template

Now that you’ve launched your Windows instance, you should be able to use Remote Desktop and the username / password you created to login.  If you’re on Windows, make sure you run “mstsc.exe /admin” to launch Remote Desktop.  After you login, you need to make some of the changes mentioned in Larry Land’s post.  Here are the steps you need to do:

  1. Make sure you know your new machine’s public IP address.  You can do this from www.whatismyip.com or from the details in the Amazon EC2 Instances menu.
  2. Run FileExtensions.bat on the desktop.  This will let you see file extensions.
  3. You might need to create an account, but make sure you download and install the GeForce drivers.  Reboot when asked.
  4. Run NvFBCEnable.exe -enable -noreset and reboot again.  That auto-login should be coming in handy now, huh?
  5. Run DisplayAdapters.bat on the desktop.
  6. Install RazerZone.exe from the C:\ drive.  There’s no need to create an account.
  7. Install OpenVPN.exe from the C:\ drive.
  8. Run OpenVPN.bat on the desktop.
    • On build-ca, leave all answers blank
    • On build-key-server server, leave all answers blank except Common Name “server”, yes to Sign and yes to Commit
    • On build-key client, leave all answers blank except Common Name “client”, yes to Sign and yes to Commit
  9. Copy the ca.crt, client.crt and client.key files from the C:\Program Files\OpenVPN\easy-rsa\keys directory to your home computer.
  10. Add startup.bat (on the desktop) to your startup scripts by using gpedit.msc.  This is covered under step 9 in Larry Land’s post.
  11. Steam is already installed.  Follow step 10 in Larry Land’s post to configure Steam properly.

That’s it!  You’re ready to capture your image.  Shut it down and from the EC2 Instances section of Amazon, just go to Image > Capture image.  This will create your own AMI in your account that you can use to launch a Steam gaming machine.

Final Thoughts

There are a few things left to do to get OpenVPN configured.

  • Install the OpenVPN client on your home computer.
  • Move the ca.crt, client.crt, and client.key files you copied earlier into the “C:\Program Files\OpenVPN\config” folder.
  • When you edit / create your connection on your home computer, you will be shown a text file to edit.  This is your client.ovpn file.  Look for a section a few paragraphs down that looks like this:

# The hostname/IP and port of the server.
# You can have multiple remote entries
# to load balance between the servers.

  • Add a line just after that text like this: remote x.x.x.x 1194
  • This is where you’ll need to know your machine’s public IP address.  Replace x.x.x.x with the public IP address of your new machine.

It’s worth noting that the public IP address of your new machine will change every time you run it, so you’ll be updating this file often.

CloudFormation Template

{
 "AWSTemplateFormatVersion" : "2010-09-09",

 "Description" : "AWS CloudFormation deploys a Windows machine used for Steam",

 "Parameters" : {

 "AWSAMI" : {
 "Description" : "Choose the AMI ID for your Steam machine. This should be a Windows Server 2012 R2 instance and the ID will look like ami-XXXXXXXX",
 "Type" : "AWS::EC2::Image::Id"
 },
 
 "AWSSubnet" : {
 "Description" : "Choose a subnet for the Steam instance.",
 "Type" : "AWS::EC2::Subnet::Id"
 }, 

 "EC2KeyPair" : {
 "Description" : "Choose a Key Pair for this instance. If you do not have one, go make one in the EC2 section and it will appear here.",
 "Type" : "AWS::EC2::KeyPair::KeyName"
 }, 

 "NewUsername" : {
 "Description" : "Type in your new username.",
 "Type" : "String"
 },

 "NewUsernamePassword" : {
 "Description" : "Type in the password for your new username.",
 "Type" : "String",
 "NoEcho" : "true"
 },
 
 "PublicIPAddress" : {
 "Description" : "What is your public IP address? Go to www.whatismyip.com to find out, then type the numbers in here and type /32 at the end.",
 "Type" : "String",
 "Default" : "0.0.0.0/32",
 "AllowedPattern": "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})"
 }, 
 
 "VpcId" : {
 "Type" : "AWS::EC2::VPC::Id",
 "Description" : "VpcId of your Virtual Private Cloud. You probably just have one default VPC. Choose it here.",
 "ConstraintDescription" : "Must be the VPC Id of an existing Virtual Private Cloud."
 }
 
 },
 
 "Resources" : {
 
 "SecurityGroupSteam": {
 "Type" : "AWS::EC2::SecurityGroup",
 "Properties" : {
 "GroupDescription" : "Security Group that allows access to VPN connections and Remote Desktop from your location.",
 "VpcId" : { "Ref" : "VpcId" },
 "SecurityGroupIngress" : [
 {"IpProtocol" : "udp", "FromPort" : "1194", "ToPort" : "1194", "CidrIp" : "0.0.0.0/0"},
 {"IpProtocol" : "tcp", "FromPort" : "3389", "ToPort" : "3389", "CidrIp" : { "Ref" : "PublicIPAddress" }}
 ]
 }
 },
 
 "SteamMachine": {
 "Type": "AWS::EC2::Instance",
 "DependsOn" : "SecurityGroupSteam",
 "Metadata": {
 "AWS::CloudFormation::Init" : {
 "config" : {
 "files" : {
 "c:\\cfn\\cfn-hup.conf" : {
 "content" : { "Fn::Join" : ["", [
 "[main]\n",
 "stack=", { "Ref" : "AWS::StackName" }, "\n",
 "region=", { "Ref" : "AWS::Region" }, "\n"
 ]]}
 },
 "C:\\Users\\Public\\Desktop\\DisplayAdapter.bat" : {
 "content": { "Fn::Join" : ["", [
 "takeown \/f C:\\Windows\\System32\\Drivers\\BasicDisplay.sys",
 "echo Y | cacls C:\\Windows\\System32\\Drivers\\BasicDisplay.sys \/G Administrators:F",
 "del C:\\Windows\System32\\Drivers\\BasicDisplay.sys"
 ]]}
 },
 "C:\\Users\\Public\\Desktop\\Startup.bat" : {
 "content": "md Z:\\SteamLibrary"
 },
 "C:\\Users\\Public\\Desktop\\OpenVPN.bat" : {
 "content": { "Fn::Join" : ["", [
 "cd C:\\Program Files\\OpenVPN\\easy-rsa\n",
 "init-config\n",
 "vars\n",
 "clean-all\n",
 "build-ca\n",
 "build-key-server server\n",
 "build-key client\n",
 "build-dh\n",
 "robocopy keys ../config ca.crt dh1024.pem server.crt server.key"
 ]]}
 },
 "C:\\Users\\Public\\Desktop\\FileExtensions.bat" : {
 "content" : "reg add HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced \/v HideFileExt \/t REG_DWORD \/d 0 \/f"
 },
 "C:\\Program Files\\OpenVPN\\server.ovpn" : {
 "content" : { "Fn::Join" : ["", [
 "local 0.0.0.0\n",
 "port 1194\n",
 "proto udp\n",
 "dev tap\n",
 "ca \"C:\\Program Files\\OpenVPN\\config\\ca.crt\"\n",
 "cert \"C:\\Program Files\\OpenVPN\\config\\server.crt\"\n",
 "key \"C:\\Program Files\\OpenVPN\\config\\server.key\"\n",
 "dh \"C:\\Program Files\\OpenVPN\\config\\dh1024.pem\"\n",
 "server 10.8.0.0 255.255.255.0\n",
 "ifconfig-pool-persist ipp.txt\n",
 "client-to-client\n",
 "keepalive 10 120\n",
 "comp-lzo\n",
 "persist-key\n",
 "persist-tun\n",
 "status openvpn-status.log\n",
 "verb 3"
 ]]}
 },
 "C:\\OpenVPN.exe" : {
 "source" : "https://swupdate.openvpn.org/community/releases/openvpn-install-2.3.10-I602-x86_64.exe"
 },
 "C:\\Steam.exe" : {
 "source" : "https://steamcdn-a.akamaihd.net/client/installer/SteamSetup.exe"
 },
 "C:\\RazerZone.exe" : {
 "source" : "http://dl.razerzone.com/drivers/Surround/win/RazerSurroundInstaller_v2.0.29.2.exe"
 }
 },
 "commands" : {
 "1-Install Steam" : {
 "command" : "C:\\SteamSetup.exe \/S"
 },
 "2-Disable IE Enhanced Security" : {
 "command" : "REG ADD \"HKLM\\SOFTWARE\\Microsoft\\Active Setup\\Installed Components\\{A509B1A7-37EF-4b3f-8CFC-4F3A74704073}\" \/v IsInstalled \/t REG_DWORD \/d 00000000 \/f"
 },
 "3-Disable Windows Firewall" : {
 "command" : "netsh advfirewall set allprofiles state off"
 },
 "4-Set Windows Audio to Automatic startup" : {
 "command" : "sc config AudioSrv start= auto"
 },
 "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"]]}
 },
 "7-Enable Auto Logon Username" : {
 "command" : { "Fn::Join" : [ "", ["reg add \"HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\" \/f \/v DefaultUserName \/t REG_SZ \/d ",{"Ref" : "NewUsername"}]]}
 },
 "8-Enable Auto Logon Password" : {
 "command" : { "Fn::Join" : [ "", ["reg add \"HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\" \/f \/v DefaultPassword \/t REG_SZ \/d ",{"Ref" : "NewUsernamePassword"}]]}
 },
 "9-Enable Auto Logon Final" : {
 "command" : { "Fn::Join" : [ "", ["reg add \"HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\" \/f \/v AutoAdminLogon \/t REG_SZ \/d 1"]]}
 }
 },
 "services" : {
 "windows" : {
 "cfn-hup" : {
 "enabled" : "true",
 "ensureRunning" : "true",
 "files" : ["c:\\cfn\\cfn-hup.conf", "c:\\cfn\\hooks.d\\cfn-auto-reloader.conf"]
 }
 }
 }
 }
 }
 },
 "Properties": {
 "InstanceInitiatedShutdownBehavior" : "stop",
 "ImageId" : { "Ref" : "AWSAMI" },
 "InstanceType" : "g2.2xlarge",
 "KeyName" : { "Ref" : "EC2KeyPair" },
 "Monitoring" : "false",
 "NetworkInterfaces": [{
 "DeleteOnTermination" : "true",
 "Description" : "Primary network interface",
 "DeviceIndex" : "0",
 "SubnetId" : {"Ref" : "AWSSubnet"},
 "GroupSet" : [{"Ref" : "SecurityGroupSteam"}]
 }],
 "UserData": { "Fn::Base64" : { "Fn::Join" : ["", [
 "<script>\n",
 "\"C:\\Program Files\\Amazon\\cfn-bootstrap\\cfn-init.exe\" -v -s ", { "Ref" : "AWS::StackId" }, " -r SteamMachine --region ", {"Ref" : "AWS::Region"}, "\n",
 "\n",
 "\"C:\\Program Files\\Amazon\\cfn-bootstrap\\cfn-signal.exe\" -e %ERRORLEVEL% ", { "Fn::Base64" : { "Ref" : "SteamMachineWaitHandle" }}, "\n",
 "</script>"
 ]]}}
 }
 },
 
 "SteamMachineWaitHandle": {
 "Type" : "AWS::CloudFormation::WaitConditionHandle"
 },
 
 "SteamMachineWaitCondition": {
 "Type" : "AWS::CloudFormation::WaitCondition",
 "DependsOn" : "SteamMachine",
 "Properties" : {
 "Handle" : {"Ref" : "SteamMachineWaitHandle"},
 "Timeout" : "600"
 }
 }
 }
}

Posted in AWS, CloudFormation | No Comments