curl transfers data to and from URLs. It’s the Swiss Army knife for anyone running servers: test a website, debug redirects, call an API, check a certificate, measure response times — all from the terminal.

Basics

curl https://example.com                 # print the response body
curl -o page.html https://example.com    # save to a file
curl -O https://example.com/file.tar.gz  # save with the remote file name
curl -L https://example.com              # follow redirects
curl -s https://example.com              # silent (no progress meter)
curl -sS https://example.com             # silent, but still show errors

Headers

curl -I https://example.com              # HEAD request: headers only
curl -i https://example.com              # headers + body
curl -sI https://example.com | grep -i cache-control
curl -sIL http://example.com | grep -iE '^(HTTP|location)'   # trace a redirect chain

The last command shows every hop of a redirect — perfect for checking HTTP→HTTPS and www rules. See Nginx redirects.

Send custom headers

curl -H "Accept: application/json" https://api.example.com/items
curl -H "Authorization: Bearer $TOKEN" https://api.example.com/me
curl -A "Mozilla/5.0" https://example.com           # user agent
curl -H "Host: example.com" http://203.0.113.10/    # test a vhost before DNS points to it

Test a site before DNS changes

--resolve makes curl connect to a specific IP for a hostname — including correct SNI for HTTPS:

curl -I --resolve example.com:443:203.0.113.10 https://example.com/

Indispensable when migrating a site to a new server.

POST data and JSON

curl -X POST -d "name=alice&role=admin" https://example.com/form
curl -X POST https://api.example.com/items \
  -H "Content-Type: application/json" \
  -d '{"name":"widget","qty":3}'
curl --json '{"name":"widget"}' https://api.example.com/items   # curl 7.82+: sets headers for you
curl -X POST -d @payload.json -H "Content-Type: application/json" https://api.example.com/items

Other methods:

curl -X PUT -d '{"qty":5}' -H "Content-Type: application/json" https://api.example.com/items/1
curl -X PATCH …
curl -X DELETE https://api.example.com/items/1

Upload files

curl -F "[email protected]" https://example.com/upload          # multipart form
curl -T backup.zip https://example.com/dav/backup.zip -u user:pass   # PUT (WebDAV)

Authentication

curl -u alice https://example.com/admin/          # prompts for password
curl -u alice:secret https://example.com/admin/   # inline (visible in shell history!)
curl --netrc-file ~/.netrc-api https://api.example.com/

Prefer tokens in environment variables over passwords on the command line.

Cookies

curl -c cookies.txt -d "user=alice&pass=…" https://example.com/login
curl -b cookies.txt https://example.com/dashboard

HTTPS and certificates

curl -v https://example.com 2>&1 | grep -E 'SSL|subject|expire|issuer'
curl --cacert ca.pem https://internal.example.com/
curl -k https://self-signed.local/       # skip verification — testing only!

Check expiry quickly:

curl -vsI https://example.com 2>&1 | grep -i 'expire date'

More in check SSL certificate expiry.

Measure response times

curl -o /dev/null -s -w 'dns:%{time_namelookup} connect:%{time_connect} tls:%{time_appconnect} ttfb:%{time_starttransfer} total:%{time_total}\n' https://example.com
  • dns — name resolution
  • connect — TCP connected
  • tls — TLS handshake done
  • ttfb — first byte from the server (server processing time shows here)
  • total — complete

A high TTFB with fast connect points to slow application code or database; a slow connect points to network distance — see latency vs bandwidth.

Just the status code:

curl -o /dev/null -s -w '%{http_code}\n' https://example.com

Downloads

curl -C - -O https://example.com/big.iso        # resume an interrupted download
curl --limit-rate 2M -O https://example.com/big.iso
curl -O https://example.com/file[1-5].txt       # URL globbing: file1…file5

Debugging

curl -v https://example.com                  # request/response headers and TLS details
curl --trace-ascii trace.txt https://example.com
curl --http1.1 https://example.com           # force HTTP version
curl --http2 -I https://example.com
curl -4 https://example.com                  # IPv4 only (-6 for IPv6)
curl --connect-timeout 5 --max-time 20 https://example.com

Health checks in scripts

if curl -fsS --max-time 10 https://example.com/health > /dev/null; then
  echo up
else
  echo down
fi

-f makes curl return a non-zero exit code for HTTP errors (4xx/5xx) — essential in scripts and cron jobs.

Quick reference

Task Command
Headers only curl -I URL
Follow redirects curl -L URL
Save file curl -O URL
JSON POST curl --json '{…}' URL
Custom header curl -H "K: V" URL
Basic auth curl -u user URL
Status code curl -o /dev/null -s -w '%{http_code}' URL
Timing curl -w '…%{time_total}' -o /dev/null -s URL
Fixed IP curl --resolve host:443:IP URL
Fail on errors curl -f

Also see wget examples for recursive downloads and mirroring.

  • curl
  • Command Line
  • HTTP