Docs
Everything you need to host a site on fuush.
Getting started
- Sign in at app.fuu.sh with your email.
- Create a site — pick a name, get
your-name.fuu.sh. - Zip your built site (the directory containing
index.html) and upload it.
Single-page apps (React, Vue, etc.)
By default we serve static files as-is: a request to /about looks for about or about/index.html on disk. If neither exists, we 404.
React Router, Vue Router, and other client-routed apps need the server to fall back to index.html for any unknown path. Turn on SPA mode on your site page and we’ll do that.
- Existing files are still served as-is (your CSS, JS, images, fonts).
- Requests with no matching file are rewritten to
/index.html.
GitHub sync Preview — coming soon
Available to invited accounts while we shake out edge cases. Ask for access.
Mirror a GitHub repo branch into your fuush site. Every push deploys.
- On your site’s dashboard, open GitHub and paste the
owner/repo(or the full GitHub URL), the branch (defaultmain), and optionally a sub-directory to deploy (e.g.public,dist). - For private repos, paste a fine-grained personal access token with Contents: Read on the repo.
- We’ll give you a Payload URL + Secret. On GitHub, open Settings → Webhooks → Add webhook, paste both, set Content-Type to
application/json, leave it on the push event, and save. - Done. Every push to the configured branch triggers a sync. You can also click Sync now in the dashboard at any time.
What gets deployed: exactly the files in the repo (or the configured sub-directory). No build step. If your site needs a build (Vite, Next, Hugo), commit the built output to a branch and point fuush at that branch.
Limits: 150 MB compressed tarball, 100 MB uncompressed (same cap as a manual upload). Symlinks are stripped. Each sync produces one new release that you can roll back from Deploy history.
File browser & inline editor Preview — coming soon
Available to invited accounts while we shake out edge cases. Ask for access.
Skip the re-zip cycle for small changes. Every site has a built-in file browser at Files on its dashboard page. From there you can:
- Drop files directly into a folder — one upload, one new release.
- Edit text files (HTML, CSS, JS, JSON, Markdown,
_redirects,_headers…) inline. - Delete files or whole directories.
- Download any file from the current release as a one-liner link.
Each action creates a new release, so you can roll back from Deploy history just like a zip upload. The editor caps at 1 MB per file — anything bigger is download-only.
Web forms
Collect form submissions on a static site without standing up a backend. Each site has its own endpoint:
POST https://api.fuu.sh/f/<site_id>/<form_name>
<form_name> is anything matching [a-z0-9][a-z0-9_-]{0,63} — pick one per form. Find your site’s ID and the full URL on the site’s Forms page in the dashboard.
Minimal HTML
<form method="POST" action="https://api.fuu.sh/f/<site_id>/contact"> <!-- Hidden honeypot. Bots fill it; the submission is silently dropped. --> <input type="text" name="_fuush_hp" tabindex="-1" autocomplete="off" style="display:none"> <input type="hidden" name="next" value="https://yoursite.fuu.sh/thanks.html"> <label>Email <input type="email" name="email" required></label> <label>Message <textarea name="message" required></textarea></label> <button type="submit">Send</button> </form>
- Spam controls: honeypot field (
_fuush_hp), 5 submissions/minute/IP, plus a per-site daily cap (default 200). - Email notifications: optional, opt-in per site, capped at 30/hour/site so a runaway form can’t flood your inbox.
- JSON mode: set
Accept: application/jsonand POST JSON; you get{"ok": true}back instead of a redirect. - Thank-you redirect: pass
next=<url>as a hidden field. Without it we redirect back to theRefererwith?fuush_form=ok. - Export: download submissions as CSV from the dashboard.
Custom 404 page
Drop a 404.html into your zip and turn on Custom 404 page in your site’s advanced options. Any path that doesn’t match a file is served from /404.html with HTTP 404.
- Has no effect while SPA mode is on — in SPA mode the client router decides what’s a 404.
- Safe to enable without a
404.htmlin the zip; visitors just get the default 404.
Redirects and custom headers
Two optional files in your zip control routing and HTTP headers.
_redirects
One rule per line: from to [status]. Status defaults to 302; 200 means a rewrite (serve the destination without changing the URL bar). Splat patterns (/*) capture a tail you can substitute with :splat.
/old-page /new-page 301 /blog/* /journal/:splat 301 /api/* https://api.example.com/:splat 200
Up to 500 rules per site. Lines starting with # are comments.
_headers
Path patterns followed by header lines (indented). /assets/* matches anything under /assets/.
/* X-Frame-Options: DENY Referrer-Policy: same-origin /assets/* Cache-Control: public, max-age=31536000, immutable
Up to 200 rules per site.
Command-line tool
The fuush CLI deploys a directory in one command and is the recommended way to wire fuush into CI.
Install
If you have Go:
go install fuu.sh/fuush/cmd/fuush@latest
Or grab a pre-built binary from github.com/baramustafa/fuush/releases (linux/macOS, x86_64 + arm64).
Use
fuush login # paste a token from app.fuu.sh/tokens fuush whoami # confirm the token works fuush sites # list your sites fuush deploy your-slug ./dist fuush deploy your-slug # current directory
The CLI zips the directory locally (skipping .git, node_modules, .env, .DS_Store), then POSTs through api.fuu.sh. Auth precedence: FUUSH_TOKEN env var wins (use this in CI); otherwise ~/.config/fuush/token from fuush login.
GitHub Actions
Save your token as a repo secret (FUUSH_TOKEN), then drop this into .github/workflows/deploy.yml:
name: Deploy to fuush
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with: { go-version: '1.23' }
- run: go install fuu.sh/fuush/cmd/fuush@latest
- run: fuush deploy your-slug ./public # ← change to your site slug + build dir
env:
FUUSH_TOKEN: ${{ secrets.FUUSH_TOKEN }}
Or — if your build outputs static files already — skip the CLI and use the GitHub sync webhook flow instead. The CLI is the right answer when you need a build step (Vite, Next export, Hugo, mdBook, etc.) before the upload.
Raw HTTP API
Underneath the CLI, every endpoint is a plain HTTP call. Generate an API token at app.fuu.sh/tokens.
GET https://api.fuu.sh/v1/whoami # { user_id, email }
GET https://api.fuu.sh/v1/sites # { sites: [{slug, url, size_bytes, ...}] }
POST https://api.fuu.sh/v1/sites/<slug>/deploy # multipart/form-data, field "file"
Deploy example:
curl -X POST \
-H "Authorization: Bearer fuu_..." \
-F file=@./dist.zip \
https://api.fuu.sh/v1/sites/your-slug/deploy
Response on success:
{
"site_id": "...",
"release_id": "...",
"site_url": "https://your-slug.fuu.sh",
"size_bytes": 1234567
}
Common error codes: missing_token, invalid_token, forbidden, not_found, too_large, rate_limited, zip_slip, zip_bomb, banned_extension, zip_empty.
Deploying from Claude / Cursor / any MCP client
fuush ships a Model Context Protocol server at https://api.fuu.sh/mcp so LLM agents can list, create, deploy, and configure sites as native tools. Authenticates with the same API tokens as the curl flow above.
Claude Desktop
Add to ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or the Windows equivalent:
{
"mcpServers": {
"fuush": {
"url": "https://api.fuu.sh/mcp",
"headers": { "Authorization": "Bearer fuu_..." }
}
}
}
Available tools
list_sites— every site on your account, with URL, size, and custom domains.get_site— full detail for one slug (releases, domains, SPA flag).create_site— new empty site; pick a slug or get a random one.deploy_zip— upload a base64-encoded zip and make it live.list_releases— deploy history for a site.set_spa_mode— toggle SPA fallback on or off.set_description— per-site label shown on the dashboard.add_custom_domain— attach a hostname; returns the TXT challenge.delete_site— irreversible (requires confirm = slug).
All MCP requests are rate-limited the same way as /v1. Deployments inherit the 100 MB hard cap and the 10-uploads-per-hour cap. Rolling back from MCP is intentionally disabled for now — use the deploy-history page in the web dashboard until the server-side Spaces copy is wired into the MCP path.
Custom domains
From your site page, add a domain (e.g. www.example.com). We’ll show you a TXT record to publish at _fuush-challenge.www.example.com; this proves you own the domain.
Once verified, add a CNAME: www.example.com → your-slug.fuu.sh. The first HTTPS hit issues a Let’s Encrypt cert automatically (5–10 seconds the first time).
Forgot which email you used?
Visit app.fuu.sh/recover and type in any subdomain or custom domain you own. We’ll send a sign-in link to the email that controls it.
Limits
- 100 MB per site (both compressed zip and uncompressed total).
- 25 sites per account.
- 10 uploads per hour per account.
- Banned file extensions:
.php .exe .sh .bat .cgi .py .rb .pl .jsp .asp .aspxand similar executables.