AWS
intermediate
30-45 minutes

Deploy with AWS App Runner

The fastest way to deploy containers on AWS. Push your Docker image and get a running URL in minutes.

What you'll accomplish

Your containerized application running on AWS with a public URL

Prerequisites

  • AWS CLI configured (previous lessons)
  • Docker installed and running
  • A Dockerized application ready to deploy

What is App Runner?

AWS App Runner is the simplest way to run containers on AWS. You give it a Docker image, and it handles:

  • Provisioning servers
  • Load balancing
  • Auto-scaling
  • SSL certificates
  • Health monitoring

Cost: Compute charges are approximately $0.064/vCPU-hour and $0.007/GB-hour for memory (pricing varies by region—check AWS App Runner Pricing for current rates). When paused, you avoid compute charges but may still incur costs for provisioned resources depending on your configuration.

Note

App Runner is perfect for web applications, APIs, and microservices. It's not suitable for background workers, cron jobs, or applications that need persistent disk storage.

Step 1: Prepare Your Application

1.1 Ensure You Have a Dockerfile

Your project needs a Dockerfile. Here's a minimal example for a Node.js app:

dockerfile
# Build stage
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Production stage
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY package*.json ./

ENV NODE_ENV=production
ENV PORT=8080
EXPOSE 8080

CMD ["node", "dist/index.js"]
Note

App Runner requires your app to listen on the port specified in the PORT environment variable (default 8080). Make sure your app reads this variable!

1.2 Add a Health Check Endpoint

App Runner checks / by default. Add an explicit health endpoint:

javascript
// Express.js example
app.get('/health', (req, res) => {
  res.status(200).json({ status: 'healthy' });
});

1.3 Test Locally

bash
# Build the image
docker build -t myapp .

# Run it locally
docker run -p 8080:8080 -e PORT=8080 myapp

# Test it
curl http://localhost:8080/health

Step 2: Create an ECR Repository

ECR (Elastic Container Registry) is AWS's Docker image storage. App Runner needs your image in ECR.

2.1 Create the Repository

2.2 Get Your Account ID

bash
# Get your AWS account ID
aws sts get-caller-identity --query Account --output text

Save this - you'll need it for the next commands. Let's call it ACCOUNT_ID.

Step 3: Push Your Image to ECR

3.1 Authenticate Docker with ECR

3.2 Tag Your Image

bash
# Tag for ECR (replace ACCOUNT_ID with your actual account ID)
docker tag myapp:latest ACCOUNT_ID.dkr.ecr.us-east-1.amazonaws.com/myapp:latest

3.3 Push to ECR

bash
# Push the image
docker push ACCOUNT_ID.dkr.ecr.us-east-1.amazonaws.com/myapp:latest

This may take a few minutes depending on your image size and internet speed.

3.4 Verify the Push

bash
# List images in your repository
aws ecr describe-images --repository-name myapp --region us-east-1

Step 4: Create App Runner Access Role

App Runner needs permission to pull images from ECR. Let's create the necessary IAM role.

4.1 Create the Trust Policy

Create a file called trust-policy.json:

json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "build.apprunner.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
Note

Note: AWS service principals can change over time. If you encounter permission errors, verify the current App Runner service principal in the AWS App Runner documentation.

4.2 Create the Role

bash
# Create the IAM role
aws iam create-role \
  --role-name AppRunnerECRAccessRole \
  --assume-role-policy-document file://trust-policy.json

# Attach the ECR access policy
aws iam attach-role-policy \
  --role-name AppRunnerECRAccessRole \
  --policy-arn arn:aws:iam::aws:policy/service-role/AWSAppRunnerServicePolicyForECRAccess

4.3 Get the Role ARN

bash
# Get the role ARN (you'll need this)
aws iam get-role --role-name AppRunnerECRAccessRole --query Role.Arn --output text

Save this ARN for the next step.

Step 5: Create the App Runner Service

Option A: Using the AWS Console (Easier for First Time)

  1. Go to the App Runner Console
  2. Click Create service
  3. For Source, select Container registry → Amazon ECR
  4. Click Browse and select your image
  5. For ECR access role, select the AppRunnerECRAccessRole you created
  6. Click Next
  7. Set Service name to myapp
  8. Set Port to 8080 (or your app's port)
  9. Under Health check, set Path to /health
  10. Click Next
  11. Review and click Create & deploy

Option B: Using the CLI

Create a file called apprunner-config.json:

json
{
  "ServiceName": "myapp",
  "SourceConfiguration": {
    "AuthenticationConfiguration": {
      "AccessRoleArn": "arn:aws:iam::ACCOUNT_ID:role/AppRunnerECRAccessRole"
    },
    "AutoDeploymentsEnabled": true,
    "ImageRepository": {
      "ImageIdentifier": "ACCOUNT_ID.dkr.ecr.us-east-1.amazonaws.com/myapp:latest",
      "ImageConfiguration": {
        "Port": "8080",
        "RuntimeEnvironmentVariables": {
          "NODE_ENV": "production"
        }
      },
      "ImageRepositoryType": "ECR"
    }
  },
  "HealthCheckConfiguration": {
    "Protocol": "HTTP",
    "Path": "/health",
    "Interval": 10,
    "Timeout": 5,
    "HealthyThreshold": 1,
    "UnhealthyThreshold": 5
  },
  "InstanceConfiguration": {
    "Cpu": "1024",
    "Memory": "2048"
  }
}
Note

Replace ACCOUNT_ID with your actual AWS account ID in both places!

Then create the service:

bash
aws apprunner create-service --cli-input-json file://apprunner-config.json --region us-east-1

Step 6: Wait for Deployment

Deployment takes 3-5 minutes. Check the status:

bash
# List your services and get the ARN
aws apprunner list-services --region us-east-1

# Check status (replace SERVICE_ARN with your actual ARN)
aws apprunner describe-service \
  --service-arn SERVICE_ARN \
  --query 'Service.Status' \
  --region us-east-1

Status progression: OPERATION_IN_PROGRESS → RUNNING

Step 7: Get Your URL and Test

bash
# Get the service URL
aws apprunner describe-service \
  --service-arn SERVICE_ARN \
  --query 'Service.ServiceUrl' \
  --output text \
  --region us-east-1

Test your deployment:

bash
# Test the health endpoint
curl https://YOUR_SERVICE_URL.us-east-1.awsapprunner.com/health

# Test your main app
curl https://YOUR_SERVICE_URL.us-east-1.awsapprunner.com/
Note

Your app is now live on the internet with HTTPS automatically configured!

Step 8: Set Up Automatic Deployments

With AutoDeploymentsEnabled: true, App Runner watches your ECR repository. To deploy a new version:

bash
# Build new version
docker build -t myapp .

# Tag it
docker tag myapp:latest ACCOUNT_ID.dkr.ecr.us-east-1.amazonaws.com/myapp:latest

# Push it
docker push ACCOUNT_ID.dkr.ecr.us-east-1.amazonaws.com/myapp:latest

# App Runner automatically detects and deploys!

Managing Environment Variables

Add Variables via CLI

bash
aws apprunner update-service \
  --service-arn SERVICE_ARN \
  --source-configuration '{
    "ImageRepository": {
      "ImageConfiguration": {
        "RuntimeEnvironmentVariables": {
          "DATABASE_URL": "postgresql://...",
          "API_KEY": "your-api-key"
        }
      }
    }
  }' \
  --region us-east-1
Note

Don't put secrets directly in environment variables for production! Use AWS Secrets Manager or SSM Parameter Store instead.

Using Secrets Manager (Recommended for Secrets)

bash
# Create a secret
aws secretsmanager create-secret \
  --name myapp/database-url \
  --secret-string "postgresql://user:pass@host:5432/db" \
  --region us-east-1

# Reference it in App Runner (requires additional IAM permissions)

Custom Domain (Optional)

1. Add Custom Domain

bash
aws apprunner associate-custom-domain \
  --service-arn SERVICE_ARN \
  --domain-name app.yourdomain.com \
  --region us-east-1

2. Configure DNS

App Runner will give you DNS records to add. Typically:

TypeNameValue
CNAMEapp.yourdomain.comYour App Runner URL
CNAME_abc123.app.yourdomain.com_abc123.acm-validations...

3. Wait for Certificate

App Runner automatically provisions an SSL certificate. This can take 10-30 minutes.

Scaling Configuration

Adjust Scaling Settings

bash
aws apprunner update-service \
  --service-arn SERVICE_ARN \
  --auto-scaling-configuration-arn arn:aws:apprunner:us-east-1:ACCOUNT_ID:autoscalingconfiguration/... \
  --region us-east-1

Or create a custom auto-scaling configuration:

bash
aws apprunner create-auto-scaling-configuration \
  --auto-scaling-configuration-name myapp-scaling \
  --max-concurrency 100 \
  --min-size 1 \
  --max-size 5 \
  --region us-east-1

Viewing Logs

bash
# Via CLI (requires CloudWatch Logs Insights)
aws logs filter-log-events \
  --log-group-name /aws/apprunner/myapp/.../application \
  --region us-east-1

# Via Console (easier)
# Go to App Runner → Your Service → Logs tab

Troubleshooting

Service Won't Start

Check the logs:

  1. Go to App Runner Console → Your Service → Logs
  2. Look for error messages during startup

Common issues:

  • App not listening on the correct port
  • Missing environment variables
  • Docker image not found

Health Checks Failing

bash
# Check health check configuration
aws apprunner describe-service \
  --service-arn SERVICE_ARN \
  --query 'Service.HealthCheckConfiguration' \
  --region us-east-1

Fix:

  • Ensure your health endpoint returns 200 status
  • Check the path is correct
  • Increase timeout if your app is slow to start

Permission Denied

bash
# Verify ECR access role
aws iam get-role --role-name AppRunnerECRAccessRole

# Check attached policies
aws iam list-attached-role-policies --role-name AppRunnerECRAccessRole

Cleaning Up

To avoid ongoing charges:

bash
# Delete the service
aws apprunner delete-service --service-arn SERVICE_ARN --region us-east-1

# Delete ECR images (optional)
aws ecr batch-delete-image \
  --repository-name myapp \
  --image-ids imageTag=latest \
  --region us-east-1

# Delete the repository (optional)
aws ecr delete-repository --repository-name myapp --force --region us-east-1

What's Next?

You've deployed your first AWS application! For more control, check out:

  • ECS Fargate - More configuration options, lower cost at scale
  • Custom Domains - Set up Route 53 for professional URLs
  • Databases - Add RDS PostgreSQL for persistent data
Note

Checkpoint: Your app should be accessible at the App Runner URL. Test the health endpoint and main functionality before continuing.