Skip to content

curl: HTTP Debugging in CLI

cURL is the standard tool for debugging HTTP in the terminal. It ships out of the box on Linux and macOS and is present in most Docker images. Need to quickly check an API, inspect response headers, or trace a redirect issue — one command line is enough.

Basic Debug Flags

The most common scenario: get a response and see what the server returned. The -i flag prints headers before the body, -v enables verbose mode with connection details.

curl -i https://api.example.com/health
curl -v https://api.example.com/health

The difference: -i shows headers plus body, -v adds DNS resolution, TLS handshake, and debug info before the request.

A HEAD request checks resource availability and metadata without downloading the body:

curl -I https://api.example.com/v2/large-file.zip
Note

HEAD does not guarantee the server supports ranges or caching — this depends on server configuration.

Methods and Request Body

By default, curl sends GET. For other methods, use the -X flag.

curl -X POST https://api.example.com/users
curl -X DELETE https://api.example.com/users/42

Request body is passed via -d. For JSON APIs, a typical pattern:

curl -X POST https://api.example.com/users \
  -H "Content-Type: application/json" \
  -d '{"name": "alice", "role": "admin"}'
Tip

Multiline JSON is easier to read in a heredoc when the body is large:

curl -X POST https://api.example.com/users \
  -H "Content-Type: application/json" \
  -d @- <<'EOF'
  {
    "name": "alice",
    "role": "admin"
  }
  EOF

To send form data or data from a file:

curl -X POST https://api.example.com/upload \
  -d "username=admin" \
  -d "password=secret"

Custom Headers

The -H flag adds or overrides a header. You can use -H multiple times.

curl -X GET https://api.example.com/orders \
  -H "Accept: application/json" \
  -H "X-Request-ID: $(uuidgen)" \
  -H "Cache-Control: no-cache"

Overriding the Host header is useful when debugging virtual hosts or proxies:

curl -X GET http://10.0.0.5/ \
  -H "Host: example.com"

To remove a default header, use -H "Accept:" — empty value after the colon.

Auth and Certificates

Basic HTTP auth via -u in user:password format:

curl -u admin:secret https://api.example.com/admin

For Bearer tokens, use a header:

curl -H "Authorization: Bearer eyJhbGci..." https://api.example.com/me
Warning

-u sends credentials in plain text if TLS is not used. Always use HTTPS for production servers.

When working with self-signed certificates, the -k flag disables verification:

curl -k https://dev.example.com/api

For known hosts and pinned certificates:

# specify CA bundle
curl --cacert /etc/ssl/certs/ca-certificates.crt https://secure.example.com
# check remote host certificate
curl -v https://secure.example.com 2>&1 | grep "Server certificate"

Timeouts and Saving Response

By default, curl waits indefinitely. For scripts and monitoring, set limits:

FlagPurpose
--max-time Ntotal timeout in seconds
--connect-timeout Nconnection timeout
curl --max-time 5 --connect-timeout 2 https://slow-api.example.com

Saving the response:

# to file with original name
curl -O https://example.com/reports/november.csv
# to specified file
curl -o report.csv https://example.com/reports/november.csv

Redirect stdout to pipe the response body:

curl -s https://api.example.com/health | jq .status

Redirects

Curl does not follow redirects by default. The -L flag enables automatic redirection:

curl -L https://bit.ly/api-status

To debug a redirect chain:

curl -Lv https://short.link/resource 2>&1 | grep -E "< HTTP|< Location"
Note

-L limits redirect depth (default 50). Infinite redirect loops are a common cause of curl hanging.

A flag combination for a full picture when debugging an API:

curl -X POST https://api.example.com/orders \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"item_id": 101, "qty": 2}' \
  -iv --max-time 10 -o response.json

This command shows request and response headers, saves the body to a file, and enforces a 10-second timeout.