Define one observable failure
“Stopped” might mean an HTTP error, a timeout, a job that did not finish or a process that exited. Write down one URL or action, its last known working time, the first failure time and your timezone. Include whether everyone is affected or only one client. Keep the current SSH session open while investigating; changing access rules is not a necessary first response to an application error.
This guide assumes a Linux host using systemd, an application service named first-api.service, and a local health endpoint at 127.0.0.1:3000/healthz. These defaults match the first API deployment guide. Substitute your actual names. Inspection may require administrator permission to see other users' processes or logs. Commands and outputs below are illustrative; no provider instance was tested for this guide.
Keep notes outside the failing app's own directory. Record observations before interpretations: “connection refused at 09:18 UTC” is a fact; “the VPS needs more CPU” is still a hypothesis. If the server itself is unreachable, use your established recovery access and collect connection details rather than assuming an app restart is possible.
Read the process state and its recent history
systemctl status first-api.service --no-pager --full
systemctl show first-api.service -p ActiveState -p SubState -p Result -p ExecMainStatus -p NRestarts
The status view describes the current or most recent invocation and includes recent journal messages. The selected properties give you a compact record to compare later. A failed state or increasing restart count deserves investigation; an active process still needs a request test. These are different checks, as described in the upstream systemctl reference.
If the unit is missing, first verify its name and the deployment method. An app started in an interactive terminal, a container and a systemd service have different owners and logs. Creating a new service immediately could leave two copies competing for the same port. Identify the existing arrangement before changing it.
Check the listener and make a local request
sudo ss -ltnp
curl --silent --show-error --max-time 5 http://127.0.0.1:3000/healthz
Look for the expected address and port, then identify the owning process. A process listening on another port may be healthy but unreachable by the configured proxy. A different process may have claimed the expected port. The ss manual defines the listener and process options.
If the local request works and the public HTTPS request fails, continue through DNS, TLS and proxy checks. If the listener is absent, examine startup failure. If the connection succeeds but the app returns an error, investigate that route and its dependencies. Curl without --fail can complete successfully for an HTTP error response, so read the response rather than relying only on its exit code. See curl's response and failure options.
Read around the first failure, not only the last line
sudo journalctl -u first-api.service --since "30 minutes ago" --no-pager -n 100
sudo journalctl -k --since "30 minutes ago" --no-pager -n 100
The first query selects the service; the second selects kernel messages. Adjust the interval to include the last working request and the change that preceded the outage. Access and retention determine what remains available. The upstream journalctl reference explains unit, time and kernel filters. Redact tokens, customer data and connection strings before sharing excerpts.
Illustrative excerpt from a separate app with an upload feature:
09:18:03 field-api: opening upload directory
09:18:03 field-api: EACCES: permission denied, open '/var/lib/field-api/uploads/index.json'
09:18:03 field-api: startup aborted
This points toward the service user's access to a specific path. Check the file and parent-directory ownership against the release instructions. Do not grant broad write access to the whole filesystem. A later proxy “upstream unavailable” message would be a consequence in this scenario, so repairing the proxy first would miss the cause.
Compare resources with the most recent release
free -h
df -h / /opt/first-api
df -i / /opt/first-api
These snapshots help you ask whether memory pressure, filesystem space or inode exhaustion coincided with the failure. Their interpretation belongs in the memory and disk guide; a single busy reading does not establish the cause. A service can also hit its own resource limit while the rest of the host has capacity.
Compare the deployed release identifier, start command, required environment-variable names and data paths with the last working release. Do not dump secret environment values into a report. Look for a renamed directory, missing runtime dependency, port change or incompatible database migration. State what changed and what the error predicts you should find.
Make one justified correction and verify recovery
Choose the smallest correction supported by the evidence. For the illustrative permission failure, that means restoring the intended access for the service account, then making one controlled start attempt. If you use a known working code release instead, first establish whether its database schema remains compatible. A code rollback cannot automatically reverse a data migration.
After the correction, repeat the same service, local endpoint and public request checks. Confirm that a representative application action works, that new errors have stopped, and that the process remains stable through the next normal workload. Restart policies can help recover a process, but do not make a persistently broken program healthy; consult the systemd service reference for the actual policy.
Finish your incident note with the symptom, first useful clue, change made and verification result. If the cause remains uncertain, report that uncertainty with redacted evidence rather than labeling a temporary restart a permanent fix. Improve the release checklist with the check that would have caught this failure earlier.
Documentation used
Primary references for this page. Check the documentation for the version installed in your own environment.