ImageSilo

English | 简体中文

ImageSilo

A lightweight, self-hosted home for your images.

Latest release CI status Docker image on GHCR Linux amd64 and arm64 MIT License

ImageSilo is a Docker-first image host built as one Go process with SQLite and local file storage. It provides authenticated uploads, stable public URLs, historical aliases, scoped API tokens, image processing, and a responsive React administration interface without Redis, an external database, or a background job service. > Release images use immutable version tags and the mutable `latest` tag. Production deployments should pin an immutable version tag or digest. ## Screenshots

ImageSilo image library
ImageSilo sign-in page ImageSilo image upload page

## Features - Store JPEG, PNG, WebP, and GIF images with strict decoding and a 16 MP safety limit - Preserve original bytes or explicitly compress and convert static images to WebP - Deliver public images, historical aliases, and path-preserving migration files with Range, conditional request, and HEAD support - Keep the delivery hot path in memory, with no SQLite lookup per image request - Manage public/private visibility, administrator sessions, CSRF protection, login rate limits, and scoped API tokens - Upload, search, filter, inspect, batch-update, and permanently delete images from the built-in web interface - Import legacy URLs, verify bytes by SHA-256, inspect storage, and rebuild in-memory indexes - Run as a non-root, multi-architecture container with image processing concurrency set to `1` by default ## Quick Start Docker is the supported production runtime. The following starts a local evaluation instance with a named volume: ```bash export IMAGESILO_IMAGE=ghcr.io/willxup/imagesilo:latest docker pull "$IMAGESILO_IMAGE" docker volume create imagesilo-data docker run --detach \ --name imagesilo \ --restart unless-stopped \ --publish 127.0.0.1:8080:8080 \ --env IMAGESILO_COOKIE_SECURE=false \ --env IMAGESILO_PROCESSING_CONCURRENCY=1 \ --volume imagesilo-data:/data \ "$IMAGESILO_IMAGE" ``` On the first launch, run `docker logs -f imagesilo` and copy the `bootstrap_token` printed by ImageSilo. Open `http://127.0.0.1:8080/admin/setup`, enter that token, and create the administrator account. The token exists only in memory, is replaced after an uninitialized restart, and is erased after setup succeeds. The `imagesilo admin create` command remains available for scripted deployments. For production, terminate HTTPS at a reverse proxy, keep `IMAGESILO_COOKIE_SECURE=true`, and back up the complete `/data` directory while writes are stopped. See the [deployment guide](./docs/deployment.md) before exposing the service. To preserve an existing image URL tree without creating one alias at a time, mount it read-only at `/data/migrations`. A file mounted as `/data/migrations/i/2022/04/example.jpg` is immediately available at `/i/2022/04/example.jpg`. Managed historical aliases take precedence when both sources contain the same path; only JPEG, PNG, WebP, and GIF files are exposed. The Migration management page can browse and copy these URLs in read-only mode; its file list uses a 30-minute lazy snapshot with manual refresh, while direct image delivery is never gated by that list cache. Only for a dedicated migration copy, make the mount writable and set `IMAGESILO_MIGRATION_MUTATIONS=true` to enable permanent deletion. ## Enable Migration Deletion Migration deletion is disabled by default and should only be enabled for a dedicated migration copy with an independent backup. The environment variable, mount mode, and host permissions must all allow deletion. Setting the variable while retaining a read-only mount is not sufficient. Enable the capability in `docker-compose.yaml` and mount `/data/migrations` writable: ```yaml services: imagesilo: image: ghcr.io/willxup/imagesilo:latest environment: IMAGESILO_MIGRATION_MUTATIONS: "true" volumes: - ./data:/data - ./migration:/data/migrations:rw ``` If the existing migration mount ends in `:ro`, change it to `:rw` or omit the mount mode. A separate migration mount is unnecessary when the files already live inside a writable `./data/migrations` directory. The container runs as UID/GID `10001:10001`. Apply these permissions only to a dedicated migration copy: ```bash sudo chown -R 10001:10001 ./migration sudo find ./migration -type d -exec chmod 750 {} + sudo find ./migration -type f -exec chmod 640 {} + ``` Validate the configuration and recreate the container. A regular `docker compose restart` does not apply new environment variables: ```bash docker compose config --quiet docker compose up -d --force-recreate docker compose exec imagesilo sh -c \ 'test "$IMAGESILO_MIGRATION_MUTATIONS" = true && test -w /data/migrations' ``` Deletion cannot be undone. After deleting an image, ImageSilo recursively removes truly empty parent directories, including empty top-level `i` or `images` directories, but never removes the `/data/migrations` root. Do not enable this capability for the only copy of a legacy image library. ## Design Boundaries | Area | Implementation | | --- | --- | | Runtime | One Go process in one container | | Metadata | SQLite in `/data/db` | | Images | Local files in `/data/images` | | Path-preserving migrations | Image tree in `/data/migrations`, read-only by default with opt-in deletion | | Cache | Local thumbnails in `/data/cache` | | Processing | libvips, concurrency `1` by default | | Delivery | File streaming with ETag revalidation; unlimited by default (`0`), optionally capped | | Platforms | `linux/amd64`, `linux/arm64` | | Production storage | Docker named volume or local bind mount | NFS and SMB are not supported. Do not run two ImageSilo containers against the same writable `/data` directory. ## Local Development ### Prerequisites - Go >=1.26.10 - Node.js >=24.22.1 - npm Local toolchains need only meet these minimum versions; no exact version is pinned. npm enforces the Node.js minimum during installation. CI uses the latest Go 1.26.x and Node.js 24.x; Docker builds use rolling Debian Bookworm image tags with `--pull`. ### Build and Verify ```bash npm --prefix web ci make check make build ``` Create an administrator and run the local binary: ```bash IMAGESILO_DATA_DIR="$PWD/data" \ ./bin/imagesilo admin create --email admin@example.com IMAGESILO_DATA_DIR="$PWD/data" \ IMAGESILO_COOKIE_SECURE=false \ ./bin/imagesilo serve ``` Use `/healthz` for liveness and `/readyz` for SQLite readiness. UI and browser behavior changes are checked on demand in an existing browser, manually or with computer-use tools. No project-managed browser or browser-test framework is required. CI runs `make check` (build, lint, type checks, and unit/integration tests), not browser acceptance. Follow the [browser acceptance checklist](./docs/browser-acceptance.md), record actual results, and explicitly mark unverified scenarios. ## Documentation | Topic | Guide | | --- | --- | | Docker deployment, backup, upgrade, and rollback | [Deployment](./docs/deployment.md) | | API tokens, curl, PicGo, and ShareX | [API token usage](./docs/api-token-usage.md) | | Legacy image and URL migration | [Imports](./docs/imports.md) | | Inspection, cleanup, and index rebuilds | [Operations](./docs/operations.md) | | Architecture and data model | [Architecture](./docs/architecture.md) · [Data model](./docs/data-model.md) | | Security and performance | [Security audit](./docs/security-audit.md) · [Performance baseline](./docs/performance-baseline.md) | | Release process and verification | [Release guide](./docs/release.md) | | HTTP API contract | [OpenAPI](./api/openapi.yaml) | | Bundled third-party licenses | [Third-party notices](./THIRD_PARTY_NOTICES.md) | ## License This project is open source under the [MIT License](./LICENSE).