Amazon GameLift Servers: Globally-scalable Fleets in an Afternoon

Amazon GameLift Servers: Globally-scalable Fleets in an Afternoon

TL;DR

1. Clone the repo in an AWS CloudShell session and run scripts
# Clone the repo and cd into it
git clone https://github.com/Rushdown-Studios/GameLiftDemo.git && cd GameLiftDemo/

# Set up the Amazon GameLift Server SDK for Golang
./scripts/setup.sh

# Build the server binary and upload it as an Amazon GameLift Build
# This will take about 5 minutes
# Make a note of the Build ID in the output
./scripts/build-and-upload.sh

# Wait ~5 minutes for the command to complete

# Create an Amazon GameLift Fleet
# The fleet needs some time to activate - for a small build like this you can expect this to take about 5 minutes
# Make a note of the Fleet ID in the output
./scripts/create-fleet.sh --build-id <Build ID>

# Wait ~5 minutes for the fleet to activate

# OPTIONAL: call the wait-for-fleet script to poll for fleet events using the AWS CLI
./scripts/wait-for-fleet.sh --fleet-id <Fleet ID>

# You can check the status in the AWS Developer Portal, or by running this command:
aws gamelift describe-fleet-events --fleet-id <fleet ID>
# {
#   "Events": [
#     {
#       "EventId": "a37b6892-5d07-4d3b-8b47-80244ecf66b9",
#       "ResourceId": "fleet-00000000-0000-0000-0000-000000000000",
#       "EventCode": "FLEET_STATE_ACTIVE",
#       "Message": "Fleet fleet-00000000-0000-0000-0000-000000000000 changed state to ACTIVE",
#       "EventTime": 1579649342.191
#     },
#     ...
# }

# Once the fleet is active, start a game session to get a server IP
aws gamelift create-game-session --fleet-id <fleet ID> --maximum-player-session-count 1
# {
#   "GameSession": {
#     "GameSessionId": "arn:aws:gamelift:us-west-2::gamesession/fleet-00000000-0000-0000-0000-000000000000/gsess-00000000-0000-0000-0000-000000000000",
#     "Status": "ACTIVATING",
#     "IpAddress": "1.2.3.4",
#     "DnsName": "ec2-1-2-3-4.us-west-2.compute.amazonaws.com",
#     "Port": 9000,
#     ...
#   }
# }
2. Clone the repo on your local machine and run the game client
git clone https://github.com/Rushdown-Studios/GameLiftDemo.git
cd GameLiftDemo/
go run ./cmd/client --host <IP Address> --port <Port> # replace host and port from the output from CloudShell
# The first build may take a few minutes
3. Clean up when you're done

From your CloudShell session:

aws gamelift delete-fleet --fleet-id <Fleet ID>

# You aren't charged for builds, only active fleets, but you can clean up your build if you'd like:
aws gamelift delete-build --build-id <Build ID>

Table of Contents

  1. Introduction: Why GameLift, Why This Post
  2. Hello, World: A Minimal GameLift Demo
    1. Sample Server
    2. Sample Client
    3. Goal: Running the Sample Game Locally
  3. Setting Up In AWS
    1. Goal: List Fleets
  4. Uploading a Build, Creating a Fleet
    1. Step 1: Clone the Sample Repo in CloudShell
    2. Step 2: Build and Upload
    3. Step 3: Create a Fleet
    4. Goal: Connecting Clients
  5. Clean Up
  6. Debugging
    1. Fleet Fails to Activate
    2. Investigating a Running Fleet
  7. What's Next?

Introduction: Why Amazon GameLift, Why This Post

Amazon GameLift Servers is a powerful managed service for hosting multiplayer game servers - handling session management, autoscaling, fleet health, and global deployment for you. If you’ve ever wrestled with server orchestration or flaky production servers, Amazon GameLift Servers might be for you.

That said, getting started with GameLift can be intimidating. The docs are comprehensive but massive, and it can be tricky to find a good way to try things out without committing engineering hours to learning the ecosystem as a whole.

This post is for engineers who want to kick the tires without spending a full week on IAM and YAML. Our goal:

Deploy a working GameLift fleet in one afternoon.

We’ll highlight common pitfalls, debug tips, and where to go next. Let’s get to it.

Hello, World: A Minimal GameLift Demo

To keep things approachable, we're starting with a barebones multiplayer setup - simple enough to grasp quickly, but complete enough to deploy and test with GameLift. We're intentionally skipping advanced topics like matchmaking and autoscaling for now; the focus is just on getting a server deployed and talking to clients.

Sample Server

See also: Amazon GameLift Servers Developer Guide: Add Amazon GameLift Servers to your game server

Written in Go, the server integrates with the GameLift Server SDK and does the following:

  • Calls the InitSDK and ProcessReady functions on startup
    • These are functions in the GameLift Server SDK that inform GameLift when the server process has started and is ready for connections
    • Calling these functions is required for GameLift servers to work properly
  • Listens for TCP connections on port 9000
  • Accepts JSON position updates from players
  • Maintains shared state of all player positions
  • Broadcasts the current state to all players every 100ms

It’s not a full game, but it covers the fundamentals: connecting clients, synchronizing state, and talking to GameLift.

Sample Client

We have two options for clients:

  • Graphical Client (Raylib): Controls a cube in 3D space. This is overkill for our purposes, but it's way more fun to play with than console output.
  • Mock Client: Simulates a player moving in a circular path. This can be handy when you want to test multiple players moving around.

You don’t need a full game to evaluate GameLift — just enough networking to validate the server flow.

Goal: Running the Sample Locally

Before moving on, let's make sure you can successfully clone, build, and run the server and client.

You'll need Go 1.24+, which you can download here. You also need to set up Raylib - you can follow the instructions on the gen2brain/raylib-go GitHub repo.

# Clone the repo via HTTPS
$ git clone https://github.com/Rushdown-Studios/GameLiftDemo.git
remote: Enumerating objects: 1234567, done.
...
Filtering content: 100% (3/3), 12.34 MiB | 5.67 MiB/s, done.

# cd into the root of the repo
$ cd GameLiftDemo/

If you're in a Bash environment like Linux, macOS, or Git Bash for Windows, you can run ./scripts/setup.sh to download and extract the GameLift Server SDK:

$ ./scripts/setup.sh
Downloading and extracting GameLift Server SDK for Golang...
Setup finished!

# verify that the project cloned and set up properly
$ ls
amazon-gamelift-go-sdk  cmd  docs  go.mod  go.sum  README.md  scripts

Or, if you're on Windows, you can run ./scripts/setup.ps1 in Powershell:

> .\scripts\setup.ps1                                     
Downloading and extracting GameLift Server SDK for Golang...
Setup finished!

# verify that the project cloned and set up properly
> ls -n
amazon-gamelift-go-sdk
cmd
docs
scripts
.gitignore
go.mod
go.sum
README.md

Run the server:

# Run the server
$ go run ./cmd/server
2025/04/23 19:32:51 Server listening on :9000

Then start clients in new terminals:

# Mock client
$ go run ./cmd/mockclient

# Graphical client (WASD + mouse)
$ go run ./cmd/client

You should be able to control a little red cube with third-peron WASD and mouse controls. If you start multiple clients, you should be able to see other clients moving around as blue cubes. If you started the mock, you should see an extra player trace out a circle in the middle of the "map".

GameLift Client Demo

GameLift Client Demo (GIF)

Setting Up In AWS

GameLift is available for paid plans in AWS, but you have up to $200 in free credits available - plenty for testing!

If you don't already have an AWS account, you'll need to create one.

⚠️
You will still need to enter a valid credit card to activate your account. Be sure to set up billing alerts or budgets if you're worried about accidental charges.

Goal: List Fleets

💡
For this guide, we'll use CloudShell to interact with the AWS CLI.

You can install the AWS CLI locally, but managing permissions when authenticating can be tricky to set up. If you want to run the AWS CLI locally, refer to the official AWS CLI User Guide for Version 2 to get started.

In the AWS Developer Console, click on the terminal icon in the top navbar to start a Cloudshell session. Once the session starts, you should be able to run aws gamelift list-fleets to get an empty list. Not the most interesting thing in the world, but now you can interact with Amazon GameLift programmatically.

List Fleets in CloudShell

List Fleets in CloudShell

Uploading a Build, Creating a Fleet

Now that we’ve confirmed the demo works locally, it’s time to package it up and launch it into the cloud.

Step 1: Clone the Sample Repo in CloudShell

To get started, open CloudShell in the AWS Console (top navbar → terminal icon) and clone the demo project. It's important to clone via HTTPS when in CloudShell since cloning via SSH will result in Permission denied, even for public repos.

# Clone the repo via HTTPS
$ git clone https://github.com/Rushdown-Studios/GameLiftDemo.git
remote: Enumerating objects: 1234567, done.
...
Filtering content: 100% (3/3), 12.34 MiB | 5.67 MiB/s, done.

# cd into the root of the repo
$ cd GameLiftDemo/

# Pull the AWS GameLift Server SDK for Golang
$ ./scripts/setup.sh

# Verify that the project cloned and set up properly
$ ls
amazon-gamelift-go-sdk  cmd  docs  go.mod  go.sum  README.md  scripts

Step 2: Build and Upload

See also: Amazon GameLift Servers Developer Guide: Create a build from a file directory

Next, we'll build the server and upload it as an Amazon GameLift Servers Build. Since the CloudShell instance doesn't have Golang installed, we'll build the server in a Docker container. To simplify the process, there's a helper script to build the server binary and upload it all in one shot. If you want to know what it's doing under the hood, take a look at the script in scripts/build-and-upload.sh.

For now you can go ahead and run it without params. Note that this might take around 5 minutes to complete.

$ ./scripts/build-and-upload.sh
go: downloading github.com/golang/mock v1.6.0
go: downloading github.com/google/uuid v1.5.0
go: downloading github.com/gorilla/websocket v1.5.1
...

Uploading out:  2.6 MiB / 2.6 MiB  (100.00%) Successfully uploaded out to AWS GameLift
Build ID: build-00000000-0000-0000-0000-000000000000

Make a note of the Build ID, since you'll need it when making a fleet in the next step.

Step 3: Create a Fleet

See also: Amazon GameLift Servers Developer Guide: Create an Amazon GameLift Servers managed EC2 fleet

Now that we have a proper build uploaded, we can create a GameLift fleet that will pull that build and run it for us. Again, I have a helper script to simplify things here. Take a look at scripts/create-fleet.sh to see what's happening under the hood if you'd like, or run it like so to continue:

$ ./scripts/create-fleet.sh --build-id <Build ID>
{
    "FleetAttributes": {
        "FleetId": "fleet-00000000-0000-0000-0000-000000000000",
        "FleetType": "ON_DEMAND",
        ...
    }
}
Fleet created successfully.

Creating a new fleet takes some time. This example usually enters the ACTIVE state about 5 minutes after creation.

You can check the status of the fleet in two ways:

  • From the AWS Developer Console, under Amazon GameLift Servers -> Fleets, then choosing your fleet ID and looking in the Events tab
  • From the AWS CLI in your CloudShell session by running aws gamelift describe-fleet-events --fleet-id <fleet id>
    • You're ready to move on to the next section when you see a fleet event with FLEET_STATE_ACTIVE.

There's a helper script in scripts/wait-for-fleet.sh that uses the AWS CLI to poll every 30 seconds and print new status updates:

$ ./scripts/wait-for-fleet.sh --fleet-id <Fleet ID>
Monitoring fleet: fleet-00000000-0000-0000-0000-000000000000
Polling every 30 seconds

[2025-04-25 18:02:47] FLEET_CREATED
    -> Message:     Fleet fleet-00000000-0000-0000-0000-000000000000 has been created with state NEW.
    -> Description: Fleet resource created with status NEW.
...
[2025-04-25 18:08:32] FLEET_STATE_ACTIVE
    -> Message:     Fleet fleet-00000000-0000-0000-0000-000000000000 changed state to ACTIVE
    -> Description: Fleet is ACTIVE and ready.

If something goes wrong here, take a look at the debugging section.

Goal: Connecting Clients

Once the fleet is active, we're ready to spin up servers to host games. GameLift uses Game Sessions to manage server processes running on a fleet, so we'll need to start a Game Session on the fleet to start a server and get an IP and port. Then we can start the client and supply the IP and port.

In your CloudShell session, start a session with the AWS CLI:

$ aws gamelift create-game-session --fleet-id <fleet id> --maximum-player-session-count 1
{
    "GameSession": {
        "GameSessionId": "arn:aws:gamelift:us-west-2::gamesession/fleet-00000000-0000-0000-0000-000000000000/gsess-00000000-0000-0000-0000-000000000000",
        "Status": "ACTIVATING",
        "IpAddress": "1.2.3.4",
        "Port": 9000,
        ...
    }
}

Back on your local machine, you can use that IP and port when starting the client:

go run ./cmd/client -host <IP Address> -port <Port>

Like when we ran locally, you should be able to move around and see your character. You can start a mock client and see it moving in a circle:

go run ./cmd/mockclient -host <IP Address> -port <Port>

Clean Up

Remember that actively running instances in a fleet count against your quota, so when you're done, you'll want to delete your fleet so that you aren't burning your free balance (or being charged if you go over).

aws gamelift delete-fleet --fleet-id <Fleet ID>

You aren't charged for builds hanging around, but it's a good idea to clean up your builds when you're done:

aws gamelift delete-build --build-id <Build ID>

Debugging

See also: Amazon GameLift Servers Developer Guide: Debug Amazon GameLift Servers fleet issues

Even with a clean build and a solid deployment script, GameLift can sometimes feel like a bit of a black box—especially when something silently fails. This section covers the most common pain points you might hit and how to investigate them effectively.

Fleet Fails to Activate

If you're waiting for your fleet to spin up and it doesn't enter the ACTIVE state within 5-10 minutes, you might want to check in on it.

The easiest way to see what's going on with a fleet before it starts running is by going to the AWS Developer Console, under Amazon GameLift Servers -> Fleets, then choosing your fleet ID and looking in the Events tab. It should look something like this:

AWS Developer Console: Fleet failed to initialize events

AWS Developer Console: Fleet with failed to initialize events

In the example image above, we can see the SERVER_PROCESS_SDK_INITIALIZATION_TIMEOUT event, which tells us that GameLift found the server binary and tried to start it, but it either didn't start or it didn't successfully call InitSDK on startup. In this case, the message is telling us that we can try to get the game session log to investigate. We can't start a game session on a fleet that's in the ERROR state, but we can still try to connect to the instance and poke around ourselves! Check out the next session to see how to do that.

Sometimes the error messages will include a log reference, which will let you download logs from the failed step right from the Events tab and get more information about what went wrong. It's a good idea to check the build extraction step, just to make sure that all of your files extracted and are in the right place.

Even if your fleet is in an ERROR state, you can sometimes explore the compute instance to investigate further - see the next section to see how to do that.

Investigating a Running Fleet

Downloading Game Session Logs

If your fleet ran a game session (even briefly), you may be able to download logs from the Game Sessions tab in the AWS Console.

A couple tips:

  • We configure the fleet to collect logs via the --log flag when creating the fleet and starting the server.
  • GameLift will package and upload logs after the session ends.
  • To see terminated sessions, you may need to remove the "ACTIVE" filter in the Game Sessions list.

This will download a ZIP file with your server's log output.

AWS Developer Console: Game Sessions tab on a running fleet

AWS Developer Console: Game Sessions tab on a running fleet

AWS Developer Console: Download Game Session Logs

AWS Developer Console: Download Game Session Logs for a terminated Game Session

Connecting to the Fleet with CloudShell

See also: Amazon GameLift Servers Developer Guide: Remotely connect to Amazon GameLift Servers fleet instances

Sometimes logs aren't enough or you can't access them through the AWS Developer Portal and you want to poke around the server itself. GameLift doesn’t support direct SSH access, but you can start an interactive shell session using AWS Systems Manager (SSM). I’ve included a helper script scripts/connect-to-fleet.sh that uses the AWS CLI to start a session.

Quick notes:

  • Using this script (or the underlying aws ssm start-session command) required that the AWS SSM plugin is installed in your shell environment. When using CloudShell, this is preinstalled.
  • If your fleet has multiple instances, the script connects to the first one it finds. You can customize the script to target others as needed.

Let's take a look at how we can use the script. Run this from your CloudShell instance:

$ ./scripts/connect-to-fleet.sh <fleet-id>
Getting compute data...
Getting compute name...
Getting compute access for i-012345abcdef67890...
Starting SSM session...
Starting session with SessionId: FleetsService-GetComputeAccess-00000000-0000-0000-0000-000000000000

This session is encrypted using AWS KMS.
sh-5.2$ cd /local/game
sh-5.2$ ls -la
total 6504
drwxrwxr-x. 2 gl-user-server gl-user             50 Apr 23 23:10 .
drwxr-xr-x. 7 root           root                87 Apr 23 23:08 ..
-rw-r--r--. 1 gl-user-server gl-user-server   24911 Apr 24 18:54 GameLiftDemoServer.log
-rwxr-xr-x. 1 gl-user-server gl-user        6627620 Apr 23 23:08 server

Let's use this to investigate the error from the previous section. We saw that the fleet got a SERVER_PROCESS_SDK_INITIALIZATION_TIMEOUT, which meant that the server process either didn't start, or it failed to call InitSDK. We can see that the GameLiftDemoServer.log is present, which means that our server started at least long enough to log to the file. Let's get the last few lines and see if we can find anything out:

sh-5.2$ tail -5 GameLiftDemoServer.log 
2025/04/24 18:49:25 Server listening on :9000
2025/04/24 18:54:26 logging to: GameLiftDemoServer.log
2025/04/24 18:54:26 Server listening on :9000
2025/04/24 18:59:27 logging to: GameLiftDemoServer.log
2025/04/24 18:59:27 Server listening on :9000

We see that the server is starting and logging, but we’re missing the usual GameLift messages like:

  • Amazon GameLift InitSDK OK
  • Amazon GameLift ProcessReady OK

If the server tried but failed to initialize, we’d typically see something like:

  • Failed to initialize Amazon GameLift Servers

So what went wrong? In this case, I added a -gamelift flag which is required to run the server in GameLift mode but forgot to pass that flag in the fleet configuration. I confirmed this by checking the Runtime Configuration section of the Fleet’s Details tab:

AWS Developer Console: Fleet with misconfigured launch parameters

AWS Developer Console: Fleet with misconfigured launch parameters

The solution was to modify the RUNTIME_CONFIGURATION variable in the create-fleet.sh script

RUNTIME_CONFIGURATION=$(cat <<EOF
{
  "ServerProcesses": [
    {
      "LaunchPath": "/local/game/server",
      "ConcurrentExecutions": 1,
      "Parameters": "-gamelift -port=9000 -log=GameLiftDemoServer.log"
    }
  ],
  "GameSessionActivationTimeoutSeconds": 600
}
EOF
)

After fixing the script, I deleted the old fleet and recreated it with the updated configuration.

💡
You don't need to modify the script yourself - I updated the script in the repo before publishing.

What's Next?

Now that you've got a fleet up and running, here are a few next steps and tools worth checking out: