TROUBLESHOOTING

Why your HTML file downloads instead of opening

Your page is uploaded and the link works, but visitors get a download prompt or a wall of source code. One HTTP header decides this, and here is how to check it.

4 min read·

The file is online. The link resolves. And yet clicking it either saves a file to someone’s Downloads folder or fills the screen with your own markup. Nothing is broken — the browser is doing exactly what it was told.

A browser does not decide how to treat a URL by looking at the extension. It reads the Content-Type header the server sends. Get that wrong and a perfectly good page becomes a download, no matter what the file is called.

The two headers that decide it

Content-Type is the important one. text/html means render this as a page. text/plain means show it as text, which is how you end up looking at your own source. application/octet-stream means treat it as an unknown binary, which triggers a download.

Content-Disposition is the override. If a server sends Content-Disposition: attachment, the browser downloads the file even when the Content-Type is text/html. Storage services often set this deliberately, because their job is delivering files rather than serving sites.

There is a third piece worth knowing about: X-Content-Type-Options: nosniff. Without it, browsers used to guess at the real type and would sometimes rescue a mislabelled page. With it — and it is now near-universal, for good security reasons — the declared type is final. Guessing was a security hole, so the escape hatch you might be hoping for is deliberately closed.

Why it happens on the hosts people reach for

GitHub raw URLs are the most common surprise, and it is easy to confirm. Request any .html file from raw.githubusercontent.com and the response comes back as text/plain; charset=utf-8 with nosniff set, so it will show you source code and can never render. That is intentional: serving arbitrary user HTML as a live page from a shared domain would be a security problem. GitHub Pages, which is built for hosting, sends text/html correctly.

Cloud storage has the same shape of problem. Buckets frequently store files with a generic content type, and share links are often built to download rather than display. Drive and Dropbox go further and present your page inside their own viewer, which is why neither serves an HTML file as a website.

And if the address starts with file:// there is no server and no header at all, which is a separate failure worth understanding if you have been emailing the file around.

How to check in ten seconds

Do not guess from what you see on screen — ask the server what it is claiming. One command tells you:

curl -sI https://your-link | grep -i "content-type\|content-disposition"

If Content-Type is anything other than text/html, that is your answer, and no change to the file itself will fix it. Either the host needs configuring, or the host is the wrong tool.

Fixing it

  • On a static host you control → set the content type for .html to text/html and remove any attachment disposition.
  • On GitHub → use Pages rather than a raw URL. Raw will never render, by design.
  • On cloud storage → possible on some services by editing object metadata, but you are fighting the tool’s purpose.
  • On FileShare Pro → nothing to do. HTML is served as text/html; charset=utf-8 with nosniff, so it renders as a page and always has.

Frequently asked

Why does my HTML file download instead of opening in the browser?

Because the server is sending a Content-Type other than text/html — commonly application/octet-stream — or a Content-Disposition: attachment header. Browsers follow the header, not the file extension, so renaming the file changes nothing.

Why does GitHub raw show my HTML as plain text?

raw.githubusercontent.com serves .html files as text/plain; charset=utf-8 with X-Content-Type-Options: nosniff, so the browser is forbidden from treating it as a page. It is deliberate — rendering arbitrary user HTML from a shared domain would be a security risk. Use GitHub Pages instead.

Can I force the browser to render it anyway?

No. nosniff explicitly stops browsers from second-guessing a declared content type, and it is sent by most hosts precisely to close that hole. The fix has to happen on the server.

How do I check what my host is actually sending?

Run curl -sI against the URL and read the content-type and content-disposition lines. That shows what the browser is being told, which is usually different from what people assume.

Got a page to share?

Drop the file, copy the link — live in seconds, free plan included.

Start sharing free