At some point in their lives, every software engineer eventually faces the task of debugging an app live on a remote server. If that app happens to be running on ECS Fargate, getting into that container safely is possible, but not immediately obvious.
Full disclosure: I haven’t done this exact thing before, but I have used the same port-forwarding trick to peek into our RDS instances via an ECS task acting as a jumpbox. So yes, I tested these instructions, and yes, they actually work.
The Setup
Here’s what we have:
- A Node.js app deployed to ECS Fargate
- Inside a private VPC subnet
- Without SSH access (Fargate doesn’t do that)
- VS Code (or some other IDE with Node.js inspector support)
Step 1: Enable Node.js inspector
First, make sure your ECS task’s running Node.js process with the inspector enabled. This can be achieved by passing a flag to the node command.
node --inspect=127.0.0.1:9229 server.js
Or by adding the inspect flag to the NODE_OPTIONS ****environmental variable.
NODE_OPTIONS="--inspect=127.0.0.1:9229"
Since we’re using ECS, adding flag to the node command would require modifying Dockerfile or overriding command in the task definition, so I’d suggest the environmental variable approach.
{
"containerDefinitions": [
{
"name": "...",
"image": "...",
"essential": true,
"environment": [
{
"name": "NODE_OPTIONS",
"value": "--inspect=127.0.0.1:9229"
}
]
}
]
}
Step 2: Enable ECS Exec and SSM Access
Before you can connect, your ECS task needs permission and execution enabled:
Attach this IAM policy to your ECS task execution role:
arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
Enable ECS Exec on your service:
aws ecs update-service \
--cluster my-cluster \
--service my-service \
--enable-execute-command
If you’re changing it through the console, it’s hidden under Troubleshooting → Enable Execute Command.
Step 3: Find Your Running Task
List your tasks:
aws ecs list-tasks --cluster my-cluster
You’ll get something like:
{
"taskArns": [
"arn:aws:ecs:us-east-1:123456789012:task/my-cluster/abc123def456ghi789"
]
}
The last part of the ARN (abc123def456ghi789) is your Task ID.
Step 4: Set Up Port Forwarding via SSM
Here’s where the real black magic starts. AWS won’t just give you a SSM target ID for the Fargate task, you have to construct it yourself using this template:
ecs:<cluster_name>_<task_id>_<container_runtime_id>
Get the container runtime ID:
aws ecs describe-tasks \
--cluster my-cluster \
--task <task_arn> \
--query "tasks[].containers"
You’ll get a massive JSON blob, and somewhere in that mess hides the runtimeId field you actually care about. There might be a few of them actually, one for each container in the task. And yes, the runtimeId contains task id in it.
Then start the port forwarding:
aws ssm start-session \
--target "ecs:my-cluster_cb39a47ef2ef45f4b947236bf00aeadd_cb39a47ef2ef45f4b947236bf00aeadd-3935363592" \
--document-name AWS-StartPortForwardingSessionToRemoteHost \
--parameters '{"host":["127.0.0.1"],"portNumber":["9229"],"localPortNumber":["9229"]}'
This opens a local port (9229) and forwards traffic securely to the Node.js process in your container.
💡 Pro tip: We’re forwarding to 127.0.0.1 here, but you can forward to any IP or hostname accessible from the ECS task.
Step 5: Connect VS Code Debugger
In .vscode/launch.json:
{
"type": "node",
"request": "attach",
"name": "Attach to Fargate",
"address": "localhost",
"port": 9229,
"localRoot": "${workspaceFolder}",
"remoteRoot": "/usr/src/app"
}
And that’s all.
If you don’t know the remoteRoot , then you can get into the container and look around to check it.
aws ecs execute-command --cluster my-cluster \
--task <task_arn> \
--interactive \
--command "/bin/sh" \
--container <container name>
Alternative: Chrome debugger (chrome://inspect). Usually works, but tends to have issues with source maps.
TL;DR Cheat Sheet
# 1. Make sure your Node.js app runs with --inspect flag
NODE_OPTIONS="--inspect=127.0.0.1:9229"
# 2. Give ECS task SSM permissions
# 3. Enable ECS Exec
aws ecs update-service —service my-service —cluster my-cluster —enable-execute-command
# 4. Get you task arn
aws ecs list-tasks --cluster my-cluster
# 5. Get your container runtime id
aws ecs describe-tasks \
--cluster <cluster> \
--region us-east-2 \
--task <task_arn> \
--query "tasks[].containers"
# 6. Start port forwarding
aws ssm start-session \
--target ecs:<cluster>_<task>_<runtime_id> \
--document-name AWS-StartPortForwardingSessionToRemoteHost \
--parameters '{"host":["127.0.0.1"],"portNumber":["9229"],"localPortNumber":["9229"]}'
Then attach your VS Code debugger to localhost:9229 and voila.
Top comments (0)