Linux CLI Best Practices
A condensed summary of the 25 most important Linux CLI practices for Node.js backend teams - shared portable content; script common ops tasks.
Search across all documentation pages
A condensed summary of the 25 most important Linux CLI practices for Node.js backend teams - shared portable content; script common ops tasks.
Prefer SIGTERM over SIGKILL: kill <PID> first so Fastify/Express close() drains HTTP and DB pools; kill -9 only after graceful timeout (Process Inspection).
Run Node APIs under systemd or Kubernetes: Not naked node & in SSH sessions - processes die when the session drops.
Persist ops sessions with tmux: Long log tails and port-forward tunnels survive disconnects.
Allow SSH before enabling ufw: ufw allow 22/tcp before ufw enable or lock yourself out.
Non-root binds high ports: Run Node on 3000+; put nginx/caddy on 443 in front - never run Node as root for port 80.
Diagnose with journalctl and kubectl logs: systemctl status → journalctl -u <svc> on VMs; kubectl logs + describe in k8s.
Lock down secret files: chmod 600 on .env and credential files on developer machines.
Prefer ripgrep over grep in repos: rg respects .gitignore and skips node_modules/.
Scope find and grep: Never search from / unfiltered - pass project dir and exclude node_modules.
Use jq on JSON logs: Pino one-line JSON - jq 'select(.level=="error")' beats grep Error (CLI Basics for Node).
curl -sf for health smoke: Fail scripts on 5xx; add -w time_total for latency spot checks.
ss replaces netstat: ss -tlnp for listening ports and backlog summary.
lsof for EADDRINUSE: lsof -i :3000 before killing random node processes.
Start scripts with set -euo pipefail: Fail fast; undefined variables error; pipe failures propagate.
Use $() not backticks: Nested command substitution and clearer quoting.
Redirect stderr: cmd > out.log 2>&1: Capture both streams for post-mortem bundles.
Use npm ci in CI scripts: Reproducible installs from lockfile - never npm install in deploy pipelines.
Pin Node in CI and Docker: 24.18.0 matches .nvmrc and engines.
Propagate x-request-id in curl smoke tests: Correlate manual checks with centralized logs.
Free stuck dev ports with SIGTERM first: lsof -ti :3000 | xargs kill before -9.
NODE_OPTIONS heap bump is temporary: --max-old-space-size for build OOM; recurring OOM needs leak triage.
kubectl port-forward for private APIs: Do not expose prod to public internet for debugging.
Commit bin/smoke.sh to repo: Same checks locally, in SSH runbooks, and post-deploy hooks.
macOS sed quirk for portable scripts: sed -i '' on macOS vs sed -i on Linux - document in CONTRIBUTING or use gnu-sed.
Document platform-specific ops in runbooks: AWS ECS exec vs kubectl exec - link from service README.
Prefer running jq from bastion against forwarded logs. Debug containers may include jq; minimal prod images often omit it.
Install in debug sidecar or use top -b -n 1 one-shot. Do not bloat production image for interactive tools unless SRE approves.
Day one: curl, jq, lsof. Week one: kubectl logs, smoke scripts. Deep systemd/nginx is SRE-partnered (Onboarding Basics).
Stack versions: This page was written for Node.js 24.18.0 (Active LTS), npm 10+, TypeScript 5.6+, Express 5, Fastify 5, and NestJS 11.
Reviewed by Chris St. John·Last updated Jul 16, 2026