DeployDoctor
When your site is down at 2 a.m., DeployDoctor is the one command that tells you what is actually broken.
deploydoctor is a small, no-magic CLI that runs the checks you would otherwise run by hand when a deployment goes sideways — DNS, HTTP/HTTPS, TLS certificates, port reachability, and the usual suspects on the host itself (nginx -t, ss -tulpn, docker ps, nginx error logs).
Output is a single readable Rich report with PASS / WARN / FAIL / SKIP markers, a summary, the most likely issue, and a set of copy-pasteable next commands.
Demo
Install
pip install deploydoctor
Or with pipx (recommended for CLI tools):
pipx install deploydoctor
Development (editable install with linter + tests):
git clone https://github.com/saidamiraslanli/deploydoctor.git
cd deploydoctor
pip install -e ".[dev]"
Python 3.11+.
Quick usage
deploydoctor check example.com # full diagnosis: remote + local
deploydoctor remote example.com # external-only: DNS, HTTP, HTTPS, SSL, ports
deploydoctor local # this host: nginx, docker, ss -tulpn
deploydoctor version
deploydoctor --help
# Also runnable as a module
python -m deploydoctor check example.com
A bare hostname (example.com) or a full URL (https://example.com/foo) both work — the host is extracted automatically.
Example output
─────────── DeployDoctor Report for example.com ───────────
╭─ DNS ─────────────────────────────────────────────────────╮
│ PASS Resolved 1 A / 1 AAAA record(s) │
│ • A: 93.184.216.34 │
│ • AAAA: 2606:2800:220:1:248:1893:25c8:1946 │
╰───────────────────────────────────────────────────────────╯
╭─ HTTPS ───────────────────────────────────────────────────╮
│ FAIL 502 gateway error │
│ → Possible cause: reverse proxy cannot reach │
│ upstream app │
│ → sudo systemctl status nginx │
│ → sudo tail -n 50 /var/log/nginx/error.log │
│ → ss -tulpn │
╰───────────────────────────────────────────────────────────╯
╭─ SSL ─────────────────────────────────────────────────────╮
│ WARN Certificate expires in 12 day(s) │
│ • Subject CN: example.com │
│ • Issuer: Let's Encrypt R3 │
│ → Schedule renewal (sudo certbot renew --dry-run) │
╰───────────────────────────────────────────────────────────╯
Summary
┌────────┬──────────┬────────┬─────────┐
│ Passed │ Warnings │ Failed │ Skipped │
├────────┼──────────┼────────┼─────────┤
│ 3 │ 1 │ 1 │ 0 │
└────────┴──────────┴────────┴─────────┘
More worked examples in docs/examples/:
502-bad-gateway.md— reverse proxy can't reach upstream appssl-expired.md— certificate expired or about to expirenginx-upstream-down.md— nginx is up, the app behind it isn'tcloudflare-525.md— Cloudflare can't complete TLS handshake with origin
What problems it detects
| Layer | Detected |
|---|---|
| DNS | NXDOMAIN, missing A/AAAA, resolver timeouts |
| HTTP / HTTPS | connection refused, connect/read timeouts, too many redirects, SSL verification failures, 4xx, 5xx, 502 / 503 / 504 gateway errors, Cloudflare 525 SSL handshake failures, redirect chains |
| SSL / TLS | expired certs, certs expiring within 30 days, verify failures, missing chain, hosts without TLS |
| Ports | 80 / 443 closed, filtered, refused, or timing out from outside |
| Local host (Linux) | nginx config syntax (nginx -t), listening sockets (ss -tulpn), nginx error log tail, running Docker containers, missing tools |
Local vs remote mode
DeployDoctor exposes two scopes deliberately:
remote <domain>— outside view. Everything runs over the network: DNS, HTTP, HTTPS, SSL, port probes. Safe to run from a laptop or from a monitoring host. Does not touch the deployment host.local— inside view. Inspects the host you run it on: is nginx installed, is its config valid, what is listening, what does the error log say, what Docker containers are running. Linux-only by design; cleanlySKIPs on Windows / macOS or when commands and permissions are missing.check <domain>— runs both back-to-back, which is what you want when SSHed into the box that serves the domain.
This split exists so you can use the tool from anywhere without the local checks polluting the report with noise.
CI exit codes
| Code | Meaning |
|---|---|
0 |
All checks passed |
1 |
At least one WARN |
2 |
At least one FAIL |
Friendly for cron, CI, uptime scripts:
deploydoctor remote example.com || curl -X POST https://my-alert-hook
# GitHub Actions example
- name: Post-deploy smoke check
run: deploydoctor remote example.com
Roadmap
- HTTP/2 + HTTP/3 capability probe
- TLS handshake details (protocol, cipher, OCSP stapling)
- Configurable check timeouts via CLI flag
- JSON output mode (
--json) for piping into other tools - systemd unit health checks (
is-active,is-failed) - Apache / Caddy parity for local config tests
deploydoctor watchfor continuous monitoring
Troubleshooting
nginx -treports permission denied — run withsudo; DeployDoctor will surfaceSKIPrather than fail.- All local checks
SKIP— local checks are gated to Linux. Run on the deployment host. - SSL check is
SKIP— port 443 refused; the domain likely doesn't serve TLS. - DNS
timeout— typically a firewall blocking UDP/53 on the host running the CLI.
Contributing
Pull requests welcome. See CONTRIBUTING.md for setup, lint / test commands, and the rules every new check must follow.
Quick start:
git clone https://github.com/saidamiraslanli/deploydoctor.git
cd deploydoctor
pip install -e ".[dev]"
pytest
ruff check .
License
MIT.
Metadata
Release files for deploydoctor 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| deploydoctor-0.1.2.tar.gz | 206.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| deploydoctor-0.1.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 223.7 kB
Release files / deploydoctor-0.1.2.tar.gz
| Download URL | deploydoctor-0.1.2.tar.gz |
|---|---|
| Size | 206.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b502f8234af71919d128b7de07468d1d6b2bb77adaf7bd61c4e83afa9fa52ed4
|
|
BLAKE2b-256 checksum How to use checksums |
b8847139530ca794455d78ff0ece5eff148d2ee8cba567c66555f3677ef5c87d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on May 23, 2026.
Transparency logRelease files / deploydoctor-0.1.2-py3-none-any.whl
| Download URL | deploydoctor-0.1.2-py3-none-any.whl |
|---|---|
| Size | 17.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d9c174a8224f61343b7653f6fcf7961d77799ba510830e7d08562243bbe1f4ea
|
|
BLAKE2b-256 checksum How to use checksums |
8d8e3ea6eaf4b51eee2e70231fda7dadf12df43dc4b349d584c0c1aa38b98879
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on May 23, 2026.
Transparency log