Where to start First steps track · 15 stages
Linux Labs

curl — HTTP requests from the console

7 min Ubuntu 24.04 · curl 8.5

curl sends HTTP and HTTPS requests from the console: status code, headers, the whole exchange, certificate checks.

Cheat sheet

9 commands Printable version
  • 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

Overview

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

Options

18

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.

Recipes

5

A status code for checks

bash
curl -s -o /dev/null -w '%{http_code}\n' http://site.lab.test/
curl -sf -o /dev/null http://site.lab.test/health || echo FAIL

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.

A site by name without DNS

bash
curl -H 'Host: docs.lab.test' http://127.0.0.1/
curl --resolve docs.lab.test:443:127.0.0.1 https://docs.lab.test/

-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.

HTTPS with your own CA

bash
curl --cacert ca.pem https://shop.lab.test/
curl -v --cacert ca.pem https://shop.lab.test/ -o /dev/null 2>&1 \
  | grep -E 'subject:|issuer:|expire date|verify'

--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.

A request into a unix socket

bash
curl --unix-socket /run/app/app.sock http://localhost/

The connection goes to the socket file; the name localhost only goes into Host. Socket permissions and errors — unix-sockets.

Data and headers

bash
curl -X POST -d 'a=1&b=2' http://site.lab.test/form
curl -H 'Content-Type: application/json' -d '{"k":"v"}' URL
curl -H 'Authorization: Bearer TOKEN' https://api.lab.test/x
curl -O https://site.lab.test/file.tar.gz     # keep the file name

With -d curl picks POST itself; -X POST is optional.

Troubleshooting

6

curl: (7) Failed to connect … Couldn't connect to server

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.

curl: (6) Could not resolve host

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.

curl: (60) SSL certificate problem

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.

curl: (35) … wrong version number

https:// went to a port where the server speaks plain HTTP. Fix the scheme or the port.

Exit code 0, yet the site returns an error

Without -f a 404 or 502 is a normal response for curl. In checks look at -w '%{http_code}' or add -f.

curl: (52) Empty reply from server

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.

Danger zone

2

-k instead of a fix

-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.

Passwords on the command line

-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).

Terms

1
timeout
An elapsed waiting limit, which does not by itself identify the reason for a delay. Also appears in: stress-ng, HAProxy, nc, Boot targets: default, multi-user, rescue and emergency and 18 more

See also

  • http — request, response, status codes and headers.
  • nginx — the server you most often send requests to.
  • openssl-tls — certificates and error (60).
  • unix-sockets — --unix-socket and socket permissions.
  • dns-resolv — how a name becomes an address.
  • ss — who listens on the port when you get (7).
  • wget — downloading files and sites.
Loading…