# Password protect a static HTML page or site for free

Publish the file to chorus.host with a username and password in the same request. Visitors get the browser's login prompt, and the server checks the password before it sends any file. No account or paid plan; links without an account last 24 hours unless you claim them.

## Publish and lock it in one request

```bash
curl -sS https://chorus.host/v1/publish -F file=@report.html \
  -F username=client -F password='choose-a-long-password'
```

The response has the link (`url`), `"passwordProtected": true`, and a `claimUrl` to keep the page past 24 hours. Send the person the link, and the username and password in a separate message.

For a whole folder, zip it and send `-F archive=@site.zip` instead of `-F file=@...`, or repeat `-F file=@...` once per file. Over 4 MB, publish with `curl -fsSL https://chorus.host/publish.py | python3 - ./site` first and then add the password with the call below.

### Already published? Add the password with the claim token

```bash
curl -sS -X PUT "https://chorus.host/v1/sites/$SLUG/password" \
  -H "X-Claim-Token: $TOKEN" -H 'Content-Type: application/json' \
  -d '{"username":"client","password":"choose-a-long-password"}'
# {"success":true}
```

`$SLUG` is the site name (`navy-twig-20` in `https://navy-twig-20.chorus.host`) and `$TOKEN` is the `claimToken` from the publish response. For a site in your account, send `Authorization: Bearer $CHORUS_API_KEY` instead of `X-Claim-Token`.

## Check that the password works

We ran these against chorus.host on 1 October 2026 with a site published a few seconds earlier:

```bash
curl -s -o /dev/null -w '%{http_code}\n' https://navy-twig-20.chorus.host/
# 401
curl -s -o /dev/null -w '%{http_code}\n' -u client:wrong https://navy-twig-20.chorus.host/
# 401
curl -s -o /dev/null -w '%{http_code}\n' -u client:'choose-a-long-password' https://navy-twig-20.chorus.host/
# 200
curl -sI https://navy-twig-20.chorus.host/ | grep -i -E 'www-authenticate|cache-control'
# cache-control: private, no-store
# www-authenticate: Basic realm="navy-twig-20"
```

Every file is behind the prompt, not just the HTML: images, CSV files and scripts in the site get the same 401 without the password.

## Or drop the file here

Drop a file, a folder or a .zip; when the link appears, the password form is already open below it.

<!-- html:dropzone-password -->

## Let your agent do it

```text
Publish report.html to chorus.host behind a password, username client, and tell me the link and the password separately. Instructions: https://chorus.host/skill.md
```

Agents connected to the MCP server (`claude mcp add --transport http chorus https://chorus.host/mcp`) can do it in one tool call: `publish_site` takes a `password` argument, `{"username": "client", "password": "..."}`, and sets it before the site goes live. [MCP setup for other clients](/mcp).

## Change it, remove it, or keep the site

- **Change it:** send the same `PUT` with a new password. It applies to the next request.
- **Remove it:** `curl -sS -X DELETE "https://chorus.host/v1/sites/$SLUG/password" -H "X-Claim-Token: $TOKEN"`.
- **Keep the site:** open the `claimUrl` and sign in with your email. The password stays on the site after it is claimed.
- **Update the page, keep the password:** `curl -sS "https://chorus.host/v1/publish?slug=$SLUG" -H "X-Claim-Token: $TOKEN" -F file=@report.html`. The password stays set.

## Every way to password-protect a static page, compared

Checked 1 October 2026 against each vendor's docs and pricing pages; prices change, so follow the links before relying on them.

| Method | What a password costs | Account needed | Where the password is checked | What it protects | Setup |
|---|---|---|---|---|---|
| chorus.host | $0 | No (the claim token is enough) | On the server, HTTP Basic Auth; the password is stored as a bcrypt hash | Every file in the site | One request |
| [StatiCrypt](https://github.com/robinmoisson/staticrypt) or PageCrypt, plus any host | $0 | Depends on the host | In the browser: the page is encrypted (StatiCrypt: AES-256, 600,000 PBKDF2 iterations) | Only the encrypted HTML; linked images and data files stay public | Encrypt locally, then upload |
| [Cloudflare Access](https://www.cloudflare.com/plans/zero-trust-services/) | $0 on Zero Trust Free, up to 50 users | Yes | On Cloudflare's edge; each person gets an email PIN or signs in with an identity provider, not a shared password | Everything behind the policy | Dashboard setup; the Pages toggle covers preview deployments only |
| [Cloudflare Worker with Basic Auth](https://developers.cloudflare.com/workers/examples/basic-auth/) | $0 within 100,000 requests a day | Yes | On the edge, in code you write | Whatever the Worker serves | Write and deploy the Worker; Cloudflare calls its sample not production-ready |
| [Netlify](https://docs.netlify.com/manage/security/secure-access-to-sites/password-protection/) | Pro plan, $20 a month | Yes | On the server | The site | Site settings |
| [Vercel](https://vercel.com/docs/deployment-protection/methods-to-protect-deployments/password-protection) | Not on Hobby; $20 a month per project on top of Pro | Yes | On the server | The deployment | Project settings |
| [GitHub Pages](https://docs.github.com/en/pages) | Not available; private publishing needs GitHub Enterprise Cloud | Yes | n/a | n/a | n/a |
| [tiiny.host](https://tiiny.host/pricing) | From the Solo plan, $13 a month billed yearly | Yes | On the server | The project | Dashboard |
| [here.now](https://here.now/docs) | $0 on its free account plan | Yes: its docs say anonymous sites can't have a password | On the server | The site | API or dashboard |

### Where the others are better

- **Cloudflare Access** gives each person their own login, so you can see who opened the page and remove one person without changing anyone else's password.
- **here.now and StatiCrypt** show a styled password page instead of the browser's plain prompt. here.now also signs out existing sessions when you change the password.
- **StatiCrypt** means the host never holds a readable copy of the page.
- **Netlify and Vercel** offer team login and SSO on their paid plans.

## Is a JavaScript password prompt enough?

A password checked by JavaScript in the page (`if (input === "secret")`) protects nothing: view-source shows both the check and the content. Encryption tools like StatiCrypt are different: the page really is encrypted and only decrypts with the right password. But the encrypted file is public, so anyone can download it and try passwords offline as fast as their computer allows. StatiCrypt's README asks for passwords of 16 characters or more for that reason, and files the page links to are not encrypted.

A server-side check (chorus.host, Netlify, Vercel, a Worker) never sends the content without the password, and each guess is a network request. HTTP Basic Auth sends the password with every request, so it's only safe over HTTPS. chorus.host only serves sites over HTTPS: a plain `http://` request is redirected first.

## Limits

- One username and password per site. Username 1-128 characters, password 1-72.
- The browser remembers the login until it is closed; there's no log-out button.
- There's no per-person access log.
- Protected responses are sent with `Cache-Control: private, no-store`, so shared caches don't keep a copy.
- Sites without an account last 24 hours, and anonymous publishing is limited to 5 sites an hour per IP address.
- Sites without an account are also sent `X-Robots-Tag: noindex`.

## Questions

### Can I password protect an HTML page for free?

Yes. `curl -sS https://chorus.host/v1/publish -F file=@page.html -F username=client -F password='...'` publishes the page behind a login prompt, free and without an account. The link lasts 24 hours unless you claim it.

### Is a JavaScript password on an HTML page secure?

Not on its own. A password checked in JavaScript can be read from the page source. Client-side encryption (StatiCrypt, PageCrypt) is stronger but can be attacked offline. A server-side check like HTTP Basic Auth over HTTPS never sends the page without the password.

### Does Netlify's or Vercel's free plan include password protection?

No. Netlify's site password needs the Pro plan ($20 a month), and Vercel doesn't offer password protection on Hobby; on Pro it costs $20 a month per protected project. Prices checked 1 October 2026.

### How do I share a password-protected link without creating an account?

Publish to chorus.host with `-F username=... -F password=...` on the same request. You get the link and a claim token; no account is involved. Send the password separately from the link.

### Will Google index a password-protected page?

No. Crawlers get the same 401 response as everyone else, so they never see the content. Sites without an account are also sent `X-Robots-Tag: noindex`.

### Can my AI agent add the password for me?

Yes. Ask it to publish to chorus.host behind a password and point it at https://chorus.host/skill.md, or connect the MCP server at https://chorus.host/mcp, whose `publish_site` tool takes a `password` argument.
