# CloudFlare-ImgBed: a serverless image host that also speaks Telegram, R2 and WebDAV

> CloudFlare-ImgBed is an MIT-licensed, self-hosted file and image host built for Cloudflare and Docker. It puts Telegram, Discord, R2, S3, Hugging Face and WebDAV behind one upload page and one API, and this review covers what that costs you.

**MarSeventh/CloudFlare-ImgBed** — 🏖️ A serverless, open-source file hosting solution built on Cloudflare. Supports image hosting, secure file storage, and personal cloud drive capabilities.

- Repository: https://github.com/MarSeventh/CloudFlare-ImgBed
- Website: https://cfbed.sanyue.de
- Stars: 6,591 · Forks: 8,410
- Language: JavaScript
- License: MIT
- Published: 2026-09-22 · Updated: 2026-09-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/marseventh-cloudflare-imgbed

## The problem it solves: one upload page over many storage backends

Most people who host images end up with the same mess. A few files sit in an object bucket, older ones live in a chat app, and a folder of screenshots is somewhere on a VPS. Each backend has its own upload flow, its own URL shape and its own way of deleting things. CloudFlare-ImgBed treats that spread as the normal case rather than an edge case. The README describes it as "a self-hosted image and file hosting solution for Docker and serverless environments" that brings Telegram, Discord, Cloudflare R2, S3-compatible storage, Hugging Face and WebDAV "into one management interface". The audience is narrow but real: people who run a personal site or a small asset library and want one place to upload, authenticate, organize into directories, moderate content, and expose the result over a RESTful API or WebDAV. It is not a photo library for a family, and it is not a CDN product. It is the control plane in front of storage you already have.

## How it works: a Worker or a Node server in front of your buckets

The repository has two runtimes. The serverless path runs on Cloudflare: the start script serves the built frontend from frontend-dist through wrangler pages dev, binding a KV namespace named img_url and an R2 bucket named img_r2. The Docker path runs the same application as a Node process. The Dockerfile builds a node:22-slim image, runs npm ci against the @cloudflare-imgbed/common and @cloudflare-imgbed/server workspaces with dev dependencies omitted, then starts deploy/server/index.js through a register hook. The compose file maps host port 7658 to container port 8080 and mounts ./data, so the container's state lives on a host directory rather than inside the image. Around that core sit the pieces that make it more than a bucket wrapper: database/ holds the schema, functions/ holds the Cloudflare Pages functions, and deploy/profiles holds the workspace packages the Docker build installs. The storage backends are adapters behind that application, which is why the same upload page can write to Telegram or to R2 depending on configuration. The practical consequence is that your data is not in one place, and the application is the only thing that knows where each file went.

## Installing CloudFlare-ImgBed with Docker Compose

The repository ships a docker-compose.yml, which is the shortest path to a running instance. It pulls marseventh/cloudflare-imgbed:latest, publishes port 7658 on the host, mounts ./data, and restarts the container unless it is stopped. Create a directory, put this file in it, and run the compose command from that directory.

```yaml
services:
  imgbed:
    image: marseventh/cloudflare-imgbed:latest
    ports:
      - "7658:8080"
    volumes:
      - ./data:/app/data
    restart: unless-stopped
```

Start it with docker compose up -d, then open http://localhost:7658 in a browser. The container listens on 8080 internally; the mapping is what puts it on 7658. Because ./data is bind-mounted, the SQLite-style state and any local files survive a container replacement, which matters when you upgrade by pulling a new tag. The README also points at a hosted demo at cfbed.1314883.xyz with the access password cfbed if you want to see the upload page, file management dashboard and public gallery before installing anything. The README does not document a rollback procedure for a failed upgrade, so keep the ./data directory under whatever backup you already run before you pull a new image.

## The serverless path and the deploy:worker script

Running on Cloudflare instead of Docker uses the wrangler toolchain that is already in devDependencies. The package.json defines a deploy:worker script that first runs node deploy/worker/generate-routes.js and then executes npx wrangler deploy with deploy/worker/wrangler.toml as the config. The generated routes file is the interesting part: the repository keeps routing logic in a script rather than in a hand-maintained config, which is a reasonable choice for a project whose API surface changes between releases, but it also means the deployed routes are a build artifact rather than something you can read and diff in the repository. For local work, npm start serves frontend-dist through wrangler pages dev with the KV and R2 bindings, an IP of 0.0.0.0, port 8080, and persistence directed at ./data. That last flag is what keeps local KV and R2 contents between restarts, and it is the reason the Docker path and the local dev path can share the same ./data directory name without sharing a runtime.

## Where CloudFlare-ImgBed is the wrong tool

The project's own README opens with an important notice telling users to check the announcement discussions first, because "important notifications and non-compatible updates will be explained in the announcement". Read that as a maintenance requirement, not a courtesy. If your instance runs unattended and nobody watches that category, a breaking change in a release will find you before the notice does. The release cadence supports the concern: v2.7.6, v2.7.5 and v2.7.4 arrived roughly a month apart through mid-2026, and the last push to the repository was on 2026-09-11. Multi-backend storage is the second limitation. When one upload page can write to Telegram, Discord, R2, S3, Hugging Face and WebDAV, nothing in the repository layout guarantees a uniform export of everything at once. A backup strategy that only snapshots the R2 bucket will miss files that went to a chat backend. Finally, the frontend-dist directory is checked into the repository, so the served UI is a build artifact; if you want to change the interface you need the toolchain that produced it, and the README does not describe that build step.

## How it differs from a plain Cloudflare R2 bucket or a static host

The obvious alternative is to skip the application and use R2 directly, or to put a static site generator's assets in Cloudflare Pages. Both are simpler and have no upgrade path to maintain. The difference in approach is where the logic lives. With a bare bucket you get an object store and an S3-compatible API; every upload needs your own script, and access control is whatever you build on top of signed URLs. CloudFlare-ImgBed puts authentication, directory organization, content moderation and a WebDAV endpoint in front of the bucket, and then lets you point that same layer at Telegram or Discord instead. That is the trade: you take on a Node or Worker application, a database, and a monthly upgrade habit, and in exchange you get one interface and a choice of backends. If your only requirement is serving images to a website, the bare bucket wins on operational cost. If you have files scattered across three services and want one place to manage them, the application is doing work the bucket cannot.

## Licence, upgrades and the cost of staying current

The project is MIT licensed, which places few restrictions on reuse and redistribution; the LICENSE file is at the repository root. That is a permissive choice and it matters if you intend to modify the frontend or embed the uploader in something else. It does not, however, tell you anything about the operational cost. Upgrades are the real recurring expense here. The Docker image tag in the compose file is latest, which means a restart can change the running version without any deliberate action on your part. Pinning a specific version is the safer pattern, and the release list gives you the tags to pin to. Cloudflare-side deployments have their own versioning through wrangler, and the deploy:worker script regenerates routes on every deploy, so an upgrade can change routing as well as application code. The README points to a version upgrade section in the documentation; that is the page to read before changing anything, and the announcement category is where non-compatible changes are explained. Nothing in the repository describes a migration tool or a downgrade path, so treat the ./data directory as the thing you protect.

## Conclusion

Adopt CloudFlare-ImgBed if you already pay for Cloudflare and want one upload page over several storage backends, or if you run Docker and would rather keep the data on your own volume. Skip it if you need to browse and restore backups from a phone, or if you cannot put a working notification channel in front of the repository's announcement category. Before you commit, read the announcement discussions for the current release, check the upgrade notes for v2.7.6, and decide which single backend will hold the files that actually matter.

## FAQ

### What is CloudFlare-ImgBed used for?

It is a self-hosted image and file hosting solution for Docker and serverless environments, per the README. It provides file management, authentication, directory organization, content moderation, a RESTful API and WebDAV over backends such as Telegram, Discord, R2, S3-compatible storage, Hugging Face and WebDAV.

### How do I install CloudFlare-ImgBed?

The repository includes a docker-compose.yml that pulls marseventh/cloudflare-imgbed:latest, maps host port 7658 to container port 8080 and mounts ./data. For Cloudflare deployments, package.json defines a deploy:worker script that generates routes and runs wrangler deploy with deploy/worker/wrangler.toml.

### Does CloudFlare-ImgBed store images itself?

No. The application is the management layer; the files live in whichever backend you configure, such as Cloudflare R2, an S3-compatible service, Telegram, Discord, Hugging Face or WebDAV. The Docker image mounts ./data for its own state, which is not the same as your file storage.

### Can I run CloudFlare-ImgBed without Docker?

Yes. The package.json start script runs the built frontend through wrangler pages dev with the img_url KV namespace and img_r2 R2 bucket bindings on port 8080. The deploy:worker script deploys the Worker variant to Cloudflare.

### What should I check before upgrading CloudFlare-ImgBed?

The README's important notice directs users to the announcement discussions first, stating that important notifications and non-compatible updates are explained there. The documentation also has a version upgrade section. The repository does not describe a rollback procedure.

## Sources

- [License: MIT](https://github.com/MarSeventh/CloudFlare-ImgBed/blob/main/LICENSE)
- [MarSeventh/CloudFlare-ImgBed on GitHub](https://github.com/MarSeventh/CloudFlare-ImgBed)
- [Project website](https://cfbed.sanyue.de)
- [README](https://github.com/MarSeventh/CloudFlare-ImgBed/blob/main/README.md)
- [Releases](https://github.com/MarSeventh/CloudFlare-ImgBed/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/marseventh-cloudflare-imgbed
