Overview
The backend API runs as a Docker container on AWS ECS Fargate behind an Application Load Balancer. This section covers building the Docker image, pushing to ECR, and deploying to ECS.
Deployment Architecture
Build Docker Image
The backend uses a Python 3.11 slim base image with FastAPI and crawling dependencies.
Review Dockerfile
The backend/Dockerfile contains:
FROM python:3.11-slim
WORKDIR /app
# Install system dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
curl \
&& rm -rf /var/lib/apt/lists/*
# Install Python dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy application code
COPY . .
EXPOSE 8000
# Run FastAPI server
CMD [ "uvicorn" , "main:app" , "--host" , "0.0.0.0" , "--port" , "8000" ]
The container exposes port 8000 for the FastAPI application.
Build the Image
Navigate to backend directory and build:
cd backend
docker build -t llmstxt-api:latest .
Expected output:
[+] Building 45.2s (11/11) FINISHED
=> [internal] load build definition from Dockerfile
=> => transferring dockerfile: 350B
=> [internal] load .dockerignore
=> [1/6] FROM docker.io/library/python:3.11-slim
=> [2/6] WORKDIR /app
=> [3/6] RUN apt-get update && apt-get install -y curl
=> [4/6] COPY requirements.txt .
=> [5/6] RUN pip install --no-cache-dir -r requirements.txt
=> [6/6] COPY . .
=> exporting to image
=> => writing image sha256:abc123...
=> => naming to docker.io/library/llmstxt-api:latest
Docker image built successfully! Image size should be around 500-700MB.
Test Image Locally (Optional)
Run container locally to verify
Test the built image before pushing to ECR: # Create .env file with test credentials
cat > .env << EOF
SUPABASE_URL=https://your-project.supabase.co
SUPABASE_KEY=your-key
R2_ENDPOINT=https://your-endpoint.r2.cloudflarestorage.com
R2_ACCESS_KEY=your-access-key
R2_SECRET_KEY=your-secret-key
R2_BUCKET=llmstxt
R2_PUBLIC_DOMAIN=https://pub-xxxxx.r2.dev
CORS_ORIGINS=*
API_KEY=test-key
CRON_SECRET=test-secret
EOF
# Run container
docker run -p 8000:8000 --env-file .env llmstxt-api:latest
Test the health endpoint: curl http://localhost:8000/health
# Expected: {"status":"ok"}
Stop the container with Ctrl+C.
Push Image to Amazon ECR
Get ECR Repository URL
Retrieve the ECR repository URL from Terraform:
cd ../terraform
terraform output ecr_repository_url
Example output:
123456789012.dkr.ecr.us-east-1.amazonaws.com/llmstxt-api
Save this as an environment variable:
export ECR_REPO = $( terraform output -raw ecr_repository_url )
echo $ECR_REPO
Authenticate Docker with ECR
Log in to ECR using AWS CLI:
aws ecr get-login-password --region us-east-1 | \
docker login --username AWS --password-stdin \
$ECR_REPO
Expected output:
ECR authentication tokens expire after 12 hours. Re-run this command if you get authentication errors.
Tag Image for ECR
Tag the local image with the ECR repository URL:
cd ../backend
docker tag llmstxt-api:latest $ECR_REPO :latest
Verify the tag:
docker images | grep llmstxt-api
You should see both tags:
llmstxt-api latest abc123... 5 minutes ago 650MB
123456789012.dkr.ecr.us-east-1.amazonaws.com/llmstxt-api latest abc123... 5 minutes ago 650MB
Push Image to ECR
Push the tagged image to ECR:
docker push $ECR_REPO :latest
Expected output:
The push refers to repository [123456789012.dkr.ecr.us-east-1.amazonaws.com/llmstxt-api]
5f70bf18a086: Pushed
6e62e7c2e5a5: Pushed
3abc4def5678: Pushed
...
latest: digest: sha256:1234567890abcdef... size: 2345
This takes 2-5 minutes depending on your internet connection.
Image successfully pushed to ECR!
Deploy to ECS
Force New Deployment
Trigger ECS to pull the new image and deploy:
aws ecs update-service \
--cluster llmstxt-cluster \
--service llmstxt-api-service \
--force-new-deployment \
--region us-east-1
Expected output:
{
"service" : {
"serviceName" : "llmstxt-api-service" ,
"clusterArn" : "arn:aws:ecs:us-east-1:...:cluster/llmstxt-cluster" ,
"deployments" : [
{
"status" : "PRIMARY" ,
"desiredCount" : 1 ,
"runningCount" : 0
}
]
}
}
Monitor Deployment Progress
Watch the deployment status:
watch -n 5 'aws ecs describe-services \
--cluster llmstxt-cluster \
--services llmstxt-api-service \
--query "services[0].deployments" \
--region us-east-1'
Press Ctrl+C to stop watching. Deployment typically takes 3-5 minutes.
Look for:
Running count : Should increase from 0 to 1
Desired count : Should be 1
Status : Should be “PRIMARY”
Check Task Status
Verify the ECS task is running:
aws ecs list-tasks \
--cluster llmstxt-cluster \
--service-name llmstxt-api-service \
--region us-east-1
Expected output:
{
"taskArns" : [
"arn:aws:ecs:us-east-1:...:task/llmstxt-cluster/abc123def456"
]
}
If you see a task ARN, the container is running!
View Task Details
Get detailed task information:
# Get task ARN
TASK_ARN = $( aws ecs list-tasks \
--cluster llmstxt-cluster \
--service-name llmstxt-api-service \
--query 'taskArns[0]' \
--output text \
--region us-east-1 )
# Describe task
aws ecs describe-tasks \
--cluster llmstxt-cluster \
--tasks $TASK_ARN \
--region us-east-1
Check lastStatus: should be RUNNING.
Verify Deployment
Get Load Balancer URL
cd ../terraform
terraform output alb_dns_name
Example output:
llmstxt-alb-1234567890.us-east-1.elb.amazonaws.com
Test Health Endpoint
Wait 30-60 seconds for the ALB health check to pass, then test:
curl http:// $( terraform output -raw alb_dns_name ) /health
Expected response:
Backend API is live and healthy!
Test WebSocket Endpoint
Test WebSocket connection (optional)
Install websocat for WebSocket testing: # macOS
brew install websocat
# Linux
wget https://github.com/vi/websocat/releases/latest/download/websocat_linux64
chmod +x websocat_linux64
sudo mv websocat_linux64 /usr/local/bin/websocat
Test crawl endpoint: ALB_URL = $( cd terraform && terraform output -raw alb_dns_name )
API_KEY = "your-api-key-from-terraform-tfvars"
echo '{"url":"https://example.com","maxPages":5,"descLength":200}' | \
websocat "ws://${ ALB_URL }/ws/crawl?api_key=${ API_KEY }"
You should see streaming crawl progress messages.
View Container Logs
Via AWS CLI
View recent application logs:
aws logs tail /ecs/llmstxt-api \
--follow \
--region us-east-1
Via AWS Console
Go to CloudWatch Console
Navigate to Logs → Log groups
Open /ecs/llmstxt-api
View log streams (one per task/container)
Check for Errors
Search logs for error messages:
aws logs filter-log-events \
--log-group-name /ecs/llmstxt-api \
--filter-pattern "ERROR" \
--region us-east-1
Updating the Application
To deploy code changes:
Make Code Changes
Edit backend code in backend/ directory.
Rebuild Docker Image
cd backend
docker build -t llmstxt-api:latest .
Tag and Push to ECR
docker tag llmstxt-api:latest $ECR_REPO :latest
docker push $ECR_REPO :latest
Force ECS Deployment
aws ecs update-service \
--cluster llmstxt-cluster \
--service llmstxt-api-service \
--force-new-deployment \
--region us-east-1
Monitor Deployment
Watch deployment progress and verify health endpoint.
ECS performs a rolling deployment: new task starts before old task stops (zero downtime).
Troubleshooting
Check task stopped reason :aws ecs describe-tasks \
--cluster llmstxt-cluster \
--tasks $TASK_ARN \
--query 'tasks[0].stoppedReason'
Common issues:
Image pull error : Verify ECR authentication
Task execution role : Check IAM permissions
Environment variables : Verify Terraform configuration
Check ALB target health :aws elbv2 describe-target-health \
--target-group-arn $( cd terraform && terraform output -raw target_group_arn )
If unhealthy:
Verify container is listening on port 8000
Check security group allows ALB → ECS traffic
Review container logs for startup errors
Verify security group :aws ec2 describe-security-groups \
--filters "Name=tag:Name,Values=llmstxt-alb-sg" \
--query 'SecurityGroups[0].IpPermissions'
Ensure port 80 and 443 are open to 0.0.0.0/0.
Increase task memory :Edit terraform/ecs.tf: resource "aws_ecs_task_definition" "llmstxt_api" {
# ...
memory = "2048" # Increase from 1024 to 2048 (2GB)
}
Apply changes: cd terraform
terraform apply
Scaling Configuration
Manual Scaling
Increase the number of running tasks:
aws ecs update-service \
--cluster llmstxt-cluster \
--service llmstxt-api-service \
--desired-count 2 \
--region us-east-1
Auto Scaling (Optional)
Configure ECS Auto Scaling based on CPU
Next Steps
Frontend Deployment Deploy the Next.js frontend to Vercel