Skip to main content
← All guides

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

Content updated October 25, 2026.

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

SvelteKit’s Vite-based dev server blocks unknown hosts. Add the tunnel domain, such as .qurl.site, to server.allowedHosts in vite.config.js; vite preview inherits that list. Form actions work in vite dev, which skips SvelteKit’s CSRF check. With qURL™, share vite dev through single-use links while the app stays on your machine with no public URL. If you later need one permanent public hostname, ngrok’s dev domain fits.

What you need

  • A SvelteKit app running with vite dev, opened through a tunnel or qURL link
  • Your vite.config.js or vite.config.ts

Steps

  1. Read the host from the error

    The page answers 403: “Blocked request. This host ("c-k3j2ab.qurl.site") is not allowed. To allow this host, add "c-k3j2ab.qurl.site" to server.allowedHosts in vite.config.js.” Allow the tool’s domain rather than that one host, so the next link works too.

  2. Add the tool’s domain to server.allowedHosts in vite.config.js

    Put server beside the sveltekit() plugin you already have. A leading dot allows the domain and every subdomain: .qurl.site for qURL, your exact dev domain for ngrok, .trycloudflare.com for a Cloudflare Quick Tunnel. Vite applies the change without a restart.

    // vite.config.js (merge into your existing config)
    export default {
      plugins: [sveltekit(/* your options */)],
      server: { allowedHosts: ['.qurl.site'] },
    }
  3. Share vite dev through qURL

    Restart vite dev with --host 127.0.0.1, then publish that loopback address from a second terminal as shown. Your app stays on this computer; nothing listens on your network. Share the dev server rather than vite preview; see the troubleshooting row on form actions. Each qurl share link opens once and expires within 24 hours.

    qurl publish http://127.0.0.1:5173
    qurl share <CRID>

What the recipient sees

With the domain allowed, the app loads through the link, hot reload connects, and form actions submit.

Which tool should carry your SvelteKit dev server?

OptionChoose it whenTrade-off
qURLqURL fits when particular people should try the app in vite dev: one .qurl.site entry covers every qURL link, and form actions work there.Share vite dev through qURL so form actions work through the link; create a separate link for each person.
ngrokngrok fits when you want one stable URL: your ngrok dev domain stays the same, so one exact allowedHosts entry, and one exact trusted origin, last.ngrok needs an account and authtoken, the URL is public, and free-plan browser visitors see a warning page first.
Cloudflare Quick TunnelsA Cloudflare Quick Tunnel fits a no-account look: .trycloudflare.com covers the hostname that changes every run.A Cloudflare Quick Tunnel URL is public unless you set --allowed-mail, and Quick Tunnels do not support Server-Sent Events.

Troubleshooting

If you seeDo this
Under vite preview or a build, form actions fail with “Cross-site POST form submissions are forbidden”SvelteKit checks a form post’s Origin outside dev, and csrf.trustedOrigins accepts only exact origins, not a pattern such as https://*.qurl.site. Share vite dev for a review: SvelteKit skips the check there.
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.

Frequently Asked Questions

Does SvelteKit check CSRF in vite dev?

No. SvelteKit’s docs say its CSRF checks apply only in production, and vite dev accepts form posts from any origin. vite preview and production builds check the Origin header.

Where does the config go in SvelteKit 3?

In vite.config.js: SvelteKit 3 takes its options inside sveltekit(...) and does not start when a svelte.config.js file exists. server.allowedHosts is a Vite option, so it sits beside the plugin in SvelteKit 2 and 3.

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.