Linux CLI Best Practices
A condensed summary of the 25 most important Linux CLI practices for Python backend teams - fast, safe terminal workflows on servers and laptops.
Search across all documentation pages
A condensed summary of the 25 most important Linux CLI practices for Python backend teams - fast, safe terminal workflows on servers and laptops.
Prefer SIGTERM over SIGKILL: Allow uvicorn/Gunicorn to drain connections before kill -9 (Process & Resource Management).
Run APIs under systemd or Kubernetes: Not naked nohup in SSH sessions - survives disconnects and reboots.
Persist ops with tmux: Long migrations and log tails survive laptop sleep (SSH & Remote Work).
Allow SSH before enabling firewall: Open port 22 (or bastion path) before ufw enable - avoid lockout.
Non-root service user: Run Python on high ports behind nginx/caddy - never as root for port 80.
Diagnose with journalctl: systemctl status then journalctl -u <unit> -n 200 on VMs (Sysadmin Essentials).
Lock down secret files: chmod 600 on .env and credential files.
Prefer ripgrep in repos: rg respects .gitignore and skips .venv/ (Search & Regex).
Scope find and grep: Never search from / unfiltered - start at /var/log/app or project root.
Use jq on JSON logs: Filter level, request_id, duration_ms - not grep Error on structured lines (Pipes & Text Processing).
curl -sf for health smoke: Scripts fail on 5xx; add -w time_total for latency spot checks.
ss replaces netstat: ss -tlnp for listening ports and backlog.
lsof for port conflicts: lsof -i :8000 before killing random python PIDs.
Start bash scripts with set -euo pipefail: Fail fast; catch pipeline errors.
Use $() not backticks: Nested command substitution and clearer quoting.
Redirect stderr in logs: cmd > out.log 2>&1 for post-mortem bundles.
Use uv sync --frozen in deploy: Reproducible env from lockfile - not pip install -r without hash.
pipx for global CLIs: ruff, httpie, copier isolated from project venv (Python-in-the-Shell).
Never sudo pip: Breaks distro Python - venv/uv only.
ProxyJump in SSH config: Document bastion path for staging/prod - no ad-hoc IP typing.
LocalForward bind 127.0.0.1: Database tunnels not exposed on all interfaces.
df and du before deploy: Disk full breaks log writes and uploads.
Commit smoke scripts to bin/: Same curl health checks locally, in CI, and post-deploy SSH.
Promote repeated aliases to scripts: Versioned bin/ with review beats personal shell only.
LC_ALL=C for ASCII logs: Predictable sort/awk when grepping access logs.
htop interactive default; top when minimal image lacks htop package.
Shell for glue on server; Python when logic exceeds ~20 lines or needs tests in repo.
WSL2 for same CLI doc; production triage still Linux SSH.
kubectl logs -f deploy/billing-api - same jq filters on container stdout.
Stack versions: This page was written for Python 3.14.0 (stable 3.14, maintenance 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, and uv 0.6+.
Reviewed by Chris St. John·Last updated Jul 19, 2026