Deploy Imagor

Image processing server that resizes and converts images from a URL

Deploy Imagor

Just deployed

imagor-result

Bucket

Just deployed

imagor-source

Bucket

Just deployed

Deploy and Host Imagor on Railway

Imagor is an open-source image processing server written in Go on top of libvips, the engine behind many commercial image CDNs. Every transformation lives in the URL — fit-in/800x600/filters:format(webp):quality(85)/photo.jpg — so your front-end never pre-generates thumbnails or stores a dozen variants of one asset. It speaks the thumbor URL syntax, making it a drop-in replacement for a thumbor install, and teams self-host Imagor for Cloudinary-style on-the-fly resizing without per-image pricing.

This template runs Imagor as a public HTTP service backed by two Railway object storage buckets. imagor is the only service with a domain: it takes a signed request, loads the original from the imagor-source bucket (or fetches it over HTTP when the path is a remote URL), renders the variant with libvips, and writes the result to the imagor-result bucket so the next identical request is served from cache. Remote originals are saved into imagor-source too, so each source is fetched once. The app tier keeps nothing on disk, which is what lets you raise the replica count later.

Railway diagram of the single public imagor service

Getting Started with Imagor on Railway

There is no login screen and no admin account. Open the deployed URL and you should see the Imagor landing page with the running version, confirming the server is up; /healthcheck returns 200 for uptime monitoring. Because IMAGOR_SECRET is generated at deploy time, every image path must carry an HMAC-SHA1 signature, so an unsigned URL gets 403 url signature mismatch rather than serving anyone who guesses a path. Copy IMAGOR_SECRET from the service variables and sign the part of the path after the signature segment:

IMAGOR_SECRET=""
P='fit-in/800x600/filters:format(webp):quality(85)/photo.jpg'
SIG=$(printf %s "$P" | openssl dgst -sha1 -hmac "$IMAGOR_SECRET" -binary | base64 | tr '+/' '-_')
echo "https:///$SIG/$P"

For your own images, upload them to imagor-source under the source/ prefix with any S3 client and reference them by filename; or put a full https:// image URL at the end of the path and Imagor fetches and caches it. Signing helpers exist for Go, Node, Python, PHP and Ruby, so a real application builds these URLs in its backend.

Imagor landing page showing the running server version Imagor smart-cropped square thumbnail of a spacewalk photo Imagor watermark filter composited over a lunar map

About Hosting Imagor

Self-hosting Imagor makes sense as soon as image delivery becomes a real line item. A commercial image CDN charges per transformation and owns the URL your pages point at; Imagor puts that layer in your own infrastructure, in front of storage you control, for the cost of the container rendering the images.

  • Resize, crop, fit-in, stretch, pad, rotate and flip from URL parameters
  • Content-aware smart cropping that keeps a photo's subject in frame
  • Filters for quality, format, fill, blur, sharpen, grayscale, hue, rounded corners and watermarks
  • JPEG, PNG, WebP, AVIF, GIF and TIFF output with automatic WebP/AVIF negotiation, animation included
  • HMAC URL signing (SHA1, SHA256 or SHA512), and storage backends for S3, Google Cloud Storage, local disk or plain HTTP

The topology is three pieces. imagor is the stateless renderer. imagor-source holds originals and caches remote fetches. imagor-result holds rendered variants keyed by a digest of the request and is safe to empty at any time, so clearing the derived cache never touches your originals.

Why Deploy Imagor on Railway

Railway removes the parts of running an image server that are not about images:

  • Both object storage buckets are provisioned and wired in for you
  • A public HTTPS domain and certificate with no configuration
  • The signing secret is generated at deploy time, so nothing ships unprotected
  • Health checks and log aggregation as standard
  • Raise replicas as traffic grows; the service holds no local state

Common Use Cases

  • Serving responsive srcset variants from one uploaded original
  • Generating product thumbnails and gallery crops for an e-commerce catalogue
  • Replacing a paid image CDN's transformation tier while keeping your own storage
  • Watermarking user-submitted media at request time

Imagor vs Thumbor vs imgproxy

Imagorthumborimgproxy
EngineGo + libvipsPython + PILGo + libvips
LicenceApache-2.0MITOpen core, paid Pro tier
URL syntaxthumbor-compatibleoriginalits own
Paid featuresnonenoneadvanced filters, internal cache

Imagor's published benchmarks put it ahead of thumbor on JPEG, PNG, WebP and AVIF, and trading places with imgproxy by format. Against imgproxy the practical difference is licensing: no Pro edition holds back filters or caching.

Dependencies for Imagor

  • shumc/imagor:latest — the Imagor server, Go and libvips in one image
  • imagor-source — bucket holding originals under source/
  • imagor-result — bucket holding rendered variants under result/

Environment Variables Reference

VariablePurpose
IMAGOR_SECRETHMAC key for URL signing; generated at deploy time
PORTHTTP listening port, 8000
IMAGOR_AUTO_WEBP / IMAGOR_AUTO_AVIFServe WebP or AVIF when the browser allows it
IMAGOR_PROCESS_CONCURRENCYCeiling on simultaneous libvips operations
IMAGOR_CACHE_HEADER_TTLCache-Control max-age on successful responses
S3_LOADER_BUCKET / S3_STORAGE_BUCKETBucket for reading and writing originals
S3_RESULT_STORAGE_BUCKETBucket for rendered variants
HTTP_LOADER_BLOCK_PRIVATE_NETWORKSRefuses origin fetches aimed at internal addresses
VIPS_STRIP_METADATADrops EXIF, including GPS, from output

Deployment Dependencies

Hardware Requirements for Self-Hosting Imagor

MinimumRecommended
CPU1 vCPU2–4 vCPU
RAM512 MB2 GB
StorageNone on the containerObject storage sized to your media
RuntimeDockerDocker

libvips streams rather than buffering whole images, so memory stays modest and CPU decides throughput. AVIF encoding is the expensive case — raise VIPS_AVIF_SPEED or stay on WebP if requests queue up.

Is Imagor Free to Self-Host?

Imagor is free and open source under Apache-2.0, with no paid edition and no feature held back — every filter, format and storage backend is in the public image. On Railway you pay for the compute the renderer uses and the storage your media occupies, so cost tracks traffic rather than image count.

Self-Hosting Imagor

To try Imagor locally first, this starts an unsigned development server:

docker run -p 8000:8000 shumc/imagor -imagor-unsafe -imagor-auto-webp

Then open http://localhost:8000/unsafe/400x400/raw.githubusercontent.com/cshum/imagor/master/testdata/gopher.png. To run it as this template does — signed URLs against S3-compatible storage — pass the settings as variables:

docker run -p 8000:8000 \
  -e IMAGOR_SECRET=your-signing-key -e S3_FORCE_PATH_STYLE=1 \
  -e AWS_ACCESS_KEY_ID=... -e AWS_SECRET_ACCESS_KEY=... -e AWS_REGION=auto \
  -e S3_ENDPOINT=https://your-s3-endpoint \
  -e S3_LOADER_BUCKET=originals -e S3_RESULT_STORAGE_BUCKET=variants \
  shumc/imagor

Never set -imagor-unsafe on a public instance: it turns signature checking off and lets anyone run transformations through your server.

FAQ

What is Imagor? An open-source image processing server built on libvips. It resizes, crops, converts and filters images on demand, with the operations written into the request URL, in thumbor's syntax.

What does this Railway template deploy? One public imagor service on the official shumc/imagor image, plus the imagor-source and imagor-result object storage buckets.

Why does the template include two object storage buckets? Separating them lets you clear the derived cache without risking your originals: imagor-result holds only regenerable images, so emptying it costs a little CPU and nothing else.

How do I generate a signed Imagor URL in my application? Compute an HMAC of the path following the signature segment, keyed with IMAGOR_SECRET, and encode it as URL-safe base64. The default algorithm is SHA1; IMAGOR_SIGNER_TYPE switches it to SHA256 or SHA512.

Can Imagor process images from a URL instead of a bucket? Yes. Put a full image URL at the end of the path and the HTTP loader fetches it, caches the original in imagor-source and renders from there. Restrict the origins it may reach with HTTP_LOADER_ALLOWED_SOURCES.

Does self-hosted Imagor support smart cropping and watermarks? Both, with no paid tier. Add smart to the path for content-aware cropping, and use the watermark() filter to composite another image.

How do I scale Imagor for heavy traffic? The service stores nothing locally, so raise the replica count and every instance shares one result cache. Put a CDN in front too, since responses already carry a long Cache-Control max-age.


Template Content

imagor-result

Bucket

imagor-source

Bucket

More templates in this category

View Template
Garage S3 Storage
Ultra-light S3 server: fast, open-source, plug-and-play.

PROJETOS
8
View Template
Redis
Self Host Latest Redis with Railway

7
View Template
EasyImg
Simple self-hostable Nuxt.js personal image hosting system.

Muhammad Bilal
0