How to Build a Test App to Manage Callaba Engine on AWS
This tutorial is based on the real aws-react-nodejs-example project used to test and manage Callaba Engine on AWS. It is not a generic architecture article. It is a practical walkthrough of a small two-part example app: an Express server that manages AWS instance actions, and a React client that drives the Callaba Engine workflow from the browser.
If your goal is to prove the control path end to end before building a larger internal panel, this is the right scope. By the end, you should have AWS credentials configured, region-specific infrastructure values in place, the Node.js server running, the React client running, and a working flow for creating an instance, authenticating to Callaba, creating an SRT server, and opening a web player.
Clone the example project
This tutorial follows the real repository used for this setup. Clone it locally before you start so you can compare each step with the actual server and client code.
git clone https://gitlab.callabacloud.com/callaba-engine-examples/aws-react-nodejs-example.git
Open the aws-react-nodejs-example repository on GitLab
Project structure
The example repository is split into two small parts:
- server — an Express app that works with AWS through
@aws-sdk/client-ec2 - client — a React app that talks to the local server and then calls the Callaba Engine API on the launched instance
This split is useful because it keeps AWS-facing logic and browser-facing control logic separate from the start.
Prerequisites
- An AWS account
- Node.js installed on your computer
- Permission to create AWS access keys, a security group, and a key pair in the target region
- A local machine where you can run both the server and client folders from the example project
Step 1. Create and download AWS access keys
The example uses the standard AWS credentials flow. Start by creating the access key pair for the IAM user or role you want to use during testing.
- Log in to the AWS Console.
- Open your username menu and go to Security credentials.
- Expand Access keys.
- Create a new access key.
- Download and store the key pair securely.


Step 2. Create the AWS credentials file
On macOS and Linux, create the credentials file at ~/.aws/credentials. On Windows, create it at C:\Users\<USER_NAME>\.aws\credentials. Put the default profile in this format:
[default]
aws_access_key_id = YOUR_ACCESS_KEY_ID
aws_secret_access_key = YOUR_SECRET_ACCESS_KEY
The server side of the example relies on the AWS SDK reading this file automatically.
Step 3. Create the security group in the correct region
The README is explicit about this: create the security group in the same region where you plan to launch the instances. If the region is wrong here, the test app quickly becomes confusing because the local code and the actual AWS environment drift apart.
The example security group uses a broad test posture:
- Inbound: All TCP from Anywhere IPv4
- Inbound: All UDP from Anywhere IPv4
- Outbound: All Traffic
Once you create it, copy the security group ID and place it into server/index.js:
const SECURITY_GROUP = "sg-XXXXXXXXXXXX"; // REPLACE WITH YOUR SECURITY GROUP ID


Step 4. Create the key pair
Create the EC2 key pair in the same AWS region. Save the key pair name and place it into the same file:
const KEY_PAIR_NAME = "your-key-pair-name"; // REPLACE WITH YOUR KEY PAIR NAME
The example server uses this constant when it launches the instance.

Step 5. Set the AWS region in the server
Still in server/index.js, set the region you actually chose in AWS:
const REGION = "us-east-1"; // REPLACE WITH YOUR REGION
This constant is used when the EC2 client is created:
const ec2Client = new EC2Client({ region: REGION });
Step 6. Understand what the server side does
The server app is intentionally small. It gives the client a clean local control layer for AWS actions.
Inside server/index.js, the example exposes four routes:
/describe— describe existing instances/create— create a new AWS instance/start— start the current instance/stop— stop the current instance
The key creation function looks like this conceptually:
async function createInstance(name, imageId, type) {
const instanceParams = {
ImageId: imageId,
InstanceType: type,
KeyName: KEY_PAIR_NAME,
SecurityGroupIds: [SECURITY_GROUP],
MinCount: 1,
MaxCount: 1,
};
const data = await ec2Client.send(new RunInstancesCommand(instanceParams));
return data.Instances[0].InstanceId;
}
This is why the repo is useful as a test app: it does not try to hide the infrastructure step. It makes it explicit and easy to inspect.
Step 7. Run the server
Open the server directory and run:
npm i
node index.js
According to the example README, a healthy startup looks like this:
Your AMI creation date is - 5/3/2022
Server listening on 3001
That tells you the AWS SDK is reading credentials correctly and the local Express layer is ready.
Step 8. Run the React client
In a second terminal, move into the client folder and run:
npm i
npm start
The client package is configured with a local proxy to the Express server:
"proxy": "http://localhost:3001"
This is what lets the browser-side app talk to the local AWS control layer while still driving the actual Callaba workflow.
Step 9. Launch and observe the instance
From the client UI, create a new instance and wait for AWS to finish launching it. The README warns that once the instance reaches Running, billing starts. This is important in a test app because it is easy to forget that a successful proof of concept is still a real paid resource in AWS.

Step 10. Authenticate to Callaba Engine
Once the instance is running, the client authenticates to the Callaba Engine API on that instance. The example code uses the instance ID as the first password value when requesting a token:
authenticate() {
fetch('http://' + this.state.ipAddress + '/api/auth/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: 'admin',
password: this.state.instanceData.Reservations[this.state.instanceIndex].Instances[0].InstanceId,
}),
})
.then(response => response.json())
.then(data => {
this.setState({ callabaToken: data.token });
});
}
The practical point here is simple: the client stores the Callaba token and uses it to sign later requests.
Step 11. Create an SRT server
The next real workflow step in the example is creating an SRT server on the Callaba instance. This is the first meaningful media control action in the app.
createStream() {
fetch('http://' + this.state.ipAddress + '/api/srt-servers/create', {
method: 'POST',
headers: {
'x-access-token': this.state.callabaToken,
'Content-Type': 'application/json',
},
body: JSON.stringify({
server_name: 'Test SRT server',
server_type: 'SERVER_TYPE_SRT',
server_port: 1935,
server_latency: 200,
server_maxbw: -1,
server_timeout: 60,
server_rcvbuf: 48234496,
server_active: true,
}),
})
.then(response => response.json())
.then(data => {
this.setState({ serverId: data._id, serverState: 'server running' });
});
}
This is the clean handoff from infrastructure control into actual streaming workflow control.

Step 12. Create a web player for the stream
To validate playback, the example creates a web player that points to the SRT server you just created.
createPlayer() {
fetch('http://' + this.state.instanceData.Reservations[this.state.instanceIndex].Instances[0].PublicIpAddress + '/api/vod/create', {
method: 'POST',
headers: {
'accept': 'application/json',
'x-access-token': this.state.callabaToken,
'Content-Type': 'application/json',
},
body: JSON.stringify({
active: true,
input: {
input_module_id: this.state.serverId,
input_stream_id: '',
input_type: 'INPUT_TYPE_SRT_SOFTWARE',
},
vod_name: 'Test SRT player',
vod_port: 10001,
}),
})
.then(response => response.json())
.then(data => this.setState({ playerId: data._id, playerState: 'running' }));
}
The app then generates the player URL from the instance IP and the created player ID so you can open the live stream in the browser.

Other actions the example already includes
The repo does more than only create resources. It also includes the first useful lifecycle actions:
- Stop an SRT server
- Start a stopped SRT server
- Delete an SRT server
- Remove a web player
- Create a restream
- Remove a restream
That is why this repository is a strong test app: it starts small, but it already contains enough lifecycle control to become a real operator-side proof of concept.
Common problems and fixes
- AWS credentials do not load: verify the
credentialsfile path and confirm the default profile is correct. - Region mismatch: check the security group, key pair, and
REGIONconstant inserver/index.js. - The server does not start: run
npm iin theserverfolder and verify Node.js is installed. - The client cannot reach the local backend: confirm the React client is still using the proxy value
http://localhost:3001. - Callaba API actions fail after instance launch: separate AWS problems from Callaba authentication problems and verify them one at a time.
- Costs continue after testing: stop or terminate the instance when the session is over.
Next steps
Once this example works, you no longer have to guess whether your AWS and Callaba control path can work together. You already have a real baseline project. From here, the next practical move is to replace hardcoded test values with your own workflow logic.
- Use Callaba Engine documentation to map the broader API surface.
- Go deeper into SRT servers if ingest is your next boundary.
- Use Video API if the test app is growing into a larger product integration.
- Use continuous streaming if your real goal is ongoing production ingest and delivery.