curl - transfer a URL
curl [options...] <url>...
Options you will use
-v- show the whole conversation: DNS, connect, TLS, request and response headers
-s / -S- silent / but still show errors (use together: -sS)
-o FILE / -o /dev/null- where the body goes
-I- HEAD request, headers only
-i- include response headers in the output
-L- follow redirects
-k- do not verify the certificate (debugging only)
--cacert FILE- trust these CAs
-f- exit 22 on HTTP >= 400
-w FORMAT / -w @file- print variables after the transfer: %{http_code} %{time_namelookup} %{time_connect} %{time_appconnect} %{time_starttransfer} %{time_total} %{remote_ip} %{num_redirects} %{errormsg}
-m SECS- total time limit
--connect-timeout SECS- limit for the TCP connect only
--resolve H:P:IP- skip DNS for this host
-x URL- use this proxy; env: http_proxy (lowercase only), https_proxy, no_proxy
-H "K: V"- extra header
-X M, -d DATA- method, request body
-s, --silent- Silent mode: no progress meter or error messages. Add -S to still see errors.
-S, --show-error- With -s: still print an error message when it fails.
-v, --verbose- Show the whole conversation on stderr: DNS, connect, TLS handshake, request (>) and response (<) headers.
-o, --output FILE- Write the body to FILE instead of stdout (-o /dev/null to throw it away).
-O, --remote-name- Save to a local file named like the remote file.
-I, --head- Fetch the headers only (a HEAD request).
-i, --include- Include the response headers in the output.
-L, --location- Follow redirects (3xx with a Location: header).
-k, --insecure- Do not verify the server certificate. Debugging only - it hides exactly the problem you may be chasing.
-f, --fail- Fail fast with no output on HTTP errors: exit 22 on status >= 400 (without it curl exits 0 on a 500).
-w, --write-out FORMAT- Print variables after the transfer: %{http_code} %{time_connect} %{time_starttransfer} %{time_total} %{remote_ip}... (or @file).
-m, --max-time SECONDS- Maximum time for the whole operation; exit 28 when it runs out.
--connect-timeout SECONDS- Maximum time for the connection phase only (DNS + TCP + TLS).
-H, --header HEADER- Extra header to include, e.g. -H "Host: shop.lab" or -H "Authorization: Bearer $TOKEN".
-X, --request METHOD- The request method: POST, PUT, DELETE... (-d already implies POST).
-d, --data DATA- Send DATA as the request body (POST, application/x-www-form-urlencoded). @file reads it from a file.
--data-urlencode DATA- Like -d, but URL-encodes the value:
--data-urlencode 'query=rate(x[5m])'- how you send PromQL with its brackets and spaces. --data-raw DATA- Like -d, but @ is not special.
--json DATA- Send JSON: sets Content-Type and Accept to application/json.
-G, --get- Send the -d / --data-urlencode data as a query string in a GET request instead of a POST body.
-u, --user USER:PASSWORD- Server user and password (basic auth).
--cacert FILE- Verify the server with the CA certificates in FILE.
--cert FILE- Client certificate for mutual TLS.
--key FILE- Private key of the client certificate.
--resolve HOST:PORT:ADDR- Use ADDR for HOST:PORT instead of DNS (keeps SNI and Host right - unlike putting the IP in the URL).
-x, --proxy URL- Use this proxy. Env: http_proxy (lowercase only), https_proxy, no_proxy.
--noproxy HOSTS- Hosts that bypass the proxy, comma separated; '*' = no proxy for anything.
--retry N- Retry N times on transient errors (timeouts, 408, 429, 5xx), with backoff.
--retry-connrefused- With --retry: treat "connection refused" as transient too (a service that is still starting).
--retry-delay SECONDS- Fixed wait between retries instead of the exponential backoff.
--http1.1- Use HTTP/1.1 (no HTTP/2 via ALPN).
--http2- Use HTTP/2.
-4, --ipv4- Resolve names to IPv4 addresses only.
-6, --ipv6- Resolve names to IPv6 addresses only.
-A, --user-agent NAME- The User-Agent header to send.
-b, --cookie DATA- Send cookies (NAME=VALUE or a cookie file).
-T, --upload-file FILE- Upload FILE (PUT).
--compressed- Ask for a compressed response and decompress it.
-N, --no-buffer- Disable output buffering (for streams).
Examples
$ curl -v https://api.lab/where does it fail
$ curl -s -o /dev/null -w '%{http_code} %{time_total}\n' http://oncall-lab/status and time only
$ curl -w @curl-format.txt -o /dev/null -s https://host/paththe timing breakdown
$ curl -v telnet://db.lab:5432is the port reachable at all
Gotchas
- The -w times are cumulative from the start: read the gaps between them.
- Exit codes: 6 DNS, 7 could not connect, 28 timeout, 35 TLS handshake, 47 too many redirects, 52 empty reply, 56 receive failure / proxy tunnel, 60 certificate.
- curl ignores uppercase HTTP_PROXY (httpoxy); HTTPS_PROXY and NO_PROXY work in either case.
Taught in
- 9.1 The handshake, and the three ways a connection fails
- 9.15 TLS: the handshake, the chain, and trust
- 9.21 HTTP on the wire, with curl -v
- 16.6 Service types: NodePort, LoadBalancer, ExternalName, headless
- 21.1 Actuator: the seam between the app and the platform
- 21.3 Health groups, liveness vs readiness, and the three probes
- 21.8 Graceful shutdown, TimeoutStopSec and terminationGracePeriodSeconds
- 21.22 Retries, jitter, circuit breakers, bulkheads, backpressure
Try curl in a real terminal Free, in your browser - a real Ubuntu terminal to try it in, with missions that check your work.