As an engineer, if you have tried to deploy a container on AWS the traditional way, you must know the feeling of getting a single app online with Amazon ECS. You'd find yourself clicking through cluster setups, several task definitions, security groups, and load balancer configurations, each with its own settings, just to ensure that everything works. For a first timer, this can be a lot to setup.
The introduction of ECS Express Mode is AWS's answer to that. Here, it collapses all of that setup into three things to get started: A container image, a task execution role, and an infrastructure role, so that once you hand it your image, it provisions and wires up the rest for you.
It is important to note that Express Mode is the successor to AWS App Runner. This is because AWS has decided to close App Runner to use customers starting April 30, 2026, and now, they recommend Amazon ECS Express as the migration path because it keeps App Runner's simplicity while providing full ECS features. So if you are considering building new applications today, Express Mode is the path you should be pointing to.
At the end of this article, you'll have taken your own container image, and turned it into a live, HTTPS-secured URL. Let's build.
What you'll build
We'll deploy Power Snapshot NG — a tiny web service that fetches official Nigeria electricity indicators from the World Bank Open Data API and displays them in the browser. Type nothing complicated: open the URL and you see real national stats — electricity access as a percentage of the population, consumption per capita, and renewable share of generation.
It's deliberately compact (one container, one port, two API routes), so nothing distracts from the deployment. But it's a step beyond the usual static "hello world": you get a live UI, a working backend, and data pulled from the outside world. If you work with data, it's a practical hint of what containers unlock — and an honest one. Unlike the UK, Nigeria doesn't offer a free public live grid API, so we use the latest published national indicators rather than minute-by-minute carbon intensity.
Under the hood, the image bundles a lightweight HTML frontend and a Node.js/Express API into a single container on port 80. Express Mode handles the HTTPS URL, load balancer, and scaling. Your job is build, push, deploy.
The sample app lives in the express-mode/ folder of the repo. Clone it, follow along, and swap in your own image later if you prefer — every step below works the same.
What Express Mode does for you
Think of Express Mode as a production-ready default layer on top of ECS. When you create an Express Mode service, AWS automatically provisions:
- An ECS service running on AWS Fargate
- An Application Load Balancer with HTTPS and SSL/TLS termination
- Auto scaling policies (CPU-based by default)
- CloudWatch logging and monitoring
- Security groups and networking in your default VPC
- A unique HTTPS URL on the
*.ecs.<region>.on.awsdomain
You don't configure any of that manually on day one. You provide the image and two IAM roles; Express Mode wires the rest.
Prerequisites
Before you start, make sure you have:
- An AWS account with permissions to use ECS, ECR, IAM, and CloudWatch
- The AWS CLI v2 installed and configured (
aws configure) - Docker Desktop installed and running locally
- A terminal open in the express-mode/ folder of the sample repo
You'll also need a container image stored in Amazon ECR — Step 2 creates and pushes that. Express Mode does not build from source the way App Runner could; you bring a ready-made image.
Step 1 — Build your container image
Get the sample app
Clone the repository and navigate into the Express Mode sample directory:
git clone https://github.com/obusorezekiel/power-snapshot-ng
cd power-snapshot-ng
The application is a Node.js server (server.js) that serves static content from the public/ folder and exposes two API routes:
| Route | Purpose |
|---|---|
/api/health |
Returns { "status": "ok" }; used by the load balancer health check. |
/api/energy |
Fetches Nigeria electricity statistics from the World Bank API. |
The Dockerfile, line by line
| Instruction | Description |
|---|---|
FROM node:20-alpine |
Starts from a lightweight Linux image with Node.js 20. |
WORKDIR /app |
Sets the working directory inside the container. |
COPY package*.json ./ |
Copies dependency definitions. |
RUN npm install --omit=dev |
Installs production dependencies (cached layer). |
COPY server.js ./ |
Copies the application server code. |
COPY public ./public |
Copies static assets. |
ENV PORT=80 |
Sets the application port environment variable. |
EXPOSE 80 |
Informs Docker that the container listens on port 80. |
CMD ["node", "server.js"] |
Starts the web server on launch. |
Build and test locally
- Build the image:
docker build -t power-snapshot-ng .
- Run the container locally (mapping port 8080):
docker run -p 8080:80 --name power-test power-snapshot-ng
Verify the deployment by visiting
http://localhost:8080. You should see the Nigeria electricity indicators page.Confirm the health endpoint:
curl http://localhost:8080/api/health
Expected response: {"status":"ok"}
- Stop and remove the test container:
docker stop power-test
docker rm power-test
Testing locally ensures your container configuration is correct before deploying to AWS, saving significant time during the ECS deployment process.
Step 2 — Push the image to ECR
Amazon ECS pulls container images from a registry. We'll use Amazon ECR — AWS's private Docker registry.
Set Environment Variables
First, define your region and AWS Account ID:
AWS_REGION = "us-east-1"
AWS_ACCOUNT_ID = aws sts get-caller-identity --query Account --output text
Create the Repository
Create the repository (skip this step if it already exists):
aws ecr create-repository --repository-name power-snapshot-ng --region $AWS_REGION
Authenticate Docker
Authenticate your local Docker client to your ECR registry:
aws ecr get-login-password --region $AWS_REGION | docker login --username AWS --password-stdin "$AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com"
Tag and Push
Tag your local image and push it to ECR:
docker tag power-snapshot-ng:latest "$AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/power-snapshot-ng:latest"
docker push "$AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/power-snapshot-ng:latest"
Verification
Verify in the console: open Amazon ECR, select power-snapshot-ng, and confirm the latest image is listed.
Note: Save your full image URI — you'll paste it into Express Mode in the next section:
<ACCOUNT_ID>.dkr.ecr.<REGION>.amazonaws.com/power-snapshot-ng:latest
Step 3 — Create the two IAM roles
Express Mode requires two specific IAM roles to function.
| Role | Purpose | Managed Policy |
|---|---|---|
| Task execution role | Lets ECS pull your image from ECR and write logs to CloudWatch. | AmazonECSTaskExecutionRolePolicy |
| Infrastructure role | Lets Express Mode create the ALB, target groups, security groups, and scaling policies on your behalf. | AmazonECSInfrastructureRolePolicyForExpressServices |
The easy path
When you create the Express Mode service in the AWS console, simply choose Create new role from each role dropdown. AWS will automatically attach the correct policies for you.
Manual creation
If you prefer to create them manually:
Task Execution Role:
- Navigate to IAM → Roles → Create role
- Select Elastic Container Service → Elastic Container Service Task
- Attach AmazonECSTaskExecutionRolePolicy
- Name it:
ecsTaskExecutionRole
Infrastructure Role:
- Navigate to IAM → Roles → Create role
- Select Elastic Container Service
- Attach AmazonECSInfrastructureRolePolicyForExpressServices
- Name it:
ecsInfrastructureRoleForExpressServices
Note: For a simple app like this, the managed policies cover everything. No custom inline policies are needed.
Step 4 — Deploy with Express Mode
This is the payoff. Follow these steps to get your container live.
Console walkthrough
- Open the Amazon ECS console
- In the left navigation, choose Express mode
- Choose Create
- Fill in the general configuration parameters:
| Field | Value for this app |
|---|---|
| Container image URI | 353928175117.dkr.ecr.us-east-1.amazonaws.com/power-snapshot-ng:latest |
| Task execution role | ecsTaskExecutionRole |
| Infrastructure role | ecsInfrastructureRoleForExpressServices |
| Service name | power-snapshot-ng |
- Expand Additional configurations and set:
| Field | Value | Note |
|---|---|---|
| Container port | 80 |
The app listens on port 80 inside the container. |
| Health check path | /api/health |
Express Mode defaults to /ping — this app uses /api/health. |
- Leave other settings as default (1 vCPU, 2 GB RAM, CPU-based auto scaling) and choose Create
Watch the provisioning progress in the Resources tab. AWS is wiring up your cluster, ALB, and URL.
When the status is Running, copy your new URL (e.g., https://po-5195b9c4136c4ef882cf7743809f69cd.ecs.us-east-1.on.aws) and open it.
Congratulations! You've successfully deployed a containerized app with a secured HTTPS endpoint.
CLI alternative
If you prefer the command line, use the following command to perform the same deployment:
aws ecs create-express-gateway-service \
--region $AWS_REGION \
--service-name power-snapshot-ng \
--execution-role-arn "arn:aws:iam::${AWS_ACCOUNT_ID}:role/ecsTaskExecutionRole" \
--infrastructure-role-arn "arn:aws:iam::${AWS_ACCOUNT_ID}:role/ecsInfrastructureRoleForExpressServices" \
--primary-container "image=${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/power-snapshot-ng:latest,containerPort=80" \
--health-check-path "/api/health" \
--monitor-resources
What went wrong — troubleshooting
This table summarizes common failures beginners encounter when deploying the Power Snapshot NG app.
| Issue | Symptom | Cause | Fix |
|---|---|---|---|
| Health Check Fail | Tasks restart; service stuck in deploy loop. | Default path /ping is used instead of /api/health. |
Set Health check path to /api/health. |
| 502 Bad Gateway | URL loads but returns 502 error. | Port mismatch between ALB and container. | Set Container port to 80. |
| Missing Data | UI loads but shows "Loading..." or error. | Backend cannot reach World Bank API. | Check CloudWatch Logs for timeouts. |
| Pull Error | Tasks fail with CannotPullContainerError. |
Task role missing ECR permissions. | Attach AmazonECSTaskExecutionRolePolicy. |
Peek under the hood
After your service is running, open these in the console. Express Mode didn't hide anything — it just created it for you.
| Resource | Where to find it | What to notice |
|---|---|---|
| ECS cluster | ECS → Clusters | A cluster created/reused for your service. |
| ECS service | ECS → Services | Desired count and deployment status. |
| Task definition | ECS → Task definitions | CPU/Memory and container image URI. |
| Application Load Balancer | ECS → Load Balancers | Internet-facing ALB with HTTPS. |
| Target group | ECS → Target Groups | Health check path and port 80 config. |
| CloudWatch log group | CloudWatch → Log groups | Logs from your Node process. |
These are standard ECS resources. You can edit the task definition, adjust auto scaling, attach a custom domain, or add environment variables — the same way you would with any ECS service. Express Mode is a starting point, not a cage.
Cleanup
Don't skip this. Idle AWS resources charge by the hour, and an ALB left running overnight is an unpleasant surprise.
- Delete the ECS service: Navigate to ECS → Express mode → Select power-snapshot-ng → Delete
- Wait for decommissioning: Ensure the service disappears from the console list before proceeding
- Delete the ECR repository: ECR → power-snapshot-ng → Delete repository (check "force delete")
- Remove the Load Balancer: Verify the shared ALB is removed under EC2 → Load Balancers
- Purge Log Groups: Optionally delete orphaned CloudWatch log groups manually
Note: If you deployed multiple Express Mode services, they may share one ALB — deleting one service won't always delete the load balancer until all services using it are gone.
Conclusion
You built a Docker image locally, pushed it to ECR, created two IAM roles, and deployed it to Amazon ECS Express Mode — ending with a live HTTPS URL serving a real data app. No cluster configuration spreadsheets. No manual ALB wiring. Three inputs, one deployment flow.
As of mid-2026, ECS Express Mode is available in all AWS regions where ECS and Fargate are supported. Console layout and label names may change — match what you see in AWS against the concepts described here.








Top comments (0)