The MEAN stack ships with several layers of observability out of the box. The Application Load Balancer continuously probes each Node.js instance through a dedicatedDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/mcamacho97/terraform-mean-stack-aws/llms.txt
Use this file to discover all available pages before exploring further.
/health endpoint. Every service — the Node.js application, Nginx, and MongoDB — runs as a systemd unit with structured logging available through journalctl. No third-party monitoring agent is required to get meaningful health signals from this stack, though production workloads should extend these defaults with CloudWatch alarms and dashboards.
ALB Health Checks
The ALB target group is configured to evaluate instance health against the Express/health endpoint. The full configuration from modules/alb/main.tf:
| Parameter | Value |
|---|---|
| Path | GET /health |
| Protocol | HTTP |
| Port | 80 (Nginx → Node.js on 3000) |
| Expected status | 200 |
| Interval | 30 seconds |
| Timeout | 5 seconds |
| Healthy threshold | 2 consecutive successes |
| Unhealthy threshold | 2 consecutive failures |
200 from /health twice in a row before the ALB routes production traffic to it. Two consecutive failures mark it unhealthy and remove it from rotation.
To check the current health of all registered targets via the AWS CLI, first find the target group ARN, then describe its health:
The target group ARN is not exported as a Terraform output in this project. Use
describe-target-groups as shown above, or navigate to EC2 → Target Groups in the AWS Console to find it.Application Health Endpoint
Each Node.js instance exposes two JSON endpoints, both served via the Express application defined inuserdata/node.sh.
GET /health — used by the ALB health check:
GET / — the root endpoint, confirming the application identity:
hostname field reflects the EC2 private DNS hostname, making it easy to identify which instance responded when testing through the load balancer. Test all three paths with curl:
hostname field rotate between the two instances confirms that load balancing is working correctly.
Service Status Checks
SSH into either Node.js instance and run the following to inspect the application and reverse proxy layers:127.0.0.1:3000 where the Node.js process listens. If the ALB marks an instance unhealthy, check the Nginx error log first — a failed proxy connection to port 3000 is the most common symptom of the nodeapp service being down.
MongoDB Monitoring
SSH into the MongoDB instance (via jump host or SSM) to inspect the database service:0.0.0.0 inside the private subnet. Confirm that Node.js can reach it by checking the nodeapp logs for connection errors — successful startup produces a log line from the Express server indicating the port it is listening on.
User-Data Bootstrap Logs
Cloud-init runs theuserdata/node.sh and userdata/mongo.sh scripts at first boot. If an instance appears unhealthy immediately after provisioning, check whether bootstrap completed successfully:
set -euxo pipefail, so any failed command aborts the script and leaves a clear error message in the cloud-init log.
This project sets
monitoring = false on all EC2 instances, which means only basic CloudWatch monitoring is enabled (5-minute metric granularity). For production workloads, enable detailed monitoring (1-minute granularity) and create CloudWatch alarms on CPUUtilization, StatusCheckFailed, and ALB UnHealthyHostCount to get proactive alerting on instance or application failures.