# Serve an HTML File Locally — and Why localhost Isn't a Share

Canonical: https://commareports.com/serve-html-file-locally
Published: 2026-08-28

> `python -m http.server` fixes the blank report in ten seconds. It does not fix sending it to anyone. What a local server does and doesn't solve, the tunnel option, and when to just publish.

# Serving an HTML file locally

This is the right first move when a report renders blank, and the wrong
last move when someone else needs to read it. Both halves matter.

## The commands

From the directory that contains `index.html`:

```bash
python3 -m http.server 8000          # stdlib, nothing to install
npx serve .                          # Node
npx http-server -p 8000              # Node, older and still fine
php -S localhost:8000                # if PHP is what you have
```

Open `http://localhost:8000`. If there's no `index.html` in that
directory you'll get a file listing instead of the report — that's the
server telling you that you're one level too high.

## Why this fixes the blank page

A file opened by double-clicking has a `file://` URL, and browsers give
those an **opaque origin**. Under the same-origin rules that means:

- `fetch()` and `XMLHttpRequest` to a neighbouring file are blocked.
- `<script type="module">` won't load — module fetches follow CORS even
  for local files.

Any report that ships its results as a separate JSON file and loads them
at render time is structurally unopenable that way. Over `http://` the
same requests are same-origin and go through untouched. Longer
diagnostic list in
[why my HTML report lost its CSS](/html-report-broken-css).

## What it does not fix

**Nobody else can open it.** `localhost` is _their_ machine. Sending the
URL sends them to a connection-refused page.

**Your LAN is not the reviewer's LAN.** `python -m http.server` binds
`0.0.0.0` by default, so a colleague at the same office can reach
`http://192.168.x.x:8000` while it's running. Add `--bind 127.0.0.1` if
you'd rather it didn't. Either way it's useless for anyone remote, on a
phone, or reading it tomorrow.

**There's no HTTPS, no auth, and no lifetime.** The stdlib server has no
access control of any kind, and the whole thing ends when you press
Ctrl-C or the laptop sleeps.

## The tunnel option, and its real cost

```bash
cloudflared tunnel --url http://localhost:8000
ngrok http 8000
```

Both hand you a public hostname in a few seconds. Reasonable for a demo
you are actively on a call for. For a report someone opens later:

- The URL dies with the process — and it's a different URL next time.
- Free tiers insert an interstitial page and rotate the hostname.
- Access control is "the hostname is hard to guess", which is not access
  control. Anyone the link reaches, and anything that scrapes it, is in.
- You've published a port on your working machine to the internet for
  the duration.

## When to just publish it

If the answer to "who reads this, and when" is anyone other than you,
right now, the local server has done its job and should be replaced by a
URL. Drag the directory (or a zip of it) into
[Comma](https://commareports.com/):

- `index.html` becomes the report body and the sibling assets upload
  with it — relative references rewritten to the uploaded copies, which
  is the same problem the local server was solving, solved permanently.
- Scripts still run, sandboxed, so the interactive parts stay
  interactive — [interactive HTML reports](/interactive-html-reports).
- Access is per report: private, team, anyone signed in, or link
  holders with view, comment or edit. See
  [sharing & access control](/docs/sharing).
- Comments anchor to the content, so the reply comes back on the report
  rather than in a thread three days later —
  [commenting on HTML](/comment-on-html).

For the CI version of the same move — generate, publish, keep one URL
across runs — see [publishing from CI](/docs/ci).

## Try it

Comma is free — unlimited reports, unlimited commenters, unlimited
revision history.

**[Publish instead of serving →](https://commareports.com/)**

### Related

- [Upload an HTML file and get a link](/upload-html-file-get-link)
- [Where to host a single HTML file](/host-html-file) · [Someone sent me an HTML file](/open-html-file-online)
- [Why the report lost its CSS](/html-report-broken-css)
