Tutorial

cURL download file: save files, resume downloads and use a proxy

Download files with curl: -o, -O, -J, folders, -C - to resume, why --retry restarts in older curl, and proxies. Every command run on 10 October 2026.

HProxy Team··Updated October 10, 2026·13 min read
HProxy.Tutorial

Skip the dead lists.

Our free proxy list re-checks every exit every few minutes across 100+ countries, with a live last-checked time, so you copy IPs that worked moments ago, not a stale text dump.

Open the free proxy list→

To download a file with curl, add -O to keep the file name from the URL, or -o and a name of your own. Add -L so curl follows redirects, and -f so it does not save an error page as your file. If the download breaks, run the same command with -C - added, and curl continues where it stopped.

curl -L -f -O https://example.com/file.zip

We ran every command below on 10 October 2026. Most ran with curl 8.5.0, the version Ubuntu 24.04 ships, and some with curl 8.21.0, the copy in Windows 11. Our test file was a 165,028-byte PNG on our own site. The two versions behave differently in three places, and this page shows where.

How do you download a file with curl?

You need curl, which Windows 10 and 11, macOS and most Linux systems include. What is cURL? shows how to check your version, and the version matters here more than usual.

Step 1: choose the name with -o

curl -o tracker.png https://hproxy.com/blog/_assets/img/amazon-price-tracker-check-output.png
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  161k  100  161k    0     0   269k      0 --:--:-- --:--:-- --:--:--  269k

-o writes the body to the file you name. The meter shows 161k for 165,028 bytes, because curl counts 1k as 1,024 bytes.

Step 2: keep the name from the URL with -O

curl -O https://hproxy.com/blog/_assets/img/amazon-price-tracker-check-output.png

-O saved the file as amazon-price-tracker-check-output.png, the last part of the URL. Three details came out of our runs:

  • The query string is dropped. robots.txt?v=2 was saved as robots.txt.
  • A file of the same name is overwritten without a question.
  • A URL that ends in a slash has no name to take. curl 8.5.0 stopped with exit 23 and Failed writing received data to disk/application. curl 8.21.0 saved the same page as curl_response, the fallback the manual gives for 8.10.0 and newer.

Step 3: let the server choose the name with -J

curl -OJ 'https://httpbin.org/response-headers?Content-Disposition=attachment%3B%20filename%3Dreport.csv'

A server can suggest a name in its Content-Disposition header, which RFC 6266 defines. -J tells -O to use it, and our run saved report.csv. curl does not overwrite an existing file this way unless you add --clobber. The manual also warns that a hostile server could pick a dangerous name, such as a DLL on Windows.

Redirects change the name as well. After a redirect, -O still names the file after the first URL. Our download through httpbin's redirect-to address was saved as redirect-to on both builds. With -OJ, curl 8.21.0 named it after the target, llms.txt, while curl 8.5.0 still wrote redirect-to. The manual dates that fallback to curl 8.19.0.

Step 4: save into a folder

curl --create-dirs --output-dir downloads/2026-10 -O https://hproxy.com/robots.txt

--output-dir (curl 7.73.0 and newer) puts the file in that folder. It fails when the folder does not exist, so --create-dirs creates it. Our run made downloads/2026-10 and saved the 910-byte file inside.

Step 5: download several files

Give every URL its own -O, or put --remote-name-all in front to apply -O to all of them. -Z (--parallel, from curl 7.66.0) fetches them at the same time, 50 at most by default.

curl -# -O https://hproxy.com/robots.txt -O https://hproxy.com/llms.txt

-# swaps the meter for a simple bar. Our two files came without a stated size, so the bar showed only #=#=# for each.

Our terminal on 10 October 2026, curl 8.5.0 on Ubuntu 24.04. curl -o saves our PNG as tracker.png, 161k at 269k per second. curl -O saves it under its own name, and ls shows both files at 165028 bytes. curl -sSO on https://example.com/ fails with curl: (23) Failed writing received data to disk/application. curl -OJ on httpbin's response-headers address prints report.csv. With --create-dirs and --output-dir, robots.txt lands in downloads/2026-10 with 910 bytes. curl -# with two -O options prints #=#=# twice.
Our own run on our server, 10 October 2026, 19:18 UTC: curl 8.5.0 on Ubuntu 24.04, captured off-screen. Each command is printed before its output, then its exit code.

How do you know the file is the one you wanted?

Exit code 0 means curl finished the transfer, not that you got the file. Two failures in our run exited 0 and still left a file behind.

Our terminal on 10 October 2026, curl 8.5.0. curl -sO http://hproxy.com/robots.txt saves an HTML page titled 301 Moved Permanently. With -L the file starts with User-Agent. curl -sO on a missing zip saves an HTML document with exit 0. With -f, curl prints curl: (22) The requested URL returned error: 404, and no file exists. A download cut by -m 3 stops at 89337 of 165028 bytes with exit 28. curl -C - resumes from byte position 89337, and sha256sum shows the same hash as a full download. curl -C - on the complete file resumes from byte position 165028 and transfers nothing.
Our own run on our server, 10 October 2026, 19:22 UTC: curl 8.5.0 on Ubuntu 24.04, captured off-screen. The test file is a 165,028-byte PNG on our own site.

A redirect page saved as your file

Our site sends http:// visitors to https:// with a 301. Without -L, curl saved that answer under the name robots.txt:

$ curl -sO http://hproxy.com/robots.txt; head -c 75 robots.txt
<html>
<head><title>301 Moved Permanently</title></head>
<body>
<center>

With -L, the same command saved the real 910-byte file. Following redirects with curl covers the limits and what happens to logins.

An error page saved as your file

A missing file gave a 404, and curl saved the error page as report-2026.zip with exit code 0. The file command found an HTML document inside. With -f, curl stopped with exit 22 and wrote no file:

$ curl -sSfO https://hproxy.com/report-2027.zip; ls -l report-2027.zip
curl: (22) The requested URL returned error: 404
ls: cannot access 'report-2027.zip': No such file or directory

If you want the error page and the exit code, use --fail-with-body, from curl 7.76.0.

Check the size, a hash or a signature

After the download, compare the file with what the publisher states. -w '%{http_code} %{size_download}' makes curl print the status and the byte count. sha256sum on Linux, or Get-FileHash in PowerShell, prints a SHA-256 hash to compare with a published one.

curl's own releases come with a signature instead. We checked curl 8.22.0 the way curl's verify page describes, with the release key from the link on that page:

curl -sSfLO https://curl.se/download/curl-8.22.0.tar.xz
curl -sSfLO https://curl.se/download/curl-8.22.0.tar.xz.asc
curl -sSf -o curl-key.asc 'https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x27edeaf22f3abceb50db9a125cc908fdb71e12c2'
gpg --import curl-key.asc
gpg --verify curl-8.22.0.tar.xz.asc curl-8.22.0.tar.xz
gpg: Signature made Wed Sep  2 07:48:56 2026 CEST
gpg:                using RSA key 27EDEAF22F3ABCEB50DB9A125CC908FDB71E12C2
gpg: Good signature from "Daniel Stenberg <daniel@haxx.se>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: 27ED EAF2 2F3A BCEB 50DB  9A12 5CC9 08FD B71E 12C2

We gave each gpg command --homedir ./gpg, a throwaway keyring; your own gpg needs no extra option. The fingerprint is the one curl's verify page lists. The warning means gpg itself cannot vouch for the key. Comparing the fingerprint with the publisher's own page is the step that does.

Our terminal on 10 October 2026, curl 8.5.0 and gpg on Ubuntu 24.04. curl downloads curl-8.22.0.tar.xz, its .asc signature and the release key. gpg reports a good signature from Daniel Stenberg, with fingerprint 27ED EAF2 2F3A BCEB 50DB 9A12 5CC9 08FD B71E 12C2. Then a stub proxy on 127.0.0.1. With -U USER:PASS, robots.txt arrives with status 200 and 910 bytes. The proxy logs CONNECT hproxy.com:443 with the login header. Through socks5h the PNG arrives whole, and the proxy receives the name hproxy.com. Without a login, curl prints curl: (56) CONNECT tunnel failed, response 407, and no file is created.
Our own run on our server, 10 October 2026, 19:27 UTC: curl 8.5.0 and gpg 2.4.4 on Ubuntu 24.04, and a stub proxy we wrote, listening on 127.0.0.1 with the login USER:PASS.

How do you resume a broken download?

Add -C - to the same command. The dash tells curl to read the size of the partial file and ask the server for the rest.

curl -C - -o part.png https://hproxy.com/blog/_assets/img/amazon-price-tracker-check-output.png

In our run, a download cut after 3 seconds stopped at 89,337 of 165,028 bytes, with exit 28. The resume printed ** Resuming transfer from byte position 89337 and fetched the other 75,691 bytes. sha256sum gave the same hash for the resumed file and for a straight download.

Running -C - on a file that is already complete does no harm. curl reported byte position 165,028, transferred nothing and exited 0.

Resuming needs the server's help. RFC 9110 lets a server ignore a Range request, and curl's manual notes that many servers then send the whole file. Our server announces accept-ranges: bytes for the test file, so it resumed.

Does --retry resume a broken download?

That depends on your curl version. Several guides pair -C - with --retry as if it always resumes. We cut the same download every 3 seconds and let --retry 3 try again:

curl versionWhat we ranWhat happened
8.5.0, Ubuntu 24.04--retry 3Four attempts, each from byte 0; exit 28; 80,158 bytes kept
8.5.0, Ubuntu 24.04--retry 3 -C -Four attempts, each from byte 0; exit 28; 53,212 bytes kept
8.21.0, Windows 11--retry 3 -C -The second attempt asked for the last 95,050 bytes; exit 0; whole file, same hash

curl's changelog explains the difference. Version 8.17.0, released on 5 November 2025, made curl keep a failed partial download for retry auto-resume. Ubuntu 24.04 ships 8.5.0, so its retries start over.

On an older curl, a shell loop does the same job, because each new run of curl -C - continues from the partial file. We added --limit-rate 20k -m 3 to cut each run after 3 seconds:

until curl --no-progress-meter --limit-rate 20k -m 3 -C - -o loop.png https://hproxy.com/blog/_assets/img/amazon-price-tracker-check-output.png; do sleep 1; done

On curl 8.5.0, the loop resumed at byte 86,477, finished on its third run and produced the right hash.

Two of our terminal captures from 10 October 2026, one above the other. Above, curl 8.5.0 on Ubuntu 24.04. With --retry 3, four attempts each count from zero out of 165028 bytes, and the command ends with exit 28. That happens both without and with -C -, and ls shows 80158 and 53212 bytes. An until loop with curl -C - resumes from 86477 bytes, and sha256sum matches the full file. Below, curl.exe 8.21.0 on Windows 11. With --retry 3 -C -, the first attempt times out at 69978 bytes. The second reports 70533 out of 95050 bytes, so it resumed. The command exits 0, and the file has 165028 bytes with the same SHA-256.
Our own runs, 10 October 2026: above, curl 8.5.0 on our Ubuntu 24.04 server at 19:23 UTC; below, the curl.exe 8.21.0 that Windows 11 ships, on our workstation at 19:24 UTC. Same 165,028-byte file, each attempt cut after 3 seconds.

More retry rules from the manual: --retry is off by default. It covers timeouts and the HTTP codes 408, 429, 500, 502, 503 and 504, as the manual of curl 8.5.0 lists them; the current manual adds 522 and 524. curl waits 1 second, then doubles the wait up to 10 minutes, and --retry-delay sets a fixed wait instead. --retry-all-errors retries any error, and the manual calls it the sledgehammer of retrying.

How do you limit the download speed?

--limit-rate caps the speed in bytes per second, with k and M counted in steps of 1,024. The cap is an average over several seconds, so a short download can beat it. Our 20k cap allowed 26,847 and 29,429 bytes per second in two downloads cut at 3 seconds. --max-filesize refuses a file above a size you set, with exit 63.

How do you download a file through a proxy?

A download takes a proxy like any other curl request: -x for the proxy and -U for its login.

curl -x http://premium.hproxy.com:10000 -U USER:PASS -O https://example.com/file.zip

We tested this against a stub proxy on our server that asked for the login USER:PASS. The lower half of the capture above shows the run:

What we ranResultWhat the proxy saw
-x http://127.0.0.1:18081 -U USER:PASS -O on robots.txtStatus 200, 910 bytes savedCONNECT hproxy.com:443 with the login header
-x socks5h://USER:PASS@127.0.0.1:11081 on the PNGStatus 200, 165,028 bytes savedThe name hproxy.com, looked up by the proxy
-x http://127.0.0.1:18081 -O on llms.txt, no loginExit 56, CONNECT tunnel failed, response 407The request, refused; no file was created

A refused proxy leaves no file behind, unlike an error page from the site itself. How to use proxies with curl covers the proxy schemes and environment variables. The cURL proxy error guide decodes the exit codes. Some downloads must come from another country. For those, our residential proxies take the same -x and -U flags, with the host, port and login from your dashboard.

How do you download a file on Windows?

Windows 10 and 11 include curl.exe, and the options on this page work the same in it. In PowerShell, three details matter:

  • In Windows PowerShell 5.1, type curl.exe, because curl alone runs Invoke-WebRequest. What is cURL? shows the errors that follow.
  • Write -o nul where Linux uses -o /dev/null.
  • Save with -o, never with >.

We downloaded our PNG three ways on Windows 11, with the curl.exe it ships:

How we saved itBytesFirst bytesSame as the original?
curl.exe -o ok.png URL165,02889 50 4e 47Yes
curl.exe URL > ps51.png in Windows PowerShell 5.1313,602ff fe fd ffNo, the image is broken
curl.exe URL > ps7.png in PowerShell 7.6.6165,02889 50 4e 47Yes

Windows PowerShell 5.1 sends > through Out-File, which writes UTF-16 text by default, so a binary file comes out broken. PowerShell 7.4 changed redirection to keep the bytes of programs like curl. -o works the same in every shell.

What goes wrong most often?

What you seeWhyWhat to do
The file holds 301 Moved Permanentlycurl saved the redirect pageAdd -L
The file is an HTML error page, and the exit code is 0curl saved the error pageAdd -f
curl: (23) Failed writing received data to disk/application with -OThe URL ends in a slash, on curl older than 8.10.0Name the file with -o
The file is called redirect-to-O took the name of the first URLUse -o, or -OJ on curl 8.19.0 or newer
--retry starts again from zerocurl older than 8.17.0Loop curl -C - until it exits 0
A broken image or archive after > in PowerShell 5.1Out-File wrote UTF-16 textSave with -o
curl: (56) CONNECT tunnel failed, response 407The proxy wants a loginAdd -U
curl: (28) Operation timed out-m ran out, or the network is slowRaise -m, then resume with -C -

What this page could not check

We ran two curl builds: 8.5.0 on Ubuntu 24.04 and 8.21.0 on Windows 11. macOS and other Linux distributions were not run. We cut downloads with --max-time instead of a real network drop. Resuming was tested on our own server, which honours ranges, and a server that ignores Range was not tested. The signature check rests on the key that curl's site links, and gpg cannot make that call for you. The proxy runs used a stub on our server, not a commercial network. Microsoft's redirection page for PowerShell 5.1 says it writes UTF-8, but its Out-File page and our test both point to UTF-16. curl releases about every eight weeks, so we will check the version notes on this page again by 10 January 2027.

Sources

  • curl manual for download options (the man page of version 8.23.0), read 10 October 2026: curl.se/docs/manpage.html.
  • curl project, changelog, with 8.17.0 of 5 November 2025, read 10 October 2026: curl.se/changes.html.
  • curl project, download page and verify page, read 10 October 2026: curl.se/docs/verify.html.
  • RFC 9110, HTTP Semantics, June 2022, for range requests, 301 and 416: rfc-editor.org/rfc/rfc9110.
  • RFC 6266, Content-Disposition in HTTP, June 2011: rfc-editor.org/rfc/rfc6266.
  • GnuPG manual, Operational GPG Commands, read 10 October 2026: gnupg.org.
  • Microsoft Learn, Out-File and about_Redirection (PowerShell 5.1), updated in July and September 2023: learn.microsoft.com.
  • Microsoft Learn, What's New in PowerShell 7.4, updated 8 September 2026: learn.microsoft.com.
  • Microsoft Learn, Get-FileHash, updated 12 December 2022: learn.microsoft.com.
  • Our own downloads of 10 October 2026, with curl 8.5.0 on Ubuntu 24.04 and curl.exe 8.21.0 on Windows 11. They fetched from our own site, httpbin.org and curl.se, partly through a stub proxy we wrote. Every transcript, capture and script sits in this page's research folder.

Frequently asked questions

How do I download a file with curl?
Use -O to keep the file name from the URL, or -o and a name of your own, for example curl -L -f -O https://example.com/file.zip. -L follows redirects, and -f stops curl from saving an error page as your file. In Windows PowerShell 5.1, type curl.exe.
What is the difference between curl -o and -O?
-o (lower case) saves the download under the name you write after it. -O (upper case) takes the name from the last part of the URL, without the query string, and overwrites a file of that name. Use one -o or -O per URL.
How do I resume a download with curl?
Run the same command again with -C - added, for example curl -C - -o file.zip URL. curl reads the size of the partial file and asks the server for the rest. In our test it resumed at byte 89,337, and the result matched a full download. The server has to support ranges.
Does curl --retry resume a broken download?
Only in curl 8.17.0 and newer, and only with -C - added. In curl 8.5.0, the version Ubuntu 24.04 ships, every retry started from zero in our test. On an older curl, run curl -C - in a loop until it exits 0.
How do I keep the file name the server sends?
Add -J to -O: curl -OJ URL. curl then uses the filename from the Content-Disposition header. It does not overwrite an existing file of that name. Since curl 8.19.0, -OJ also falls back to the name of the file a redirect points to.
Why is the file I downloaded with curl an HTML page?
Either the server redirected you and curl saved the redirect page, so add -L, or the server sent an error page, which curl saves with exit code 0, so add -f. With -f, curl exits with code 22 and writes no file.
How do I download a file through a proxy with curl?
Add -x with the proxy address and -U with its login, for example curl -x http://premium.hproxy.com:10000 -U USER:PASS -O URL. For a SOCKS5 proxy, write socks5h:// so the proxy looks up the name. A refused login ends with exit 56 and no file.

Get proxies that are alive right now

Our free proxy list re-checks every exit every few minutes across 100+ countries, with a live last-checked time, so you copy IPs that worked moments ago, not a stale text dump. When the location has to survive a real check, the paid network holds up.

129M+ proxy checks run · 100+ countries · HTTP / HTTPS / SOCKS · re-checked every few minutes · no signup

HProxy.

Honest guides and comparisons on proxies, scraping and staying unblocked, from the team that runs the network.

RSS feed