A cross-platform, high-performance and asynchronous web server for static file-serving ⚡
Overview
Note
This is the upcoming v3, currently in development. For production use, see v2 (LTS).
Static Web Server (SWS)
is a small, fast, production-ready web server for static file-serving
that prioritizes simplicity and ease of use while delivering high performance and safety, powered by Rust. Built on Hyper and Tokio to deliver efficient and performant asynchronous I/O and HTTP/1-2 support with a low resource footprint.
SWS is available for a variety of platforms like Linux, macOS, Windows, FreeBSD, NetBSD, Android and Docker.
Wasmer
updates very frequently. If you have installed Wasmer some time ago,
chances are your Wasmer version is out of date. Get the latest version
of Wasmer by running:
wasmer self-update
from https://docs.wasmer.io/install/
--------------
You have an application you want to deploy on Wasmer Edge? You’re in the right place!
Welcome to wasmer deploy. For most languages and frameworks, you can deploy your app from zero, with the following steps:
Install Wasmer
Click here for instructions on how to install Wasmer if you haven’t done it already!
Create an account
You can create an account directly via wasmer login or via the Wasmer website:
wasmer.io/signup
Run wasmer deploy
The wasmer deploy command will make sure that everything is in place for you to deploy your
app: it will guide you through the creation of the app and its deployment if it doesn’t exist,
or redeploy it after it changes.
The deploy command is a one-stop-shop for multiple functionalities needed to
deploy apps on Wasmer Edge. To learn more about the commands available in the
CLI to manage your Wasmer Edge apps, refer to the dedicated CLI
page!
from https://docs.wasmer.io/edge/get-started/
-----
Deploy Git repositories on Wasmer Edge
Wasmer Edge can deploy an app from a connected Git repository. This lets you keep
your source code and deployment configuration in Git while Wasmer handles the
deployment.
Git deployments currently focus on GitHub repositories. If you use another Git
provider, you can still deploy from a local checkout with
wasmer deploy.
How Git deployments work
Connect a repository to a Wasmer Edge app.
Choose the branch that should deploy to production, usually main.
Push changes to that branch when you want to update the app.
App configuration
If an app.yaml file is present in the repository, Wasmer extends the app’s
configuration with the values from that file during deployment.
Production branch
The production branch is the branch Wasmer treats as the source of the live app.
Most projects use main, but you can choose the branch that matches your release
process.
Deploy without Git
You can always deploy from a local checkout:
wasmer deploy
This is useful when you are setting up a project for the first time, testing a
deployment locally, or using a Git provider that is not connected to Wasmer Edge.
from https://docs.wasmer.io/edge/git/
-----
Deploy GitHub repositories with Wasmer
Wasmer for GitHub connects a GitHub repository to Wasmer Edge so changes can be
deployed from GitHub.
Before you start
A Wasmer account
Access to the GitHub repository you want to deploy
A Wasmer Edge app, or permission to create one
Connect a repository
Open your Wasmer Edge app
Go to the Wasmer dashboard and select the app you want to connect to GitHub.
Connect GitHub
Open the app’s Git settings and choose GitHub as the repository provider. If
prompted, authorize Wasmer to access the repository or organization.
Select the repository and branch
Choose the repository that contains your app and select the branch Wasmer should
deploy to production. Most apps use main.
Deploy
Save the connection and deploy the app. Future changes pushed to the selected
branch can be deployed through the Git connection.
App configuration
If an app.yaml file is present in the repository, Wasmer extends the app’s
configuration with the values from that file during deployment.
Pull requests
Use pull requests to review changes before merging them into the production
branch. If your app needs a one-off deployment while a change is still in review,
you can deploy that branch from a local checkout with wasmer deploy.
Troubleshooting
I do not see my repository
Make sure the GitHub account or organization connected to Wasmer has access to
the repository. For organization repositories, an organization owner may need to
approve access.
A deployment did not start
Check that the repository is connected to the right app and that the pushed
branch is the branch configured for deployment. You can still deploy manually
from the repository checkout:
wasmer deploy
from https://docs.wasmer.io/edge/git/wasmer-for-github/
-----
Quickstart guide for a static website
In this quickstart guide, you’ll learn the process of deploying a static site on Wasmer Edge.
We will cover installation of the CLI, setting up a new static site, and deploying it.
If you want to deploy a static site made from frameworks like React, Vue, or
Svelte, you can follow our React Static
Site tutorial.
Deploying a static site
Install Wasmer
Click here for instructions on how to install Wasmer if you haven’t done it already!
Log in into Wasmer
Create a new account in Wasmer .
Then, log in into the Wasmer CLI and follow the provided steps to provide
the CLI access to your Wasmer account.
wasmer login
Deploy!
We begin creating a new empty directory.
mkdir my-new-sitecd my-new-site
Then, running a single command, we can setup a static website.
wasmer deploy --template=static-website
Expect to see output similar to this:
It seems you are trying to create a new app!✔ Who should own this app? · wasmer-user✔ What should be the name of the app? · my-new-site✔ Unpacked template✔ Do you want to deploy the app now? · yesLoading local package (manifest path: ~/wasmer-user/Projects/my-new-site/.)✔ Correctly built package locally✔ Package correctly uploaded✔ Succesfully pushed release to namespace wasmer-user on the registryDeploying app my-new-site (wasmer-user) to Wasmer Edge...App my-new-site (wasmer-user) was successfully deployed 🚀https://my-new-site-wasmer-user.wasmer.app→ Unique URL: https://2dyh6i3cvx1y.id.wasmer.app→ Dashboard: https://wasmer.io/apps/wasmer-user/my-new-siteWaiting for new deployment to become available...(You can safely stop waiting now with CTRL-C)
The above command will do the following:
Download the template from the registry
Store the template locally in your current directory (try running ls -la)
Deploy it to Wasmer Edge
Don’t change the public directory attribute in the wasmer.toml file for this tutorial.
If you want to learn how to specify a different directory for build output, check out our React Static Site tutorial.
Try clicking the URL which is under the deployment message https://my-new-site-wasmer-user.wasmer.app, and expect to see something like:
The deployment URL follows the format https://<app-name>-<app-owner>.wasmer.app
Update the app
To illustrate the lifecycle of an app, let’s edit the index.html file in the public folder:
Your directory structure should look like this:
Lets modify index.html:
sed -i -e 's/Hi from the Edge/This is our new title!/g' public/index.html
Now, let’s redeploy it:
wasmer deploy
When refreshing the browser, expect the page to have been updated:
Add your content
Currently, the public directory only contains a basic index.html file.
You can now modify this directory and copy your own files (HTML, CSS, JavaScript, images, etc) as needed.
Test your site locally
You can also test your site locally before deploying the app on Wasmer Edge by running the following command:
wasmer run .
This will start a local server using the Static Web Server on http://localhost:8080.
You can also specify a different port by passing the --port flag, as in wasmer run . -- --port=<your-port>.
The arguments after -- (double dash) are passed to the underlying server running in the Wasmer runtime.
You can see all the available options with wasmer run --help or click here to see the full documentation.
To see all the avilable options for the static web server, run wasmer run . -- --help.
Conclusion
Congratulations! You have successfully deployed a static site on Wasmer Edge 🚀.
Tip: To make changes to your site, simply modify the files in the public
directory and run wasmer deploy again to deploy the changes.
from https://docs.wasmer.io/edge/guides/static-site/
Since the original Telegraph API interface was closed by
the official, you need to switch the upload channel to Telegram Channel.
Please set TG_Bot_Token and TG_Chat_ID according to the deployment requirements in the documentation, otherwise the upload function will not work properly.
Table of Contents
Quick Start: deploy a working image host in 3 steps
3 simple steps to have your own image hosting. The only
thing you need in advance is a Cloudflare account (to deploy on your own
server without relying on Cloudflare, refer to #46).
Fork this repository (Note: You must deploy using Git or the Wrangler CLI tool for it to work properly, Documentation)
Open the Cloudflare Dashboard, enter the Pages management page, select Create Project, choose Connect to Git provider, follow the prompts to enter the project name, select the repository you just forked, then click Deploy site
After deployment, go to the project's Settings -> Environment Variables, add TG_Bot_Token and TG_Chat_ID (see the next section for how to obtain them), save, then go to the Deployments page and redeploy once
Done! Open your *.pages.dev domain and start uploading. For the dashboard, upload protection, short links, and more, see the Optional Features Guide.
How to Obtain Telegram Bot_Token and Chat_ID
If you don't have a Telegram account yet, please create one first. Then, follow these steps to get the BOT_TOKEN and CHAT_ID:
Get the Bot_Token
In Telegram, send the command /newbot to @BotFather, and follow the prompts to input your bot's name and username. Once successfully created, you will receive a BOT_TOKEN, which is used to interact with the Telegram API.
Set the bot as a channel administrator
Create a new channel (Channel), enter the channel and select channel
settings. Add the bot you just created as a channel administrator, so
it can send messages.
Get the Chat_ID
Get your channel ID through @VersaToolsBot. Send a message to this bot and follow the instructions to receive your CHAT_ID (the ID of your channel).
Or get your channel ID through @GetTheirIDBot. Send a message to this bot and follow the instructions to receive your CHAT_ID (the ID of your channel).
Configuration Reference
All configuration is done in your Cloudflare Pages project's Settings. Note: after changing environment variables or the KV binding, you need to redeploy for the changes to take effect.
Channel ID, ensure the TG Bot is an administrator of the channel or group.
Optional environment variables (enable features as needed, see the Optional Features Guide):
Environment Variable
Example Value
Description
BASIC_USER
admin
Login username for the dashboard (/admin). Leave unset for a dashboard without login.
BASIC_PASS
admin-password
Login password for the dashboard. Must be set together with BASIC_USER.
UPLOAD_BASIC_USER
uploader
Username for protecting the public upload endpoint. Leave unset to keep uploads public.
UPLOAD_BASIC_PASS
strong-password
Password for protecting the public upload endpoint. Must be set together with UPLOAD_BASIC_USER.
ENABLE_SHORT_URLS
true
When enabled (and a KV namespace is bound), uploads return a short link like /file/AbC123 instead of the long file name. Existing long links keep working.
SHORT_URL_LENGTH
6
Length of generated short ids (4-16, default 6). Only used when ENABLE_SHORT_URLS is on.
Bind a pre-created KV namespace to enable the image management dashboard; the short links feature also requires this binding
Features
Unlimited image storage, you can upload an unlimited number of images
No need to purchase a server, hosted on Cloudflare's
network. When usage does not exceed Cloudflare's free quota, it's
completely free
No need to purchase a domain name, you can use the free second-level domain *.pages.dev provided by Cloudflare Pages, and also supports binding custom domain names
Supports image review API, can be enabled as needed. When
enabled, inappropriate images will be automatically blocked and no
longer loaded
Supports backend image management, allowing you to preview
uploaded images online, add to whitelist, blacklist, and other
operations
Supports multiple file types (images, videos, audio, and
more). Previewable files (images/video/audio/PDF) open directly in the
browser instead of being force-downloaded
Optional Basic Auth protection for the upload endpoint and
optional short links, both enabled on demand via environment variables
Optional Features Guide
Image Management Dashboard
Disabled by default. To enable: in the Cloudflare Pages backend, click Settings -> Functions -> KV namespace bindings -> Edit bindings, enter img_url as the Variable name, select a pre-created KV namespace as the KV namespace, redeploy, then visit http(s)://your-domain/admin to open the dashboard
The dashboard supports: total image count, filename
search, paginated loading, online preview, rename, blacklist/whitelist
management, record deletion, and grid/waterfall views. See the Update Log for detailed descriptions and screenshots of each feature.
Note: the dashboard "delete" action only removes the
record from the list; it does not delete the source file from Telegram.
To prevent a file from loading, use the blacklist feature.
Dashboard Login
Disabled by default. To enable, add the following environment variables:
Variable Name
Value
BASIC_USER =
BASIC_PASS =
Of course, you can also choose not to set these two
values, so that accessing the backend management page will not require
verification and will skip the login step directly. This design allows
you to use it in combination with Cloudflare Access to achieve email
verification code login, Microsoft account login, Github account login,
and other functions. It can be integrated with the existing login method
on your domain without having to remember another set of backend
credentials. For adding Cloudflare Access, please refer to the official
documentation. Note that the protected path needs to include /admin and
/api/manage/*
Upload Protection
Uploads are public by default. To protect only the public upload endpoint, set both UPLOAD_BASIC_USER and UPLOAD_BASIC_PASS; the web page and API uploads will then require Basic Auth (see Upload API for API usage). When these two variables are not set, uploads remain public for compatibility with existing deployments.
Short Links
Disabled by default. With a KV namespace bound and ENABLE_SHORT_URLS=true, uploads return short links like /file/AbC123 (length configurable via SHORT_URL_LENGTH, 4-16, default 6), and the dashboard copy buttons prefer the short link. Existing long links are unaffected and keep working.
Open the Cloudflare Pages management page, click Settings, Environment Variables, Add Environment Variables in sequence
Add a variable name as ModerateContentApiKey, value as the API key you just obtained in step 1, then click Save
Note: Since the changes will take effect on the next deployment, you may also need to go to the Deployments page and redeploy the project
After enabling image review, the first image load will be
slow because review takes time. Subsequent image loads will not be
affected due to caching
Whitelist Mode
With the image management feature enabled, set the environment variable WhiteList_Mode to true
and only images added to the whitelist will be loaded. Uploaded images
need to be approved before they can be displayed, which prevents
inappropriate images from loading to the greatest extent
Bind Custom Domain
In the custom domain section of Pages, bind a domain name
that exists in Cloudflare. For domain names hosted in Cloudflare, DNS
records will be automatically modified
Upload API
The upload endpoint is POST /upload using multipart/form-data, with the file in a field named file:
The endpoint works with upload tools that support custom web image hosts, such as PicGo.
Limitations and Free Quotas
Files are uploaded via the Telegram Bot API and stored on
Telegram's servers. Uploads are limited by the Bot API (about 50MB per
file), but the Bot API file download endpoint (getFile) only supports
files up to 20MB, so files larger than 20MB cannot be served back after
upload — treat 20MB as the practical per-file limit
Due to the use of Cloudflare's network, image loading speed may not be guaranteed in some regions
The free version of Cloudflare Function is limited to
100,000 requests per day (i.e., the total number of uploads or image
loads cannot exceed 100,000). If exceeded, you may need to purchase the
paid plan of Cloudflare Function
With the image management feature enabled, Cloudflare KV free quotas also apply:
Cloudflare KV only has a free write quota of 1000 times per day.
Each new image loaded will consume this write quota. If this quota is
exceeded, the image management backend will not be able to record newly
loaded images
Maximum of 100,000 free read operations per day. Each image load
will consume this quota (when there is no cache. If your domain has
cache enabled on Cloudflare, this quota will only be consumed when the
cache misses). If exceeded, blacklist and whitelist features may fail
Maximum of 1,000 free delete operations per day. Each image record
will consume this quota. If exceeded, you will not be able to delete
image records
Maximum of 1,000 free list operations per day. Each time you open or
refresh the backend /admin, it will consume this quota. If exceeded,
backend image management will be affected
In most cases, the free quota is basically sufficient and
can be slightly exceeded. It doesn't stop immediately when exceeded.
Each quota is calculated separately. When a certain operation exceeds
the free quota, only that operation will be suspended and will not
affect other functions. That is, even if my free write quota is used up,
my read and write functions are not affected, images can load normally,
I just can't see new images in the image management backend.
If your free quota is not enough, you can purchase the
paid version of Cloudflare Workers from Cloudflare yourself, starting at
$5 per month, pay-as-you-go, without the above quota limitations
In addition, changes made to environment variables will take effect on the next deployment. If you changed Environment Variables to enable or disable a certain function, remember to redeploy.
How to Update if Already Deployed?
Updating is actually very simple. Just refer to the update
log, first go to the Cloudflare Pages backend, set the required
environment variables in advance and bind the KV namespace, then go to
your previously forked repository on Github and select Sync fork->Update branch.
After a while, Cloudflare Pages will detect that your repository has
been updated and will automatically deploy the latest code
You can also enable automatic syncing: after forking, go
to your repository's Actions page, enable Workflows and the Upstream
Sync Action to sync with upstream hourly (see the July 2024 section of
the Update Log for illustrated instructions).
Local Development and Testing
npm install
npm start # start a local dev server (wrangler pages dev on port 8080; dashboard credentials default to admin/123)
npm test# run the unit tests (mocha)
Thanks
Ideas and code provided by Hostloc @feixiang and @乌拉擦
Update Log
July 19, 2026 - Upload Protection, Short Links, and Preview Update
Added optional Basic Auth protection for the upload endpoint via UPLOAD_BASIC_USER and UPLOAD_BASIC_PASS, thanks to @ytagent and @lelouch0823 (#278/#279)
Added optional short links: enable with ENABLE_SHORT_URLS and configure the length with SHORT_URL_LENGTH; uploads then return links like /file/AbC123 and the dashboard copy buttons prefer the short link, thanks to @wyksean448 (#226/#305)
Previewable files (images, video, audio, PDF) now open directly in the browser instead of being force-downloaded (#279)
Fixed incorrect Content-Type on files stored via the Bot API, which
prevented images from rendering on GitHub and other strict clients,
thanks to @gynamics (#233/#305)
Fixed the broken rename feature in the dashboard, and refactored
core functions with unit test coverage, thanks to @ytagent (#277/#304)
The dashboard "delete" action is now explicitly record-only and does not remove the source file from Telegram (#279)
August 15, 2025 - Dashboard Loading Performance Update
The dashboard file list now loads in pages (KV cursor pagination + load more) instead of fetching all records at once (#253)
Dashboard search now filters by filename prefix on the server (#254)
July 6, 2024 - Backend Management Page Update
Support for two new management page views (Grid view and Waterfall view)
Grid view, thanks to @DJChanahCJD for the submitted code
Supports batch delete/copy links
Supports sorting in reverse chronological order
Supports pagination
Waterfall view, thanks to @panther125 for the submitted code
Added automatic update support
Now forked projects can automatically sync with the
upstream repository to automatically install the latest project
features, thanks to @bian2022
Steps to enable automatic updates:
After you fork the project, due to Github's limitations, you need to
manually go to the Actions page of your forked project to enable
Workflows, and enable Upstream Sync Action. Once enabled, automatic
updates will occur hourly:
If you encounter Upstream Sync execution errors, please manually Sync Fork once!
Manually update code
If you want to manually update immediately, you can check Github's documentation to learn how to sync your forked project with upstream code.
You can star/watch this project or follow the author to receive notifications of new feature updates.
Added remote telemetry
You can opt out of telemetry by adding the disable_telemetry environment variable
January 18, 2023 - Image Management Feature Update
Support for image management feature, disabled by default. To enable, after deployment, go to the backend and click Settings->Functions->KV Namespace Bindings->Edit Bindings->Variable Name enter: img_urlKV Namespace
select the KV storage space you created in advance. After enabling,
visit http(s)://your-domain/admin to open the backend management page
| Variable Name | KV Namespace |
| ----------- | ----------- |
| img_url | Select the KV storage space created in advance |
The backend management page has a new login verification feature,
also disabled by default. To enable, after deployment, go to the backend
and click Settings->Environment Variables->Define variables for production->Edit variables and add the variables shown in the table below to enable login verification
| Variable Name | Value |
| ----------- | ----------- |
|BASIC_USER = | |
|BASIC_PASS = | |
Of course, you can also choose not to set these two
values, so that accessing the backend management page will not require
verification and will skip the login step directly. This design allows
you to use it in combination with Cloudflare Access to achieve email
verification code login, Microsoft account login, Github account login,
and other functions. It can be integrated with the existing login method
on your domain without having to remember another set of backend
credentials. For adding Cloudflare Access, please refer to the official
documentation. Note that the protected path needs to include /admin and
/api/manage/*
You can also protect the public upload endpoint separately by setting both UPLOAD_BASIC_USER and UPLOAD_BASIC_PASS. When these two variables are not set, uploads remain public for compatibility with existing deployments.
Added image total count statistics
When the image management feature is enabled, you can view the number of images in the record at the top of the backend
Added image filename search
When the image management feature is enabled, you can use the image
filename in the backend search box to quickly search and locate the
images you need to manage
Added image status display
When the image management feature is enabled, you can view the current
status of the image in the backend { "ListType": "None", "TimeStamp":
1673984678274 }
ListType indicates whether the image is currently in the blacklist or
whitelist. None means it's neither in the blacklist nor the whitelist,
White means it's in the whitelist, Block means it's in the blacklist.
TimeStamp is the timestamp when the image was first loaded. If image
review API is enabled, the image review result will also be displayed
here, identified by Label
Added blacklist feature
When the image management feature is enabled, you can manually add
images to the blacklist in the backend. Images on the blacklist will not
load properly
Added whitelist feature
When the image management feature is enabled, you can manually add
images to the whitelist in the backend. Images on the whitelist will
always load properly, bypassing the image review API results
Added record deletion feature
When the image management feature is enabled, you can manually delete
image records in the backend. This only removes the item from the
backend list; it does not delete the original file from Telegraph or
Telegram. If the file is uploaded and loaded again later, a record may
be created again. To prevent the file from loading, use the blacklist
feature mentioned in point 6 above.
Added program running mode: Whitelist mode
When the image management feature is enabled, in addition to the default
mode, this update also adds a new running mode. In this mode, only
images added to the whitelist will be loaded. Uploaded images need to be
approved before they can be displayed, which prevents inappropriate
images from loading to the greatest extent. To enable, please set the
environment variable: WhiteList_Mode=="true"
Added backend image preview feature
When the image management feature is enabled, you can preview images
loaded through your domain in the backend. Click on images to zoom in,
zoom out, rotate, and perform other operations。