When an EC2 instance is already running production, the most dangerous problems are often not the dramatic ones you notice immediately, but the small things that quietly ruin the machine:
- logs growing too fast and filling the disk
- failing log shippers consuming RAM
- unusual CPU or network usage that nobody checks
- disk space dropping without early alerts
These are not business logic bugs, but they are exactly the kind of issues that can slow down apps, trigger restarts, freeze the host, or cause downtime.
Quick conclusion
If you only remember a few things when managing a production EC2:
- if you use Docker, you must limit logs from day one to avoid filling the volume
- low-value logs that nobody really uses should be limited or removed
- if you do not deploy with Docker and instead run apps directly on EC2, you must be extra careful with PM2 logs and Elasticsearch-style log shippers
- CPU, RAM, disk, and network must be monitored continuously, and abnormal behavior should be fixed early
Why are logs one of the easiest ways to kill an EC2?
Many production machines die in a very boring way:
- the app is technically still running
- there is no huge code failure
- but the disk becomes full because of logs
Once the disk is full, you may get:
- container restart failures
- local database write failures
- missing logs
- broken system services
- failed deployments
That is why logs must never be allowed to grow without limits.
If you use Docker, limit logs immediately
This is one of the most important rules.
If you run apps with Docker on EC2 and leave logging at defaults, container logs can keep growing under:
/var/lib/docker
If the service has:
- high request volume
- repeated errors
- overly verbose debug logging
then the volume can fill up surprisingly fast.
The safe approach is to define log rotation at the Docker level.
Example in Docker Compose:
services:
api:
image: my-api:latest
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
Meaning:
- each log file is capped at
10MB - only
3files are kept
That prevents a container from generating unlimited disk growth.
Not every log is worth keeping
In production, a lot of logs have very low value:
- healthcheck requests
- overly detailed debug logs
- repeated retry logs
- noisy traces from side services nobody actually reads
If these are emitted heavily, they only:
- waste disk
- waste network
- waste CPU
- make important logs harder to read
The practical rule is:
- if a log does not help operations or debugging, reduce it
- if it has low value, limit it
Low-priority log pipelines also need limits
A very real example is shipping logs into ELK or another central logging stack.
If a side service:
- emits a lot of logs
- ships them continuously
- but nobody actually uses them
then you are spending resources for almost no operational benefit.
This becomes more dangerous when the shipper fails to send logs and starts buffering or retrying:
- RAM rises
- CPU rises
- network usage becomes abnormal
- spool files or queues start growing
In short:
- low-value logs should not be shipped without limits
- if you keep them, retention and buffering must be controlled
If you do not deploy with Docker and run apps directly on EC2, be very careful with PM2 logs
Many people run Node.js or NestJS directly on EC2 with PM2.
PM2 is convenient, but it can become a trap when:
- stdout/stderr logs are noisy
- log rotation is missing
- the app enters an error loop
Then logs can grow continuously inside:
~/.pm2/logs
Without rotation, one bug or one broken retry loop can fill the disk much faster than expected.
So if you use PM2, you should always:
- know where the logs live
- rotate or limit them
- avoid verbose production logging unless you truly need it
Avoid letting Elasticsearch log shippers eat RAM when delivery fails
This is a very real production pain point.
If you have a process that:
- ships logs to Elasticsearch
- or buffers logs before sending
and the destination becomes slow, broken, or unreachable, memory usage can climb quickly.
This is especially dangerous when:
- the app is not containerized
- the shipper runs directly on EC2
- there is no clear memory limit around that process
Then a logging pipeline failure can lead to:
- growing RAM usage
- swap pressure
- a slow server
- OOM situations
If the log stream is not truly important, do not enable it just for the sake of “having logs somewhere.”
Practical rules for logs
If you want a short rule set:
- Docker logs must always have
max-sizeandmax-file - PM2 logs must always rotate
- low-value log shippers should be limited or disabled
- verbose debug logs should not stay enabled in production
- abnormal log growth should be treated like an incident
What should you monitor on a production EC2?
At minimum, watch:
- CPU
- RAM
- disk
- network
These are the four most basic signals. If the machine is a real AWS EC2 instance, there are also a few extra signals worth watching:
EC2 status checksCPU creditsonTfamily instancesEBS BurstBalanceif the volume is stillgp2
CPU, RAM, disk, and network: what should you look for?
CPU
Abnormal CPU growth can come from:
- app loops
- real traffic spikes
- aggressive retries
- broken collectors or log shippers
If CPU stays high for too long, check:
- which process is using it
- whether the traffic spike is real
- whether a cron job, worker, sidecar, or background process is looping
RAM
RAM is one of the easiest metrics to ignore until it becomes painful.
Abnormal RAM growth can come from:
- memory leaks
- log buffering
- backed-up queues
- apps holding too many objects
- Elasticsearch or log shippers keeping retry state
If RAM rises gradually over time, do not just restart and move on. Find the root cause.
Disk
Disk is not only about “how many GB are left.”
You also need to check:
- what path is growing
- how fast it is growing
- whether inode exhaustion is becoming a problem
Very important paths to inspect:
/var/lib/docker~/.pm2/logs- application log folders
- cache / temp / spool paths
If disk gets close to full and nobody reacts early, a lot of other systems start failing in sequence.
Network
Abnormal network usage can indicate:
- real traffic spikes
- retry loops to external systems
- excessive log shipping
- broken backup or sync jobs
- abuse or scanning
If outbound traffic jumps unexpectedly, investigate:
- which app is calling out
- whether a log shipper is retrying
- whether some service is pushing logs or metrics too aggressively
Do not ignore EC2 status checks
According to AWS documentation, EC2 has status checks that help detect problems at the instance layer or in the underlying infrastructure.
Source:
One very worthwhile setup is:
- create a
CloudWatch alarm - monitor
StatusCheckFailed_System - enable
automatic recoverywhen appropriate
AWS also documents recovery through alarm actions:
This does not replace application monitoring, but it is a very useful extra layer.
If you use T3 or another burstable family, watch CPU credits
This article is about EC2 production operations in general, but if your machine is a T instance such as:
t3.microt3.small
then looking only at % CPU is not enough.
According to AWS, burstable instances expose dedicated CPU credit metrics in CloudWatch.
Source:
Important metrics to watch:
CPUCreditBalanceCPUSurplusCreditBalanceCPUSurplusCreditsCharged
Why this matters:
- the machine may still appear to be running
- but credits may be draining steadily
- or the instance may start bursting in a way that increases cost
If the volume is still gp2, monitor BurstBalance
According to AWS, gp2 exposes the BurstBalance metric to show remaining I/O burst credits.
Source:
If BurstBalance drops too low:
- the volume may get throttled back to baseline
- the app can become slow in a way that is hard to explain
- disk latency may rise even when CPU and RAM still look acceptable
If production still runs on gp2, this is a very important signal.
Disk usage inside the OS does not fully appear by default unless you install an agent
One easy misunderstanding is:
- default EC2 metrics do not automatically give you all the in-OS disk usage details you often want
According to AWS, if you want disk space usage from inside the instance without SSHing in manually, you should use:
CloudWatch Agent
Source:
This is especially useful for early alerts like:
/below 20%/var/lib/dockergrowing unusually fast- a log volume getting close to full
Fix abnormal behavior early
This is one of the most important operating principles.
On a production EC2, signs like:
- abnormal CPU growth
- RAM climbing over time
- disk dropping too quickly
- unexplained network spikes
should not be treated as “we’ll look at it tomorrow.”
Many major incidents start exactly that way.
The earlier you fix them, the lower the cost:
- less downtime
- less log loss
- fewer emergency restarts
- lower risk of data issues
Production EC2 checklist
You should at least have this checklist:
- Do Docker logs already use
max-sizeandmax-file? - Are PM2 logs rotating?
- Which log shippers are running, and are they actually necessary?
- What is current disk usage?
- Which directories are growing fastest?
- Do you know the normal CPU / RAM / network baseline?
- Do you have alerts for abnormal usage?
- Is there already an alarm for
StatusCheckFailed_System? - If this is a
t3, are you watchingCPUCreditBalance? - If the volume is
gp2, are you watchingBurstBalance? - Do you have
CloudWatch Agentmetrics for disk usage inside the OS?
The single most important habit
If you keep only one habit, keep this one:
- never let log growth remain uncontrolled
On a production EC2, unlimited logs are one of the fastest ways to break your own machine.
Conclusion
Managing a production EC2 is not just about deploying the app and walking away. The things that need tight control are:
- Docker logs
- PM2 logs
- log shippers
- CPU
- RAM
- disk
- network
- EC2 status checks
- CPU credits on T-series
- EBS burst behavior if you still use gp2
And if you use Docker, the first thing you should almost always do is:
- set log limits
If you do not use Docker and run apps directly on EC2, you need to be even more careful with:
- PM2 logs
- Elasticsearch-style log shipping processes
Finding abnormal behavior early and fixing it quickly is what keeps a production EC2 healthy over time.