Skip to main content
← All guides

Fix Vite “Blocked request. This host is not allowed”

Content updated October 24, 2026.

Why does Vite say “Blocked request. This host is not allowed” when I open my app through a tunnel?

Vite blocks unknown Host headers with “Blocked request”. Add the tunnel hostname to server.allowedHosts: .qurl.site for qURL™, your exact ngrok dev domain, or .trycloudflare.com for Cloudflare. Restart Vite if it does not reload the config; never set allowedHosts to true. With qURL one .qurl.site entry covers every link, and the app stays off the public internet with no public URL; if you later need one permanent public hostname, ngrok’s dev domain fits.

What you need

  • A Vite dev server (or vite preview) opened through a tunnel or proxy
  • Your vite.config.js or vite.config.ts

Steps

  1. Read the host from the error

    The page names the host Vite refused: “Blocked request. This host (“abc.trycloudflare.com”) is not allowed. To allow this host, add “abc.trycloudflare.com” to server.allowedHosts in vite.config.js.” If it says preview.allowedHosts, vite preview answered rather than the dev server.

  2. qURL: allow .qurl.site

    A qURL link opens the app on a new subdomain of qurl.site, so add the domain with a leading dot: it allows qurl.site and every subdomain under it. Allow only the tool you use, and never a top-level domain such as .com. Your app stays on this computer; nothing listens on your network. If localhost resolves only to IPv6, publish the quoted http://[::1]:PORT address, or start the dev server with --host 127.0.0.1 and publish that address.

    // vite.config.js (merge into your existing config)
    export default {
      server: {
        allowedHosts: ['.qurl.site'],
      },
    }
  3. ngrok: allow your dev domain

    ngrok assigns each account one dev domain on ngrok-free.app or ngrok-free.dev, and it stays the same between runs, so allow that exact hostname. Copy it from the Forwarding line ngrok prints, or from the Vite error.

    // vite.config.js (merge into your existing config)
    export default {
      server: {
        allowedHosts: ['your-domain.ngrok-free.app'],
      },
    }
  4. Cloudflare Quick Tunnel: allow .trycloudflare.com

    A Cloudflare Quick Tunnel gets a new random trycloudflare.com hostname each time cloudflared starts, so allow the domain with a leading dot rather than one hostname.

    // vite.config.js (merge into your existing config)
    export default {
      server: {
        allowedHosts: ['.trycloudflare.com'],
      },
    }
  5. Restart Vite

    Vite restarts itself when a config file it loaded changes. Restart it yourself if you just created the file, then reload the page through the tunnel.

  6. For vite preview, nothing extra

    preview.allowedHosts defaults to server.allowedHosts, so one entry covers both. Set preview.allowedHosts only to give the preview server a different list; Vite 6.0.11 fixed a bug that ignored specific values there.

What the recipient sees

With the host allowed, the request reaches Vite and the page loads through the link. If the page loads but hot reload never connects, the tunnel is not carrying the WebSocket: see the hot reload guide. To send the running app to a client through qURL from here, the client review guide covers publishing, the link and ending access.

Which tool should carry your Vite dev server?

OptionChoose it whenTrade-off
qURLqURL fits when particular people should open your Vite app: one .qurl.site entry covers every link, including hot reload, and the app stays on your machine with no public URL.Each qURL link opens once, so run qurl share for each viewer, and keep Vite and your computer running.
ngrokngrok fits when you want one stable URL: your account’s ngrok dev domain stays the same between runs, so one exact allowedHosts entry lasts.ngrok needs an account and authtoken, the URL is public, and free-plan browser visitors see a warning page before Vite answers.
Cloudflare Quick TunnelsA Cloudflare Quick Tunnel fits a quick public look with no account; allow .trycloudflare.com once, because the hostname changes every run.A Cloudflare Quick Tunnel URL is public unless you set --allowed-mail, and Quick Tunnels do not support Server-Sent Events.
Tailscale FunnelTailscale Funnel fits when the machine is already on a tailnet: its ts.net name is stable, so one exact allowedHosts entry lasts.Tailscale Funnel makes the Vite server public to anyone on the internet, with no access control on Funnel traffic.

Troubleshooting

If you seeDo this
qurl publish says the local app is not accepting TCP connectionsStart the app first and check that curl works on the same address. qurl publish connects to localhost as 127.0.0.1, so if your app listens only on IPv6 (on macOS or Linux, lsof -iTCP -sTCP:LISTEN -nP shows [::1]), publish 'http://[::1]:PORT' instead, or start the dev server with --host 127.0.0.1 and publish that address. Neither requires listening on your LAN. Keep the quotes: zsh treats the brackets as a pattern.
The recipient sees “Access link invalid”The link was already used or has expired. Run qurl share again and send the new link.
The recipient sees “Resource not found”The resource was deleted after the link was made. Publish the app again, then run qurl share and send the new link.
publish rejects http://127.0.0.1 with “only HTTPS URLs are allowed”, or asks you to log inYou have a CLI older than 3.0. On macOS run brew update, then brew upgrade qurl; elsewhere install the latest release again. After updating, qurl --version should print 3.4.1 or later.
publish prints no Access: line, or the Access: line says public and you did not ask for publicWith no Access: line, the CLI is older than 3.4.1: on macOS run brew update, then brew upgrade qurl; elsewhere install the latest release again. A resource that an older CLI published is public unless you published it with --private, and anyone who has the CRID of a public resource can open it. To make a public resource private, run qurl delete <CRID> and publish again with qurl 3.4.1 or later. The new resource is private and has a new CRID.
publish says this Linux session “can’t reach a systemd user manager”You are in a container or sandbox without a user service manager. Run qurl publish with --foreground; sharing lasts as long as that process runs.
publish says “Quota Exceeded” with “protected resource limit reached”, or “Your qURL account has reached a plan limit”You can see this without an account: a device with no account can keep up to 3 active resources, with links that last up to 24 hours. Run qurl list --status active, then qurl delete <CRID> for any you no longer need (it asks you to confirm; --yes skips that). qurl stop keeps the resource, so it does not free a slot.
Still blocked after editing the configVite did not reload the file. Restart it, and check you edited the config it actually loads (vite.config.ts and vite.config.js can both exist).
The error names preview.allowedHostsYou are running vite preview. Add the domain to server.allowedHosts, which preview inherits, or set preview.allowedHosts on Vite 6.0.11 or later.
The page loads but edits don’t appear without a refreshThe hot reload WebSocket is not getting through. See the guide to hot reload through a tunnel.

Frequently Asked Questions

Does this fix work on Vite 8?

Yes. In Vite 8, use server.allowedHosts for the dev server; vite preview inherits the same list. Add .qurl.site to load and hot-reload the app through a qURL link.

Can I set allowedHosts to true?

You can, but Vite’s docs warn against it: true allows any website to send requests to your dev server through DNS rebinding attacks and download your source code and content. Use an explicit list of the domains you need.

Why did this start happening?

Vite 6.0.9, 5.4.12 and 4.5.6 added the host check to fix a DNS rebinding vulnerability (GHSA-vg6x-rcgg-rjx6). By default Vite allows localhost, subdomains of .localhost, and IP addresses; any other hostname, including a tunnel’s, must be listed.

Which domain do I add for qURL?

.qurl.site. A qURL link opens the app at an address like https://r_….qurl.site/, and the leading dot covers every subdomain. Your app stays on this computer; nothing listens on your network. If localhost resolves only to IPv6, publish the quoted http://[::1]:PORT address, or start the dev server with --host 127.0.0.1 and publish that address.

Who else can reach my app while the link is open?

Opening the link admits the network address it was opened from for the session, which lasts 1 hour by default. Other devices that share that public IP address, such as people on the same office or café network or VPN, can reach the app until the session ends. By default a link admits whoever opens it; access rules set through the API, such as IP allow and deny lists, can restrict that. Keep your app’s own sign-in for anything sensitive.

Publish your app now

Install the CLI, then run one command. No sign-up, no API key.

Install the CLI ↗

Pilot LayerV

Tell us what to protect, and we’ll scope a pilot.

Enterprise starts with a scoped, paid pilot on one application, typically 60 to 90 days, credited in full toward year one if you convert within 60 days. Then an annual package sized to what you protect. Not per seat.