A status code for checks
The first command prints the code; 000 means there was no HTTP response. The
second relies on the exit code: -f turns 4xx and 5xx into error 22.
curl sends HTTP and HTTPS requests from the console: status code, headers, the whole exchange, certificate checks.
curl -i http://site.lab.test/
code, headers, body
curl -I http://site.lab.test/
headers only (HEAD)
curl -v -o /dev/null http://site.lab.test/
the whole exchange
curl -s -o /dev/null -w '%{http_code}\n' http://site.lab.test/
curl -H 'Host: docs.lab.test' http://127.0.0.1/
curl --resolve shop.lab.test:443:127.0.0.1 https://shop.lab.test/
curl --cacert ca.pem https://shop.lab.test/
trust your own CA
curl --unix-socket /run/app/app.sock http://localhost/
curl -X POST -H 'Content-Type: application/json' -d '{"a":1}' URL
curl sends a request and prints the response body to stdout, errors to
stderr. For debugging sites and proxies it is the first tool: you see the
status code, headers, and what curl did before HTTP — DNS, the connection,
TLS. How requests and responses are built — see http.
curl's exit code tells whether things got as far as HTTP. A response with any code, even 404 or 502, is a success for curl, exit code 0. A non-zero code means there was no response or it failed a check:
| Exit code | What happened |
|---|---|
| 6 | the name did not resolve to an address |
| 7 | the connection did not open |
| 28 | the time limit ran out |
| 35 | TLS negotiation failed: e.g. https:// to an HTTP port |
| 52 | the server closed the connection without a response |
| 60 | the certificate failed verification |
| 22 | with -f: a 4xx or 5xx response |
The table below lists the main options. -s hides both progress and errors;
scripts pair it with -S so errors stay visible.
| Option | What it does | Example |
|---|---|---|
-s --silent |
No progress bar or connection errors printed; handy for scripts. | curl -s https://example.com |
-f --fail |
Exit with an error on HTTP 4xx/5xx instead of printing the error body — important for scripts. | curl -sf https://example.com |
-L --location |
Follow redirects (3xx). | curl -L https://example.com |
-I --head |
Response headers only (a HEAD request). | curl -I https://example.com |
-v --verbose |
Show the whole exchange — request, response, TLS handshake. | curl -v https://example.com |
-X --request method |
The HTTP method to use (POST, PUT, DELETE…). | curl -X POST https://api.example.com/x |
-d --data data |
Send data in the body (defaults to POST, form-urlencoded). | curl -d 'a=1&b=2' https://api.example.com/x |
-H --header header |
Add a custom request header. | curl -H 'Authorization: Bearer TOKEN' https://api.example.com/x |
-i --include |
Print the status line and response headers before the body. | curl -i http://site.lab.test/ |
-S --show-error |
Show the error even together with -s. | curl -sS https://example.com |
-w --write-out format |
Print a metric after the request — status code, time, size. | curl -s -o /dev/null -w '%{http_code}\n' https://example.com |
-o --output file |
Save the response body to the given file. | curl -o out.bin https://example.com/x |
-O --remote-name |
Save using the filename taken from the URL. | curl -O https://example.com/file.tar.gz |
--resolve host:port:address |
Override DNS resolution for this request. | curl --resolve example.com:443:10.0.0.1 https://example.com |
--cacert file |
Trust the root certificate from the file for this request. | curl --cacert ca.pem https://shop.lab.test/ |
--unix-socket path |
Connect through a unix socket instead of TCP; the URL name only goes into Host. | curl --unix-socket /run/app/app.sock http://localhost/ |
-m --max-time seconds |
A time limit for the whole request; when it runs out, exit code 28. | curl -m 5 http://site.lab.test/ |
-k --insecure |
Skip TLS certificate verification — for debugging only, never for production. dangerous | curl -k https://self-signed.local |
Nothing found. Try a shorter query.
The first command prints the code; 000 means there was no HTTP response. The
second relies on the exit code: -f turns 4xx and 5xx into error 22.
-H 'Host: …' changes only the header — the server picks the site by it. For
HTTPS use --resolve: the name from the URL goes into SNI and into the
certificate check as well.
--cacert adds a trusted root for one request. -v shows which certificate
arrived and how the check ended: SSL certificate verify ok. or the reason for
refusal.
The connection goes to the socket file; the name localhost only goes into
Host. Socket permissions and errors — unix-sockets.
With -d curl picks POST itself; -X POST is optional.
Nothing listens on the address and port, or a firewall drops the connection.
Check sudo ss -tlnp on the server. With --unix-socket curl prints the same
Failed to connect to localhost port 80 both when the file is missing and
when permission is denied.
The name was not found: a typo, no DNS record, nothing in /etc/hosts. Check
getent hosts <name> (dns-resolv) or bypass DNS with --resolve.
The certificate failed one of three checks: trust (unable to get local issuer
certificate, self-signed certificate), name (no alternative certificate
subject name matches) or date (certificate has expired). Each one is
explained in openssl-tls.
https:// went to a port where the server speaks plain HTTP. Fix the scheme or
the port.
Without -f a 404 or 502 is a normal response for curl. In checks look at
-w '%{http_code}' or add -f.
The connection opened, but the server closed it without a response: the application crashed on the request or speaks another protocol. Check the application log.
-k (--insecure) turns certificate verification off entirely. A check with
-k passes even with a spoofed server or an expired certificate. If you need
your own CA, use --cacert.
-u user:pass and -H 'Authorization: …' show up in shell history and in
other users' ps. For scripts use a file with mode 600 (-K file or
--netrc).
--unix-socket and socket permissions.Found an inaccuracy? Report an error in the article