Skip to main content

Satellite on AWS ECS

Prerequisites​

Before installing the Levo Satellite on AWS ECS, ensure you have:

  • Access to AWS ECS
  • AWS credentials configured (aws configure with Access Key ID and Secret Access Key)
  • Levo Authorization Token (refer to Generating CLI Authorization Keys)
  • Organization ID (refer to Accessing Organization IDs)
  • IAM Role (choose one):
    • Option 1: Use the --create-iam-role flag in the CLI script to auto-create the role with required permissions
    • Option 2: Manually create an AWS IAM Role with the following permissions:
      • SQS Actions (for queue creation and management):
        • sqs:CreateQueue β€” Create queues on startup
        • sqs:SendMessage β€” Write messages to queues
        • sqs:ReceiveMessage β€” Read messages from queues
        • sqs:DeleteMessage β€” Remove processed messages
        • sqs:GetQueueAttributes β€” Get queue metadata
        • sqs:GetQueueUrl β€” Resolve queue URLs
        • sqs:ChangeMessageVisibility β€” Update message visibility timeout
        • sqs:SetQueueAttributes β€” Configure queue settings
        • sqs:TagQueue β€” Add tags to queues
      • SQS Resource Pattern: arn:aws:sqs:${REGION}:${ACCOUNT}:*-levoai_*
      • CloudWatch Logs Actions (for container logging):
        • logs:CreateLogGroup β€” Create log group
        • logs:CreateLogStream β€” Create log stream
        • logs:PutLogEvents β€” Write logs
      • ECR Actions (for pulling Docker images):
        • ecr:GetAuthorizationToken β€” Authenticate with ECR
        • ecr:BatchCheckLayerAvailability β€” Check image layers
        • ecr:GetDownloadUrlForLayer β€” Get layer download URLs
        • ecr:BatchGetImage β€” Pull Docker images
  • A VPC with at least one subnet and a security group allowing inbound TCP on port 8080
  • For Terraform: Terraform CLI installed
  • For CLI: AWS CLI v2 installed

Quick Start (CLI)​

Download the installation script:

curl -O https://docs.levo.ai/artifacts/satellite/install-satellite.sh
chmod +x install-satellite.sh

Then proceed to installation methods below.

Network Configuration (CLI Only)​

The Satellite requires a VPC, subnet, and security group. Choose the scenario that matches your setup:

Scenario 1: You Have VPC, Subnet, and Security Group​

If you already have these resources configured, use them directly:

./install-satellite.sh \
--region us-east-1 \
--org-id <YOUR_ORG_ID> \
--auth-key <YOUR_AUTH_KEY> \
--subnets subnet-abc123 \
--security-groups sg-xyz789 \
--create-iam-role \
--assign-public-ip

Requirements:

  • Security Group: Must allow inbound TCP on port 8080 from your sensor network (or 0.0.0.0/0 for testing)
  • Subnet: Any subnet with available IP addresses (private subnets recommended)
tip

You can specify multiple subnets (comma-separated) for high availability: --subnets subnet-abc123,subnet-def456

Scenario 2: You Have VPC, But Don't Know Which Subnet/Security Group to Use​

Discover available resources in your VPC:

# Step 1: List all subnets and security groups
./install-satellite.sh \
--list \
--vpc-id vpc-abc123 \
--region us-east-1

This shows:

  • All subnets with CIDR, availability zone, type (public/private), and available IPs
  • All security groups with port 8080 status (βœ“ = open, βœ— = closed)
# Step 2: Use the discovered IDs
./install-satellite.sh \
--region us-east-1 \
--org-id <YOUR_ORG_ID> \
--auth-key <YOUR_AUTH_KEY> \
--subnets subnet-abc123 \
--security-groups sg-xyz789 \
--create-iam-role \
--assign-public-ip
info

Choose a security group with βœ“ next to it (port 8080 already open). If none exist, use Scenario 3 to create one.

Scenario 3: You Have VPC, But Need to Create Subnet and/or Security Group​

Create both subnet and security group:

./install-satellite.sh \
--region us-east-1 \
--org-id <YOUR_ORG_ID> \
--auth-key <YOUR_AUTH_KEY> \
--vpc-id vpc-abc123 \
--create-subnet \
--create-security-group \
--sensor-cidr 10.0.0.0/16 \
--create-iam-role \
--assign-public-ip

Create only subnet (you have a security group):

./install-satellite.sh \
--region us-east-1 \
--org-id <YOUR_ORG_ID> \
--auth-key <YOUR_AUTH_KEY> \
--vpc-id vpc-abc123 \
--create-subnet \
--security-groups sg-xyz789 \
--create-iam-role \
--assign-public-ip

Create only security group (you have a subnet):

./install-satellite.sh \
--region us-east-1 \
--org-id <YOUR_ORG_ID> \
--auth-key <YOUR_AUTH_KEY> \
--vpc-id vpc-abc123 \
--create-security-group \
--sensor-cidr 10.0.0.0/16 \
--subnets subnet-abc123 \
--create-iam-role \
--assign-public-ip

Customize auto-created resources:

./install-satellite.sh \
--region us-east-1 \
--org-id <YOUR_ORG_ID> \
--auth-key <YOUR_AUTH_KEY> \
--vpc-id vpc-abc123 \
--create-subnet \
--subnet-cidr 10.1.20.0/24 \
--subnet-az us-east-1a \
--create-security-group \
--sensor-cidr 10.0.0.0/16 \
--create-iam-role \
--assign-public-ip
Customization FlagDefaultDescription
--subnet-cidr10.0.10.0/24CIDR block for new subnet
--subnet-az(first AZ in region)Availability zone for subnet
--sensor-cidr(required with --create-security-group)CIDR allowed inbound on ports 8080 and 4317
SECURITY CRITICAL

--sensor-cidr controls WHO can access your Satellite on ports 8080 and 4317.

# Use your VPC CIDR
--sensor-cidr 172.31.0.0/16

# Or your private network range
--sensor-cidr 10.0.0.0/8

# ⚠️ Testing only - EXPOSES TO PUBLIC INTERNET
--sensor-cidr 0.0.0.0/0

This flag is REQUIRED when using --create-security-group

Scenario 4: You Don't Have a VPC​

If you don't have a VPC, create one first using AWS Console or CLI:

Using AWS Console:

  1. Go to VPC Console
  2. Click Create VPC
  3. Choose VPC and more (creates VPC with subnets automatically)
  4. Note the VPC ID and subnet IDs
  5. Use Scenario 1 or 2 above

Using AWS CLI:

# Create VPC
aws ec2 create-vpc --cidr-block 10.0.0.0/16 --region us-east-1

# Note the VPC ID from output, then use Scenario 3 to create subnet and security group
Always Test First

Run any command with --dry-run flag first to preview what will be created without making actual changes.

1. Create a Task Definition​

NOTE: Ensure you are in the correct AWS region where you want to deploy your service

  • Use the following task definition:
{
"family": "levoai-satellite",
"containerDefinitions": [
{
"name": "levoai-satellite",
"image": "levoai/satellite:stable",
"cpu": 0,
"portMappings": [
{
"name": "levoai-satellite-9999-tcp",
"containerPort": 9999,
"hostPort": 9999,
"protocol": "tcp",
"appProtocol": "http"
}
],
"essential": true,
"command": [
"-w",
"1",
"-b",
"0.0.0.0:9999",
"--worker-class",
"uvicorn.workers.UvicornWorker",
"--worker-connections",
"30",
"levoai_e7s.satellite.satellite:create_server()"
],
"environment": [
{
"name": "LEVOAI_BASE_URL",
"value": "https://api.levo.ai"
},
{
"name": "LEVOAI_ORG_ID",
"value": "INSERT YOUR ORG ID HERE"
},
{
"name": "LEVOAI_MODE",
"value": "docker-compose"
},
{
"name": "AWS_DEFAULT_REGION",
"value": "INSERT YOUR AWS REGION HERE"
},
{
"name": "LEVOAI_CONF_OVERRIDES",
"value": "{\"onprem-api\": {\"url\": \"${LEVOAI_BASE_URL}\", \"refresh-token\": \"${LEVOAI_AUTH_KEY}\", \"org-id\": \"${LEVOAI_ORG_ID:-}\", \"org-prefix\": \"${LEVOAI_ORG_PREFIX:-}\"},\"traces_queue\": {\"type\": \"sqs\"},\"spans_queue\": {\"type\": \"sqs\"},\"findings_queue\": {\"type\": \"sqs\"},\"mcp_span_queue\": {\"type\": \"sqs\"},\"ai_span_queue\": {\"type\": \"sqs\"}}"
},
{
"name": "LEVOAI_DEBUG_ENABLED",
"value": "false"
},
{
"name": "LEVOAI_AUTH_KEY",
"value": "INSERT YOUR LEVO.AI AUTH KEY HERE"
},
{
"name": "LEVOAI_LOG_LEVEL",
"value": "INFO"
}
],
"mountPoints": [],
"volumesFrom": [],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/levoai-satellite",
"awslogs-create-group": "true",
"awslogs-region": "INSERT YOUR AWS REGION HERE",
"awslogs-stream-prefix": "ecs"
}
},
"systemControls": []
},
{
"name": "levoai-tagger",
"image": "levoai/satellite:stable",
"cpu": 0,
"portMappings": [],
"essential": true,
"entryPoint": [
"python",
"-OO"
],
"command": [
"/opt/levoai/e7s/src/python/levoai_e7s/tag_server.py"
],
"environment": [
{
"name": "LEVOAI_BASE_URL",
"value": "https://api.levo.ai"
},
{
"name": "LEVOAI_ORG_ID",
"value": "INSERT YOUR ORG ID HERE"
},
{
"name": "LEVOAI_MODE",
"value": "docker-compose"
},
{
"name": "AWS_DEFAULT_REGION",
"value": "INSERT YOUR AWS REGION HERE"
},
{
"name": "LEVOAI_CONF_OVERRIDES",
"value": "{\"onprem-api\":{\"url\": \"${LEVOAI_BASE_URL}\",\"refresh-token\":\"${LEVOAI_AUTH_KEY}\",\"org-id\": \"${LEVOAI_ORG_ID}\",\"org-prefix\": \"${LEVOAI_ORG_PREFIX}\"},\"dynamic_url_threshold_factor\": 0.5,\"api_rule_evaluation\":{\"enabled\": true},\"enable_ssl_cert_checks\": true,\"traces_queue\":{\"type\": \"sqs\"},\"spans_queue\":{\"type\": \"sqs\"},\"findings_queue\":{\"type\": \"sqs\"},\"mcp_span_queue\":{\"type\": \"sqs\"},\"ai_span_queue\":{\"type\": \"sqs\"}}"
},
{
"name": "PI_DETECTOR_DATA_DIR",
"value": "/opt/levoai/datasets/"
},
{
"name": "LEVOAI_DEBUG_ENABLED",
"value": "false"
},
{
"name": "LEVOAI_AUTH_KEY",
"value": "INSERT YOUR LEVO.AI AUTH KEY HERE"
},
{
"name": "LEVOAI_LOG_LEVEL",
"value": "INFO"
}
],
"mountPoints": [],
"volumesFrom": [],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/levoai-satellite",
"awslogs-create-group": "true",
"awslogs-region": "INSERT YOUR AWS REGION HERE",
"awslogs-stream-prefix": "ecs"
}
},
"systemControls": []
},
{
"name": "levoai-collector",
"image": "levoai/collector:stable",
"cpu": 0,
"portMappings": [
{
"name": "levoai-collector-4317-tcp",
"containerPort": 4317,
"hostPort": 4317,
"protocol": "tcp",
"appProtocol": "http"
}
],
"essential": true,
"command": [
"--config",
"/etc/opt/levoai/config-ecs.yml"
],
"environment": [],
"mountPoints": [],
"volumesFrom": [],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/levoai-satellite",
"awslogs-create-group": "true",
"awslogs-region": "INSERT YOUR AWS REGION HERE",
"awslogs-stream-prefix": "ecs"
}
},
"systemControls": []
},
{
"name": "levoai-haproxy",
"image": "levoai/haproxy:stable",
"cpu": 0,
"portMappings": [
{
"name": "levoai-haproxy-8080-tcp",
"containerPort": 8080,
"hostPort": 8080,
"protocol": "tcp",
"appProtocol": "http"
}
],
"essential": true,
"command": [
"-f",
"/levo/haproxy-ecs.cfg"
],
"environment": [
{
"name": "LEVOAI_ORG_ID",
"value": "INSERT YOUR ORG ID HERE"
},
{
"name": "LEVOAI_SATELLITE_AUTHN_ENABLED",
"value": "false"
},
{
"name": "LEVOAI_CONF_OVERRIDES",
"value": "{\"org-id\": \"INSERT YOUR ORG ID HERE\"}"
}
],
"mountPoints": [],
"volumesFrom": [],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/levoai-satellite",
"awslogs-create-group": "true",
"awslogs-region": "INSERT YOUR AWS REGION HERE",
"awslogs-stream-prefix": "ecs"
}
},
"systemControls": []
}
],
"taskRoleArn": "INSERT THE ARN OF THE ROLE YOU WANT TO ASSIGN TO THIS TASK HERE",
"executionRoleArn": "INSERT THE ARN OF THE ROLE YOU WANT TO ASSIGN TO THIS TASK HERE",
"networkMode": "awsvpc",
"volumes": [],
"placementConstraints": [],
"requiresCompatibilities": [
"FARGATE"
],
"cpu": "4096",
"memory": "8192",
"runtimePlatform": {
"cpuArchitecture": "X86_64",
"operatingSystemFamily": "LINUX"
}
}
info

Depending on the region you are installing in, you may need to set a different Levo base URL for the satellite.

For example, if the satellite will be used with app.india-1.levo.ai, set the LEVOAI_BASE_URL environment variable as

{
"name": "LEVOAI_BASE_URL",
"value": "https://api.india-1.levo.ai"
},

2. Run the Satellite​

Now that the task definition is created, deploy the Satellite as a service in an ECS cluster:

  • Open the levo-satellite task definition and select the latest revision
  • Navigate to Deploy and select Create Service
  • Choose the cluster where you want to deploy the Satellite
  • Under Compute Options, select Launch Type
  • Add a Service name in the Deployment configuration
  • Leave other configurations at their default settings and start the service

3. Retrieval Port & External Access​

After deployment, the Satellite is accessible at:

External Endpoint: <public-ip>:8080 (via HAProxy)

Public IP Location: ECS Task Details β†’ Container details β†’ Network bindings β†’ External link

Example: <PUBLIC_IP>:8080 (e.g., 52.32.232.165:8080)

Protocol: HTTP (can be wrapped in your own TLS layer)

Port 8080 is the retrieval port used for communication between the Satellite and Sensors.

To find the public IP:

  • Head over to the cluster you earlier used to run the satellite on
  • Click on Tasks and select the particular satellite task
  • Under the Container details for levoai-haproxy, go to Network bindings

It should look something like this:

Network bindings
Host port Container port Protocol External link
8080 8080 tcp <PUBLIC_IP>:8080
info

NOTE: If you're unable to reach the Satellite, add the necessary inbound rules to the security group used by this task.

Record this informationβ€”you'll need it to configure the Sensor.

Verify Satellite is running:

curl http://{satellite-ip}:8080/health

Finding Private IP (for VPC-internal sensors):

AWS Console: ECS β†’ Tasks β†’ Click task β†’ Private IP address

AWS CLI:

aws ecs describe-tasks --cluster levoai-satellite \
--tasks $(aws ecs list-tasks --cluster levoai-satellite --query 'taskArns[0]' --output text) \
--query 'tasks[0].attachments[0].details[?name==`privateIPv4Address`].value' --output text

Use: http://{private-ip}:8080

Please proceed to install traffic capture sensors.


Viewing Satellite Logs​

Download the log viewer script:

curl -O https://docs.levo.ai/artifacts/satellite/levo-logs.sh
chmod +x levo-logs.sh

The Levo Satellite deployment includes multiple containers, each writing logs to CloudWatch. You can view logs for individual containers or all containers together.

Log Levels​

The Satellite supports two log levels controlled by the LEVOAI_LOG_LEVEL environment variable:

  • INFO (default) β€” Standard operational logs showing key events, API calls, and processing status
  • DEBUG β€” Verbose logs including internal operations, SQS polling, AWS authentication, metrics collection, and detailed request/response data

To change the log level, update the LEVOAI_LOG_LEVEL environment variable in your task definition and redeploy:

  1. Open your task definition in the ECS console
  2. Find the levoai-satellite and levoai-tagger containers
  3. Update the LEVOAI_LOG_LEVEL environment variable to DEBUG
  4. Create a new revision and update your service
tip

Use DEBUG level for troubleshooting issues or understanding internal behavior. For production deployments, INFO level is recommended to reduce log volume and costs.

Viewing Logs by Container​

The Satellite deployment consists of four containers, each writing to separate log streams within the same CloudWatch log group (/ecs/levoai-satellite):

  • satellite β€” Main API processing, SQS queue polling, authentication, metrics (stream: ecs/levoai-satellite/)
  • tagger β€” API cataloging, endpoint mapping, schema detection (stream: ecs/levoai-tagger/)
  • collector β€” OpenTelemetry trace collection and processing (stream: ecs/levoai-collector/)
  • haproxy β€” Incoming HTTP connections on port 8080 (stream: ecs/levoai-haproxy/)

Each container writes to its own log stream, so you can view them separately or all together.

View logs for a specific container (replace <YOUR_CLUSTER> and <YOUR_REGION> with your values):

# View satellite logs (main processing)
./levo-logs.sh satellite --cluster <YOUR_CLUSTER> --region <YOUR_REGION>

# View haproxy logs (incoming connections - clean, simple logs)
./levo-logs.sh haproxy --cluster <YOUR_CLUSTER> --region <YOUR_REGION>

# View tagger logs (API cataloging)
./levo-logs.sh tagger --cluster <YOUR_CLUSTER> --region <YOUR_REGION>

# View collector logs (OpenTelemetry)
./levo-logs.sh collector --cluster <YOUR_CLUSTER> --region <YOUR_REGION>

Additional options:

# View logs from the last hour
./levo-logs.sh satellite --cluster <YOUR_CLUSTER> --since 1h --region <YOUR_REGION>

# View logs without following (print and exit)
./levo-logs.sh haproxy --cluster <YOUR_CLUSTER> --no-follow --region <YOUR_REGION>

# Export logs to a file (for sharing or analysis)
./levo-logs.sh satellite --cluster <YOUR_CLUSTER> --export --export-file satellite-logs.txt --since 2h --region <YOUR_REGION>
./levo-logs.sh haproxy --cluster <YOUR_CLUSTER> --export --export-file haproxy-logs.txt --since 2h --region <YOUR_REGION>
./levo-logs.sh tagger --cluster <YOUR_CLUSTER> --export --export-file tagger-logs.txt --since 2h --region <YOUR_REGION>
./levo-logs.sh collector --cluster <YOUR_CLUSTER> --export --export-file collector-logs.txt --since 2h --region <YOUR_REGION>

# Specify custom log group (if not using default /ecs/levoai-satellite)
./levo-logs.sh satellite --cluster <YOUR_CLUSTER> --log-group /ecs/my-custom-log-group --region <YOUR_REGION>
tip

Replace <YOUR_CLUSTER> with your ECS cluster name (e.g., levoai-satellite) and <YOUR_REGION> with your AWS region (e.g., us-east-1).

Using AWS CLI Directly​

# View ALL satellite logs (all containers mixed together)
aws logs tail /ecs/levoai-satellite --follow --format short --region <YOUR_REGION>

# View logs from a SPECIFIC container only
aws logs tail /ecs/levoai-satellite \
--log-stream-name-prefix ecs/levoai-haproxy/ \
--follow --format short --region <YOUR_REGION>

# View satellite container logs only
aws logs tail /ecs/levoai-satellite \
--log-stream-name-prefix ecs/levoai-satellite/ \
--follow --format short --region <YOUR_REGION>
tip

Without --log-stream-name-prefix, the AWS CLI will show logs from all containers mixed together, which can be overwhelming when DEBUG logging is enabled. Use the log viewer script or specify the stream prefix to view individual container logs.

Using AWS Console​

  1. Navigate to CloudWatch β†’ Log groups
  2. Select /ecs/levoai-satellite
  3. You'll see multiple log streams - use the filter dropdown to select a specific container:
    • ecs/levoai-satellite/ β€” Satellite logs
    • ecs/levoai-haproxy/ β€” HAProxy logs
    • ecs/levoai-tagger/ β€” Tagger logs
    • ecs/levoai-collector/ β€” Collector logs
  4. Or use the search bar to filter log content by text
Was this page helpful?