
Photo by David Pupăză on Unsplash
In modern infrastructure, services are the lifeblood of applications. They manage queues, handle database connections, serve web requests, and execute background tasks—all operating silently until something goes wrong. When a critical service unexpectedly ceases operation, the resulting outage can range from minor inconvenience to catastrophic business disruption.
A common mistake among administrators is treating the symptom (the stopped service) rather than the root cause (the underlying issue—be it memory exhaustion, a bad configuration parameter, or an external dependency failure). Simply running a restart command masks the problem and guarantees recurrence.
This guide walks you through a complete, hands-on workflow for diagnosing and recovering failed services. Every section includes practical commands, real-world examples, and a step-by-step checklist you can apply immediately.
Part 1: Diagnose the Failure State
Before attempting any fix, accurately determine the current state of the service. This section applies to Linux (systemd, SysVinit), Windows, and containerized environments.
1.1 Linux: Check service state with systemd
Command:
systemctl status <service-name>
What to look for:
| Status output | Meaning | Action |
|---|---|---|
active (running) |
Service is healthy and running | No action needed |
active (exited) |
Service started once, may be healthy | Verify with health check |
inactive (dead) |
Service was stopped normally | Check if it should be running |
failed |
Abnormal termination | Investigate logs immediately |
activating (auto-restart) |
Service is in a crash loop | Stop, analyze, fix root cause |
deactivating |
Normal shutdown in progress | Wait, verify completion |
Example: Checking an nginx service that is failing:
$ systemctl status nginx
● nginx.service - A high performance web server and a reverse proxy server
Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
Active: failed (Result: exit-code) since Mon 2026-09-01 14:23:01 UTC; 3min 22s ago
Process: 1234 ExecStart=/usr/sbin/nginx -g 'daemon on; master_process on;' (code=exited, status=1/FAILURE)
Main PID: 1234 (nginx)
CPU: 2.134s
Sep 01 14:23:01 webserver.example.com systemd[1]: Starting A high performance web server and a reverse proxy server...
Sep 01 14:23:01 webserver.example.com nginx[1234]: nginx: [emerg] mkdir() "/var/cache/nginx/client_temp" failed (13: Permission denied)
Key insight from this example: The failure is not a code bug; it’s a filesystem permission issue. The service failed with status: 1/FAILURE and the error is mkdir() "/var/cache/nginx/client_temp" failed (13: Permission denied).
1.2 Linux: Check fast-failing state (crash loop)
Command:
# Check the restart counter and result
systemctl show <service-name> -p NRestarts -p Result -p MainPID -p StatusErrno
# Check for crash loops in the last 10 minutes
journalctl -u <service-name> --since "10 minutes ago"
Example output:
NRestarts=12
Result=signal
MainPID=5678
StatusErrno=0
What this means: NRestarts=12 in a short window = crash loop. Result=signal = the process was killed by a signal (likely SIGKILL = OOM kill).
Action: Stop the automatic restart, investigate the kernel logs:
dmesg -T | grep -i "killed process"
journalctl -k --since "10 minutes ago"
1.3 Windows: Check service state
PowerShell (faster, more informative):
Get-Service <service-name> | Select-Object Name, DisplayName, Status, StartType, CanStop
Output:
Name DisplayName Status StartType CanStop
---- ----------- ------ --------- -------
WebService IIS Admin Service Stopped Manual True
Command Prompt alternative:
sc query <service-name>
Example:
C:\> sc query WebService
QUERY SERVICE SAMPLE BEGIN
SERVICE_NAME: WebService
TYPE : 10 WIN32_OWN_PROCESS
STATE : 1 STOPPED
CONTROLS_CAPACITY : 0
WIN32_EXIT_CODE : 0 (0x0)
SERVICE_EXIT_CODE : 0 (0x0)
CHECKPOINT : 0x0
SERVICE_TRANSITION: 0x0
Key state codes:
| STATE value | Meaning |
|---|---|
1 (STOPPED) |
Service is not running |
2 (START_PENDING) |
Service is starting |
3 (STOP_PENDING) |
Service is stopping |
4 (RUNNING) |
Service is running (healthy) |
Part 2: Perform Deep Log Analysis
Once you know the service is failing, the next step is forensic log analysis. Never trust a single log source—correlate across at least two.
2.1 Linux: Three-source log correlation
When a service crashes, its actions leave trails in at least three places:
| Source | What it shows | Command |
|---|---|---|
| Application logs | Immediate cause of failure (e.g., “connection refused”) | journalctl -u <service> or tail -f /var/log/app/*.log |
| System logs | Resource limits, OOM kills, kernel events | dmesg -T or journalctl -k |
| Kernel logs | Process termination, OOM killer, signal delivery | dmesg -T \| grep <PID> or journalctl -k |
Example: Correlating the nginx failure from Part 1
# 1. Application/system log (nginx unit journal)
journalctl -u nginx -n 50 --no-pager
# 2. Kernel log (OOM kills, signals)
dmesg -T | tail -30
# 3. Full PID trace (which process died, why)
journalctl -u nginx --since "14:20" --until "14:25"
# 4. Check the specific PID
systemctl show nginx -p MainPID -p NRestarts -p Result
Example output of kernel log (the smoking gun):
[14:23:01.123456] nginx[1234]: segfault at 0 ip 0x0 sp 0x7ffd4f4d2b30 error 14
[14:23:01.123456] nginx[1234]: #0 0x000055a8b1c3d423 in ???
Action: The ip 0x0 and error 14 means a null pointer dereference (a code bug). The service should be fixed in the application, but you also check whether the filesystem permission issue (from earlier) was a misconfiguration that also needs fixing.
2.2 Windows: Check Event Viewer for service failures
Event Viewer path:
Windows Logs → System
Filter Current Log → Event ID: 7036 (Service Control Manager)
What to look for:
| Event ID | Meaning |
|---|---|
| 7036 | Service control manager initiated a stop/start (normal for restart) |
| 7035 | Service entered the stopped state (normal) |
| 7022 | Service control manager encountered an error trying to start the service |
| 7026 | Service was stopped with a non-zero exit code (crash) |
Example: Event 7026 for a Windows service
Log Name: System
Source: Service Control Manager
Event ID: 7026
Level: Error
Description: The Apache2.4 service exited with code 1.
Note: exit code 1 = an application crash or configuration error, not a service manager failure.
2.3 Docker/Kubernetes: Check container logs and status
Docker:
# Check the container status
docker inspect <container-id> --format '{{.State.Status}} {{if .State.Health}}{{.State.Health.Status}}{{end}}'
# View logs (use -t for timestamps)
docker logs --tail 50 -t <container-id>
# If the container restarted, check the previous logs
docker logs --tail 50 -t <container-id> --previous
Kubernetes:
# Describe the pod (shows restarts, recent events)
kubectl describe pod <pod-name>
# Get logs (add --previous to see logs from the last crashed instance)
kubectl logs <pod-name> --previous
# Check the restart count
kubectl get pod <pod-name> -o jsonpath='{.status.containerStatuses[0].restartCount}'
Example kubectl describe output (crash loop):
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning BackOff 5m kubelet Back-off restarting failed container
Normal Pulled 10m kubelet Container image "nginx:latest" already present on machine
Warning Unhealthy 5m kubelet Readiness probe failed: HTTP probe failed with statuscode 502
Action: Back-off restarting failed container = the container is failing and Kubernetes is retrying. Readiness probe failed = the app is not responding to health checks. Investigate the application logs:
kubectl logs <pod-name> --previous | tail -50
Part 3: Analyze Dependencies and External Constraints
Most crashes are caused by failed assumptions about the environment. The service itself may be fine; its dependencies may be broken.
3.1 Check service dependencies
Linux (systemd):
# List all dependencies of a service
systemctl list-dependencies <service-name> --all
# Check if a dependent service is active
systemctl is-active postgresql
systemctl is-active redis
Example:
$ systemctl list-dependencies nginx.service --all
nginx.service
├─ network.target
├─ nginx.service
│ └─ postgresql.service # <-- critical dependency!
└─ rpc-statd.service
Action: If postgresql.service is inactive, start it first before starting nginx:
sudo systemctl start postgresql
sudo systemctl start nginx
3.2 Check resource constraints
The most common cause of unexpected termination is resource exhaustion.
Check memory:
# Real-time memory usage
free -h
# Kernel ring buffer for OOM kills
dmesg -T | grep -i "out of memory"
# Container memory limits
docker stats --format "table {{.Name}}\t{{.MemUsage}}\t{{.MemPerc}}"
Check CPU:
# Real-time CPU
top -bn1 | head -20
# Process-specific CPU
ps aux --sort=-%cpu | head -10
Check disk:
# Disk space
df -h
# Inode usage (often causes silent failures)
df -i
Example: OOM kill diagnosis
$ dmesg -T | grep -i "killed process"
[14:30:01.123456] Out of memory: Killed process 1234 (nginx) total-vm:1234567kB, anon-rss:654321kB, file-rss:12345kB, shmem-rss:0kB
Action:
- Increase the service’s memory limit (
memory_limitin PHP-FPM,--memoryin Docker,resources.limits.memoryin Kubernetes) - Optimize the application to use less memory
- Add a swap file:
sudo fallocate -l 4G /swapfile && sudo chmod 600 /swapfile && sudo mkswap /swapfile && sudo swapon /swapfile
3.3 Check network ports
Linux:
# Check which process is listening on a port
ss -tlnp | grep <port>
# Check all listening ports
ss -tlnp
# Verify connectivity to a remote port
nc -vz <hostname> <port>
Windows (PowerShell):
Get-NetTCPConnection -LocalPort <port> -State Listen
# Test connectivity
Test-NetConnection <hostname> -Port <port>
Common causes:
- Port already bound by another process (stale process, config error)
- Firewall blocking the port
- DNS resolution failure for upstream services
Part 4: Apply Practical Recovery Strategies
4.1 Graceful restart with systemd
Step 1: Stop the service cleanly
sudo systemctl stop nginx
Step 2: Start the service
sudo systemctl start nginx
Step 3: Verify it’s running
systemctl status nginx
curl -I http://localhost
Step 4: Enable auto-start on boot
sudo systemctl enable nginx
4.2 Configure systemd restart policy
Example /etc/systemd/system/myapp.service
[Unit]
Description=My Application
After=network.target postgresql.service
Requires=postgresql.service
[Service]
Type=simple
User=myapp
WorkingDirectory=/opt/myapp
ExecStart=/opt/myapp/bin/start.sh
Restart=on-failure
RestartSec=5
StartLimitBurst=3
StartLimitIntervalSec=60
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
Key directives explained:
| Directive | What it does |
|---|---|
Restart=on-failure |
Restart on non-zero exit or signal |
RestartSec=5 |
Wait 5 seconds before restarting |
StartLimitBurst=3 |
Allow 3 restart attempts in the interval |
StartLimitIntervalSec=60 |
Reset counter every 60 seconds |
Step 3: Reload systemd and restart
sudo systemctl daemon-reload
sudo systemctl restart myapp
4.3 Docker restart policy
Example docker run command:
docker run -d --restart=on-failure:5 --memory=512m --name myapp myapp:latest
Policy types:
| Policy | Behavior |
|---|---|
no |
Never restart (default) |
always |
Always restart |
on-failure |
Restart only on non-zero exit |
on-failure:5 |
Restart on failure, max 5 times |
Example: Health check in Docker
docker run -d --health-cmd="curl -f http://localhost/health || exit 1" \
--health-interval=30s --health-timeout=5s --health-retries=3 \
--name myapp myapp:latest
4.4 Kubernetes liveness and readiness probes
Example deployment with probes:
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 2
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: myapp:latest
ports:
- containerPort: 8080
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 10
periodSeconds: 10
failureThreshold: 3
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
failureThreshold: 3
resources:
requests:
memory: "256Mi"
cpu: "500m"
limits:
memory: "512Mi"
cpu: "1000m"
Probe types explained:
| Probe | What it detects | Action on failure |
|---|---|---|
| Liveness probe | App is hung/crashed | K8s restarts the container |
| Readiness probe | App is not serving traffic | K8s removes from service endpoints; traffic stops |
Part 5: Operational Safety and Change Management
5.1 Snapshot and backup before changes
Linux (file system):
# Backup config files before any change
sudo cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak.$(date +%F)
# Snapshot a system (if using Btrfs or ZFS)
sudo btrfs subvolume snapshot / /root/snapshot-$(date +%F)
Kubernetes:
# Backup a deployment
kubectl get deployment myapp -o yaml > myapp-backup-$(date +%F).yaml
# Undo a bad rollout
kubectl rollout undo deployment/myapp
5.2 Least privilege
- Never run service processes as
rootunless absolutely required. Use a dedicated unprivileged user. - Use
sudo -u myapp systemctl restart myappinstead ofsudo systemctl restart myapp. - Limit
systemctlaccess to production admins only.
5.3 Staging validation
- Never apply a fix directly to production if it can be replicated in staging.
- Use the failure scenario to improve test coverage.
- Build automated validation checks that mimic real-world usage patterns.
5.4 Document recovery steps
Record every recovery action in your runbook:
| Step | Action | Command / Tool |
|---|---|---|
| 1. Check state | systemctl status / Get-Service / sc query |
OS-specific |
| 2. Pull logs | journalctl -u service, dmesg, event viewer |
OS-specific |
| 3. Validate dependencies | systemctl list-dependencies, ss -tlnp |
OS-specific |
| 4. Apply fix | systemctl restart, increase memory limits |
OS-specific |
| 5. Verify | systemctl is-active, health endpoint |
OS-specific |
| 6. Document | Update runbook / ticket | Your ITSM tool |
Part 6: Summary — The Complete Recovery Workflow
Key Takeaways
| Step | Action | Command / Tool |
|---|---|---|
| 1. Check state | Determine if it’s a real failure or normal | systemctl status, Get-Service, sc query |
| 2. Identify crash loop | Count restarts and check result | systemctl show -p NRestarts -p Result |
| 3. Pull logs | Application, system, kernel | journalctl -u service, dmesg, /var/log/kern.log |
| 4. Validate dependencies | Database, network, config | systemctl list-dependencies, ss -tlnp, systemd-analyze verify |
| 5. Apply fix | Restart with policy, fix config, increase limits | systemctl restart, systemctl enable --now |
| 6. Verify | Health check, monitor for 10 min | watch systemctl status, health endpoint |
| 7. Document | Record root cause and fix | Update runbook / ITSM ticket |
Related Articles
- The Linux Command Line: What Actually Gets You Through the Work
- Mastering Linux: The Essential Toolkit for Resource Monitoring (50+ Commands with Examples)
- Getting Started with Docker: A Beginner’s Guide to Containerization – Master Modern Infrastructure Today
- Linux System Metrics That Matter: CPU, Memory, Disk I/O — What to Watch Daily


