
# Restrict a Website to Specific People with Cloudflare Access

**Cloudflare Access** puts a login wall in front of a site and lets in only the
people on a list you control — free, for up to 50 users. It's not a plugin or
server code: Cloudflare checks who's knocking *before* the request reaches your
site, so it works the same for WordPress, a static site, or a single HTML page —
and an unapproved visitor never even loads it. Nobody shares a password; each
person signs in with their own email, and you add or remove someone in seconds.

> The classic case: gate a **staging site or self-hosted app to a couple of
> collaborators by their email addresses**, and nobody else — not even someone
> who guessed the URL.

What you'll need: a site already served through Cloudflare (easiest is a free
Cloudflare Pages site — see the companion guide, [Host a Free Website with
Cloudflare Pages and GitHub](/cloudflare-pages/)), a free **Cloudflare account**, and the email
addresses you want to let in. About 15 minutes, mostly one-time setup.

## 1. Turn on Zero Trust (one time)

Cloudflare Access lives in **Zero Trust** (sometimes labeled *Cloudflare One*) — a
separate section of the dashboard from DNS and caching. Open it from the sidebar.
First time through, you pick a **team domain** (any name — it becomes
`yourname.cloudflareaccess.com`, your login page's address) and a plan. Pick
**Free**: up to **50 users**, far more than a homelab or small team needs. It may ask for a
card to activate; it isn't charged.

## 2. Add your site as an Access application

An *application* is one site (or one path) you protect. Go to **Access controls →
Applications → Create new application** and choose **Self-hosted and private**,
then give it:

- A **name** (e.g. "Staging" or "Homelab Dashboard").
- The **destination** to protect — your site's hostname (`dashboard.example.com`),
  a whole subdomain, or just a path (`example.com/internal`).

> **Close the back door.** A Cloudflare Pages site also answers at its
> `*.pages.dev` address. Add that hostname as a second destination on the same
> application, or someone can bypass the wall by visiting the pages.dev URL.

Leave the session duration at its default (24 hours) — how long someone stays
signed in before re-authenticating.

## 3. Write the allow-list — the one step that matters

The rule that decides who gets in. On the application, add a **policy**:

- **Action:** Allow
- **Include:** the selector that fits —

| Selector | Admits | Use when |
|---|---|---|
| **Emails** | the **exact addresses** you type | you want *specific people* |
| **Emails ending in** | everyone at a whole domain | it's a company and you want *all* `@company.com` staff |

For "just these people," choose **Emails** and list them: `you@example.com`,
`teammate@example.com`, and so on. Save — the policy is live within seconds.

> **The one trap:** don't use *"Emails ending in"* with `@gmail.com` to admit a
> few Gmail users — that admits **every Gmail account on Earth**. For a named
> list, always use **Emails**.

## 4. How people sign in

By default, Access uses a **one-time PIN** — no setup, works for any email:

1. A visitor opens the site and is asked for their email.
2. Cloudflare emails them a **6-digit code**.
3. They enter it, and Cloudflare checks the address against your allow-list.

The PIN only proves someone controls that inbox; your **allow-list decides who's
actually let in**. A stranger who enters their own Gmail gets a code, enters it,
and is still **denied** — their address isn't on the list.

*(Optional: add a "Sign in with Google" button instead of the emailed code — handy
if everyone's on Google, but it's more setup (a Google OAuth client) and rarely
worth it for a handful of people. The PIN is simplest.)*

## 5. Test it

Open your site in a **private/incognito window** (so you're not already signed
in). You should hit the Cloudflare login page, not your site. Enter an allowed
email, get the code, land on the site. Then try a **non-allowed** email — you
should be denied. That one test confirms both that the wall is up *and* that the
list is doing its job.

## 6. Add or remove people later

It's all under **Access controls → Applications → your app → Policies** (or edit
the reusable policy under **Access controls → Policies**). Edit the **Emails** list
to add or remove someone; it takes effect on their next sign-in. To lock someone
out immediately, remove them and revoke their active session.

---

## It's not just for static sites

Access sits in front of *anything* Cloudflare proxies — a WordPress site, a web
app, even a service running on a computer at home (exposed with a **Cloudflare
Tunnel**). The login wall and allow-list behave identically; all that changes is
how the site got behind Cloudflare in the first place.
