cloudimgs: a self-hosted image host with a URL-parameter API and local search
云图 - 极简风格的云图库,支持NAS部署,支持设置密钥,支持各种灵活的API开放接口,NAS图床,PicGo插件直接安装使用
At a glance
- What is it?
- CloudImgs is a React and Node.js image hosting application that stores files on a NAS, resizes and converts them on the fly through URL parameters, and can search its own library with a local CLIP model. The README is written in Chinese, and the demo site is a static mock rather than a live instance.
- Who is it for?
- CloudImgs fits a person or a small team that already has a NAS, that wants an image host they control rather than a hosted service, and that will use the URL parameter API from a script or from PicGo.
- Can I use it commercially?
- Not without permission. GitHub finds no licence file in the repository, and without a licence all rights are reserved by default: you may read the code but not reuse it. Check the README, or ask the authors, before using it.
- Is it still maintained?
- Yes. The repository last received commits 63 days ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
It started as a need for image processing inside a workflow
The project description is minimal, a minimal style image library that supports NAS deployment, key configuration and flexible open APIs, an image host for a NAS with a PicGo plugin that installs directly. The introduction explains where it came from, and the reason is specific.
The author needed a lot of image processing while working with N8N workflows, looked at many open source projects, found some of them old and unmaintained and others needing a paid PRO version for the extra features, and, having a NAS of their own, wrote a free and open image hosting project.
That origin explains a lot about the shape of the thing. It is meant to be run on hardware the user already has, which is why the deployment guidance is Docker Compose on a NAS rather than a managed service. It is meant to be scriptable, which is why there is an API and why a PicGo plugin exists, since the workflow that started it all needed to push images somewhere without a browser. And the multi-format upload support, which includes other files as well as images and a global upload mode, is there because a workflow tool sends whatever it has.
The application is a React frontend with a Node.js backend. The package metadata describes it as a modern image hosting application with React frontend and Node.js backend, with `main` pointing at `server/index.js`, and the keywords are image hosting, react, nodejs and express. The licence field in the package metadata says MIT, but the repository metadata does not classify the licence under a standard name, so the licence position is one of the things to check before deploying it anywhere that matters.
The primary language is JavaScript, the default branch is `main`, the last push was on 2026-08-21, and the recent releases are v1.7.28 from 2026-08-21, v1.7.27 from 2026-07-14 and v1.7.26 from 2026-06-23.
The demo is a mock, and the README is careful to say so
The demo site is the first thing a visitor sees, and the README puts a note above it.
The demo is deployed in a purely static mock mode, where the image data loads at random and no real backend is called. The access password is `123456`, and the explanation is that uploading and deleting only demonstrate the interface, the data is not saved, and some functions are unavailable. In a real environment the thumbnails are generated with thumbhash and the experience is smoother.
That note is worth reading carefully, because the demo is otherwise indistinguishable from a working instance. The interface is the real interface, the navigation and the layout are the real ones, and the difference is that the data behind them is invented. So the demo is a good way to evaluate the user experience and a bad way to evaluate the upload path, the storage behaviour or the API.
The documentation lives at a separate address, `ytdoc.qazz.site`, which is a good sign, since a separate documentation site for a self-hosted project usually means the README is a summary and the real reference is elsewhere.
The screenshots in the README give a sense of the scope, with pages for the magic search, the login, the management view, batch actions, sharing, the whole page upload, the trajectory map, the image editor, the API, and the mobile layout. The mobile one matters, because the project lists mobile adaptation as a core feature and an image host is frequently used from a phone.
Magic search runs a small CLIP model on the server
The most interesting feature in the list is the one that is not about storing images.
The magic search is based on a local CLIP small model and supports natural language search, for example searching for blue sky and white clouds. The important word is local: the model runs on the machine running the application rather than being called out to an API, which is what makes a search over a private library possible without sending the images anywhere.
The cost is stated in the configuration itself, where the `ENABLE_MAGIC_SEARCH` option carries a comment that the local CLIP small model uses a fair amount of memory. The dependency list backs that up. `@huggingface/transformers` is the library that runs the model, and `sqlite-vec` is a vector search extension for SQLite, so the library is not searching with the model alone but storing embeddings and querying them.
The rest of the advanced features fit the same profile of a personal media library rather than a stock image site. There is a traffic dashboard that shows usage, and a photo trajectory that shows where the photos were taken on a map. The map one implies that location data is read from the images, and the dependency list has `exifr` for exactly that, along with `music-metadata` for audio files, which fits the multi-format upload support.
Two more performance-oriented details are worth noting. `thumbhash` is used to generate thumbnails without a visible loading step, and the `sharp` library does the actual image work, which is the standard high performance image library for Node and covers the resizing, the quality setting and the format conversion that the URL parameter API exposes.
The API is URL parameters, and it fits PicGo
The API section is what makes the project usable from a script, and it is built on one idea: the URL describes the transformation.
The example given is `image.jpg?w=500&h=300&q=80&fmt=webp`, and the features around it are real-time URL parameter processing for size, quality and format conversion, uploads by Base64, SVG to PNG conversion, drag and drop upload, and deletion and listing of images. There is also support for fetching a random image or an image with specified parameters.
That is a design that suits an image host used by a script. A workflow tool holds a URL and a desired size, appends the parameters and gets back an image that is already the right shape and format, which is a saving on bandwidth, on storage and on the client side. The same feature list also covers the user-facing side, with online image editing, a compression tool with custom quality and size, SVG to PNG, and a one-click copy of the image link.
The ecosystem integration is the PicGo plugin, which can be installed directly and lives in its own repository. PicGo is a picture bed uploader for editors, and a plugin for it means a developer can upload from inside their editor without visiting the site, which is a much better workflow than copy and paste.
The demo site is a mock, but the API is the part a developer would actually use, and the documentation site is where the parameter list and the endpoints live.
Deploying on a NAS with Docker Compose
Docker Compose is the recommended deployment, and the compose file in the repository is a good starting point. The service definition is short:
services:
cloudimgs:
image: qazzxxx/cloudimgs:latest
container_name: cloudimgs-app
restart: unless-stopped
ports:
- "3001:3001"The rest of the configuration is environment variables, and the repository has a table for them.
`PASSWORD` sets the access password, and leaving it empty means no password is required. `ENABLE_MAGIC_SEARCH` turns the AI magic search on or off. `MAX_FILE_SIZE` is the maximum upload size in bytes, with a default of 104857600, which is 100MB. `THUMBNAIL_WIDTH` is the width in pixels of the thumbnails in the waterfall view, where 0 means the original image is used.
The permissions settings are the part that matters on a NAS, because the application writes files as the user running the container. `PUID` and `PGID` are the real user id and group id of the NAS account, and the README notes that they should be the actual values from `id -u` and `id -g`. `UMASK` is set to 002 so that the files the container writes are readable by the group, which is what a shared NAS account needs.
Two notes in the README complete the picture. Setting `PASSWORD` automatically enables login protection, and the login state is stored in the browser's local storage, so it is a per-browser convenience rather than a server-side session.
The repository also carries a `Dockerfile`, a `Dockerfile.gha` for the GitHub Actions build, a `docker-entrypoint.sh`, a `start.sh`, a `config.js` and an `env.example`, and the `client/` and `server/` directories that hold the two halves of the application.
The container build shows where the memory goes
The `Dockerfile` in the repository is a multi-stage build, and it is unusually explicit about its resource settings, which tells you where the pressure is.
The build stage is `node:18-bookworm-slim`, and it installs the tools needed to compile the native dependencies: git, python3, make and g++. Those are there for `better-sqlite3` and `sharp`, both of which have native parts that have to be built rather than downloaded as prebuilt binaries in every case.
The memory settings are the interesting part. `NODE_OPTIONS` is set to `--max-old-space-size=2048`, with a comment that this avoids an out of memory error, and `GENERATE_SOURCEMAP` is set to false, with the comment that it reduces memory use and speeds up the build. `DISABLE_ESLINT_PLUGIN` is also set, so that a lint error during the client build does not interrupt it. The npm configuration is quieted down as well, with audit, fund and progress turned off.
The client is built with `react-scripts`, which the build stage checks explicitly by listing the React and react-scripts versions, and the npm install commands use `--legacy-peer-deps`, which is the pragmatic flag for a dependency tree that has not been reconciled with the strict peer dependency rules.
So the build is a create-react-app build with a Node backend, and the flags around it are the accumulated knowledge of somebody who has run it on a small machine. That is a useful signal for anyone planning to build the image on a NAS, where the build container is often the largest thing running.
Where cloudimgs is the wrong tool
Three limits are worth weighing, and they are about the deployment rather than the code.
The first is the storage model. The uploaded files live in a directory mounted into the container, at `/app/uploads` by default, and the database is SQLite through `better-sqlite3`, with the vector extension alongside it for the search. That is a perfectly good arrangement for one NAS and one instance, and it is not a replicated store with a backup story. A user who needs their images to survive a disk failure has to think about that separately, and the `DataDir` equivalent of an object store with versioning simply is not here.
The second is the documentation language. The README, the environment variable table and the comments inside the compose file are in Chinese, and the project is aimed at users with NAS hardware, which is a market where that is not unusual. But a team that cannot read it is going to struggle with the configuration, because the configuration is where the real decisions live, and the parts of it that matter, the file size limit, the thumbnail width, the memory cost of the search, are exactly the parts explained in the Chinese text.
The third is version drift, and it is visible in the repository. The version in `package.json` reads 1.2.3 while the released tags are on the 1.7 line, and the package metadata still has the placeholder author `Your Name`, which suggests the published package metadata was not fully maintained. The deployed artefact is the `qazzxxx/cloudimgs:latest` image, so the image tag is what actually determines the version, and pinning a tag rather than using `latest` is the obvious precaution.
The alternative for an application that needs a public image host with durability is an object storage bucket with a CDN in front of it, which is more infrastructure but has a storage model designed for the job. The difference in approach is that cloudimgs is a single process on your own hardware that treats the filesystem as the database of record, and the alternative treats a bucket as the store and the application as a thin layer in front of it, and the second is what a team with a public site and a backup policy should choose.
Editorial conclusion
CloudImgs fits a person or a small team that already has a NAS, that wants an image host they control rather than a hosted service, and that will use the URL parameter API from a script or from PicGo. It is the wrong choice for an application that needs durable object storage with replication, because the storage is a directory mounted into a container, and it is the wrong choice for a team that cannot read the Chinese documentation, since the README, the comments in the compose file and the environment variable notes are all in Chinese. Before deploying it, set `PASSWORD` rather than leaving it empty, keep `ENABLE_MAGIC_SEARCH` off on a small machine because the local CLIP model is memory hungry, and check the image tag you pin, since the version in `package.json` and the released version have drifted apart.
Frequently asked questions
How do I deploy cloudimgs on a NAS?
With Docker Compose, using the qazzxxx/cloudimgs:latest image with the uploads directory mounted at /app/uploads, and the environment set to your real NAS user id and group id through PUID and PGID with UMASK=002, plus NODE_ENV=production, PORT=3001 and STORAGE_PATH=/app/uploads. The service listens on port 3001.
Does cloudimgs require a password to access the images?
Not by default: leaving PASSWORD empty means no password is needed. Setting it automatically enables login protection, and the login state is kept in the browser's local storage rather than in a server-side session.
What can the cloudimgs API do?
Base64 uploads, SVG to PNG conversion, drag and drop upload, image deletion and listing, random image retrieval, and real-time URL parameter processing for size, quality and format, for example image.jpg?w=500&h=300&q=80&fmt=webp. There is also a PicGo plugin for uploading from an editor.
What does the magic search in cloudimgs use, and what does it cost?
A local CLIP small model, enabled with ENABLE_MAGIC_SEARCH=true, which supports natural language queries such as searching for blue sky and white clouds. The README notes that the local model uses a fair amount of memory, so it is off by default.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/qazzxxx-cloudimgs)Was this useful?